From 1bee0986c786010bfc4560eb610e48633e67e283 Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Thu, 16 Feb 2023 12:05:54 +0100 Subject: [PATCH] Preserve order for json ser/de --- Cargo.lock | 1 + Cargo.toml | 2 +- luneDocs.json | 964 ++++++++++---------- packages/cli/src/gen/{doc.rs => doc/mod.rs} | 6 + packages/cli/src/gen/{ => doc}/tag.rs | 0 packages/cli/src/gen/{ => doc}/visitor.rs | 25 +- packages/cli/src/gen/mod.rs | 35 +- 7 files changed, 519 insertions(+), 514 deletions(-) rename packages/cli/src/gen/{doc.rs => doc/mod.rs} (95%) rename packages/cli/src/gen/{ => doc}/tag.rs (100%) rename packages/cli/src/gen/{ => doc}/visitor.rs (87%) diff --git a/Cargo.lock b/Cargo.lock index cfa5996..100d636 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1273,6 +1273,7 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ + "indexmap", "itoa", "ryu", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8cdcf60..cfd51c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,9 @@ panic = "abort" # Remove extra panic info console = "0.15.5" lazy_static = "1.4.0" -serde_json = "1.0.91" serde = { version = "1.0.152", features = ["derive"] } +serde_json = { version = "1.0.91", features = ["preserve_order"] } tokio = { version = "1.24.2", features = ["full"] } [workspace.dependencies.reqwest] diff --git a/luneDocs.json b/luneDocs.json index 1f80b3e..bd5051b 100644 --- a/luneDocs.json +++ b/luneDocs.json @@ -1,152 +1,442 @@ { "@roblox/global/fs": { - "code_sample": "", "documentation": "Filesystem", "keys": { "fs": "@roblox/global/fs.fs" }, - "learn_more_link": "" - }, - "@roblox/global/fs.isDir": { - "code_sample": "", - "documentation": "Checks if a given path is a directory.\n\nAn error will be thrown in the following situations:\n\n* The current process lacks permissions to read at `path`.\n* Some other I/O error occurred.", "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.isDir/param/0", - "name": "path" - } - ], - "returns": [ - "@roblox/global/fs.isDir/return/0" - ] + "code_sample": "" }, - "@roblox/global/fs.isDir/param/0": { - "documentation": "The directory path to check" - }, - "@roblox/global/fs.isDir/return/0": { - "documentation": "If the path is a directory or not" - }, - "@roblox/global/fs.isFile": { - "code_sample": "", - "documentation": "Checks if a given path is a file.\n\nAn error will be thrown in the following situations:\n\n* The current process lacks permissions to read at `path`.\n* Some other I/O error occurred.", + "@roblox/global/net": { + "documentation": "Networking", + "keys": { + "net": "@roblox/global/net.net" + }, "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.isFile/param/0", - "name": "path" - } - ], - "returns": [ - "@roblox/global/fs.isFile/return/0" - ] + "code_sample": "" }, - "@roblox/global/fs.isFile/param/0": { - "documentation": "The file path to check" - }, - "@roblox/global/fs.isFile/return/0": { - "documentation": "If the path is a file or not" - }, - "@roblox/global/fs.readDir": { - "code_sample": "", - "documentation": "Reads entries in a directory at `path`.\n\nAn error will be thrown in the following situations:\n\n* `path` does not point to an existing directory.\n* The current process lacks permissions to read the contents of the directory.\n* Some other I/O error occurred.", + "@roblox/global/process": { + "documentation": "Current process & child processes", + "keys": { + "process": "@roblox/global/process.process" + }, "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.readDir/param/0", - "name": "path" - } - ], - "returns": [ - "@roblox/global/fs.readDir/return/0" - ] + "code_sample": "" }, - "@roblox/global/fs.readDir/param/0": { - "documentation": "The directory path to search in" + "@roblox/global/stdio": { + "documentation": "Standard input / output & utility functions", + "keys": { + "stdio": "@roblox/global/stdio.stdio" + }, + "learn_more_link": "", + "code_sample": "" }, - "@roblox/global/fs.readDir/return/0": { - "documentation": "A list of files & directories found" + "@roblox/global/task": { + "documentation": "Task scheduler & thread spawning", + "keys": { + "task": "@roblox/global/task.task" + }, + "learn_more_link": "", + "code_sample": "" }, "@roblox/global/fs.readFile": { - "code_sample": "", "documentation": "Reads a file at `path`.\n\nAn error will be thrown in the following situations:\n\n* `path` does not point to an existing file.\n* The current process lacks permissions to read the file.\n* The contents of the file cannot be read as a UTF-8 string.\n* Some other I/O error occurred.", - "learn_more_link": "", "params": [ { - "documentation": "@roblox/global/fs.readFile/param/0", - "name": "path" + "name": "path", + "documentation": "@roblox/global/fs.readFile/param/0" } ], "returns": [ "@roblox/global/fs.readFile/return/0" - ] + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.readDir": { + "documentation": "Reads entries in a directory at `path`.\n\nAn error will be thrown in the following situations:\n\n* `path` does not point to an existing directory.\n* The current process lacks permissions to read the contents of the directory.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.readDir/param/0" + } + ], + "returns": [ + "@roblox/global/fs.readDir/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.writeFile": { + "documentation": "Writes to a file at `path`.\n\nAn error will be thrown in the following situations:\n\n* The file's parent directory does not exist.\n* The current process lacks permissions to write to the file.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.writeFile/param/0" + }, + { + "name": "contents", + "documentation": "@roblox/global/fs.writeFile/param/1" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.writeDir": { + "documentation": "Creates a directory and its parent directories if they are missing.\n\nAn error will be thrown in the following situations:\n\n* `path` already points to an existing file or directory.\n* The current process lacks permissions to create the directory or its missing parents.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.writeDir/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.removeFile": { + "documentation": "Removes a file.\n\nAn error will be thrown in the following situations:\n\n* `path` does not point to an existing file.\n* The current process lacks permissions to remove the file.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.removeFile/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.removeDir": { + "documentation": "Removes a directory and all of its contents.\n\nAn error will be thrown in the following situations:\n\n* `path` is not an existing and empty directory.\n* The current process lacks permissions to remove the directory.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.removeDir/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.isFile": { + "documentation": "Checks if a given path is a file.\n\nAn error will be thrown in the following situations:\n\n* The current process lacks permissions to read at `path`.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.isFile/param/0" + } + ], + "returns": [ + "@roblox/global/fs.isFile/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/fs.isDir": { + "documentation": "Checks if a given path is a directory.\n\nAn error will be thrown in the following situations:\n\n* The current process lacks permissions to read at `path`.\n* Some other I/O error occurred.", + "params": [ + { + "name": "path", + "documentation": "@roblox/global/fs.isDir/param/0" + } + ], + "returns": [ + "@roblox/global/fs.isDir/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/net.request": { + "documentation": "Sends an HTTP request using the given url and / or parameters, and returns a dictionary that describes the response received.\n\nOnly throws an error if a miscellaneous network or I/O error occurs, never for unsuccessful status codes.", + "params": [ + { + "name": "config", + "documentation": "@roblox/global/net.request/param/0" + } + ], + "returns": [ + "@roblox/global/net.request/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/net.socket": { + "documentation": "Connects to a web socket at the given URL.\n\nThrows an error if the server at the given URL does not support\nweb sockets, or if a miscellaneous network or I/O error occurs.", + "params": [ + { + "name": "url", + "documentation": "@roblox/global/net.socket/param/0" + } + ], + "returns": [ + "@roblox/global/net.socket/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/net.serve": { + "documentation": "Creates an HTTP server that listens on the given `port`.\n\nThis will ***not*** block and will keep listening for requests on the given `port`\nuntil the `stop` function on the returned `NetServeHandle` has been called.", + "params": [ + { + "name": "port", + "documentation": "@roblox/global/net.serve/param/0" + }, + { + "name": "handlerOrConfig", + "documentation": "@roblox/global/net.serve/param/1" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/net.jsonEncode": { + "documentation": "Encodes the given value as JSON.", + "params": [ + { + "name": "value", + "documentation": "@roblox/global/net.jsonEncode/param/0" + }, + { + "name": "pretty", + "documentation": "@roblox/global/net.jsonEncode/param/1" + } + ], + "returns": [ + "@roblox/global/net.jsonEncode/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/net.jsonDecode": { + "documentation": "Decodes the given JSON string into a lua value.", + "params": [ + { + "name": "encoded", + "documentation": "@roblox/global/net.jsonDecode/param/0" + } + ], + "returns": [ + "@roblox/global/net.jsonDecode/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/process.args": { + "documentation": "The arguments given when running the Lune script.", + "params": [], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/process.cwd": { + "documentation": "The current working directory in which the Lune script is running.", + "params": [], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/process.env": { + "documentation": "Current environment variables for this process.\n\nSetting a value on this table will set the corresponding environment variable.", + "params": [], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/process.exit": { + "documentation": "Exits the currently running script as soon as possible with the given exit code.\n\nExit code 0 is treated as a successful exit, any other value is treated as an error.\n\nSetting the exit code using this function will override any otherwise automatic exit code.", + "params": [ + { + "name": "code", + "documentation": "@roblox/global/process.exit/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/process.spawn": { + "documentation": "Spawns a child process that will run the program `program`, and returns a dictionary that describes the final status and ouput of the child process.\n\nThe second argument, `params`, can be passed as a list of string parameters to give to the program.\n\nThe third argument, `options`, can be passed as a dictionary of options to give to the child process.\nThe available options inside of the `options` dictionary are:\n* `cwd` - The current working directory for the process\n* `env` - Extra environment variables to give to the process\n* `shell` - Whether to run in a shell or not - set to `true` to run using the default shell, or a string to run using a specific shell\n* `stdio` - How to treat output and error streams from the child process - set to \"inherit\" to pass output and error streams to the current process", + "params": [ + { + "name": "program", + "documentation": "@roblox/global/process.spawn/param/0" + }, + { + "name": "params", + "documentation": "@roblox/global/process.spawn/param/1" + }, + { + "name": "options", + "documentation": "@roblox/global/process.spawn/param/2" + } + ], + "returns": [ + "@roblox/global/process.spawn/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/stdio.color": { + "documentation": "Return an ANSI string that can be used to modify the persistent output color.\n\nPass `\"reset\"` to get a string that can reset the persistent output color.\n\n### Example usage\n\n```lua\nstdio.write(stdio.color(\"red\"))\nprint(\"This text will be red\")\nstdio.write(stdio.color(\"reset\"))\nprint(\"This text will be normal\")\n```", + "params": [ + { + "name": "color", + "documentation": "@roblox/global/stdio.color/param/0" + } + ], + "returns": [ + "@roblox/global/stdio.color/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/stdio.style": { + "documentation": "Return an ANSI string that can be used to modify the persistent output style.\n\nPass `\"reset\"` to get a string that can reset the persistent output style.\n\n### Example usage\n\n```lua\nstdio.write(stdio.style(\"bold\"))\nprint(\"This text will be bold\")\nstdio.write(stdio.style(\"reset\"))\nprint(\"This text will be normal\")\n```", + "params": [ + { + "name": "style", + "documentation": "@roblox/global/stdio.style/param/0" + } + ], + "returns": [ + "@roblox/global/stdio.style/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/stdio.format": { + "documentation": "Formats arguments into a human-readable string with syntax highlighting for tables.", + "params": [ + { + "name": "...", + "documentation": "@roblox/global/stdio.format/param/0" + } + ], + "returns": [ + "@roblox/global/stdio.format/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/stdio.write": { + "documentation": "Writes a string directly to stdout, without any newline.", + "params": [ + { + "name": "s", + "documentation": "@roblox/global/stdio.write/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/stdio.ewrite": { + "documentation": "Writes a string directly to stderr, without any newline.", + "params": [ + { + "name": "s", + "documentation": "@roblox/global/stdio.ewrite/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/stdio.prompt": { + "documentation": "Prompts for user input using the wanted kind of prompt:\n\n* `\"text\"` - Prompts for a plain text string from the user\n* `\"confirm\"` - Prompts the user to confirm with y / n\n* `\"select\"` - Prompts the user to select *one* value from a list\n* `\"multiselect\"` - Prompts the user to select *one or more* values from a list\n* `nil` - Equivalent to `\"text\"` with no extra arguments", + "params": [ + { + "name": "kind", + "documentation": "@roblox/global/stdio.prompt/param/0" + }, + { + "name": "message", + "documentation": "@roblox/global/stdio.prompt/param/1" + }, + { + "name": "defaultOrOptions", + "documentation": "@roblox/global/stdio.prompt/param/2" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/task.cancel": { + "documentation": "Stops a currently scheduled thread from resuming.", + "params": [ + { + "name": "thread", + "documentation": "@roblox/global/task.cancel/param/0" + } + ], + "returns": [], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/task.defer": { + "documentation": "Defers a thread or function to run at the end of the current task queue.", + "params": [ + { + "name": "functionOrThread", + "documentation": "@roblox/global/task.defer/param/0" + } + ], + "returns": [ + "@roblox/global/task.defer/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/task.delay": { + "documentation": "Delays a thread or function to run after `duration` seconds.", + "params": [ + { + "name": "functionOrThread", + "documentation": "@roblox/global/task.delay/param/0" + } + ], + "returns": [ + "@roblox/global/task.delay/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/task.spawn": { + "documentation": "Instantly runs a thread or function.\n\nIf the spawned task yields, the thread that spawned the task\nwill resume, letting the spawned task run in the background.", + "params": [ + { + "name": "functionOrThread", + "documentation": "@roblox/global/task.spawn/param/0" + } + ], + "returns": [ + "@roblox/global/task.spawn/return/0" + ], + "learn_more_link": "", + "code_sample": "" + }, + "@roblox/global/task.wait": { + "documentation": "Waits for the given duration, with a minimum wait time of 10 milliseconds.", + "params": [ + { + "name": "duration", + "documentation": "@roblox/global/task.wait/param/0" + } + ], + "returns": [ + "@roblox/global/task.wait/return/0" + ], + "learn_more_link": "", + "code_sample": "" }, "@roblox/global/fs.readFile/param/0": { "documentation": "The path to the file to read" }, - "@roblox/global/fs.readFile/return/0": { - "documentation": "The contents of the file" - }, - "@roblox/global/fs.removeDir": { - "code_sample": "", - "documentation": "Removes a directory and all of its contents.\n\nAn error will be thrown in the following situations:\n\n* `path` is not an existing and empty directory.\n* The current process lacks permissions to remove the directory.\n* Some other I/O error occurred.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.removeDir/param/0", - "name": "path" - } - ], - "returns": [] - }, - "@roblox/global/fs.removeDir/param/0": { - "documentation": "The directory to remove" - }, - "@roblox/global/fs.removeFile": { - "code_sample": "", - "documentation": "Removes a file.\n\nAn error will be thrown in the following situations:\n\n* `path` does not point to an existing file.\n* The current process lacks permissions to remove the file.\n* Some other I/O error occurred.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.removeFile/param/0", - "name": "path" - } - ], - "returns": [] - }, - "@roblox/global/fs.removeFile/param/0": { - "documentation": "The file to remove" - }, - "@roblox/global/fs.writeDir": { - "code_sample": "", - "documentation": "Creates a directory and its parent directories if they are missing.\n\nAn error will be thrown in the following situations:\n\n* `path` already points to an existing file or directory.\n* The current process lacks permissions to create the directory or its missing parents.\n* Some other I/O error occurred.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.writeDir/param/0", - "name": "path" - } - ], - "returns": [] - }, - "@roblox/global/fs.writeDir/param/0": { - "documentation": "The directory to create" - }, - "@roblox/global/fs.writeFile": { - "code_sample": "", - "documentation": "Writes to a file at `path`.\n\nAn error will be thrown in the following situations:\n\n* The file's parent directory does not exist.\n* The current process lacks permissions to write to the file.\n* Some other I/O error occurred.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/fs.writeFile/param/0", - "name": "path" - }, - { - "documentation": "@roblox/global/fs.writeFile/param/1", - "name": "contents" - } - ], - "returns": [] + "@roblox/global/fs.readDir/param/0": { + "documentation": "The directory path to search in" }, "@roblox/global/fs.writeFile/param/0": { "documentation": "The path of the file" @@ -154,96 +444,26 @@ "@roblox/global/fs.writeFile/param/1": { "documentation": "The contents of the file" }, - "@roblox/global/net": { - "code_sample": "", - "documentation": "Networking", - "keys": { - "net": "@roblox/global/net.net" - }, - "learn_more_link": "" + "@roblox/global/fs.writeDir/param/0": { + "documentation": "The directory to create" }, - "@roblox/global/net.jsonDecode": { - "code_sample": "", - "documentation": "Decodes the given JSON string into a lua value.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/net.jsonDecode/param/0", - "name": "encoded" - } - ], - "returns": [ - "@roblox/global/net.jsonDecode/return/0" - ] + "@roblox/global/fs.removeFile/param/0": { + "documentation": "The file to remove" }, - "@roblox/global/net.jsonDecode/param/0": { - "documentation": "The JSON string to decode" + "@roblox/global/fs.removeDir/param/0": { + "documentation": "The directory to remove" }, - "@roblox/global/net.jsonDecode/return/0": { - "documentation": "The decoded lua value" + "@roblox/global/fs.isFile/param/0": { + "documentation": "The file path to check" }, - "@roblox/global/net.jsonEncode": { - "code_sample": "", - "documentation": "Encodes the given value as JSON.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/net.jsonEncode/param/0", - "name": "value" - }, - { - "documentation": "@roblox/global/net.jsonEncode/param/1", - "name": "pretty" - } - ], - "returns": [ - "@roblox/global/net.jsonEncode/return/0" - ] - }, - "@roblox/global/net.jsonEncode/param/0": { - "documentation": "The value to encode as JSON" - }, - "@roblox/global/net.jsonEncode/param/1": { - "documentation": "If the encoded JSON string should include newlines and spaces. Defaults to false" - }, - "@roblox/global/net.jsonEncode/return/0": { - "documentation": "The encoded JSON string" - }, - "@roblox/global/net.request": { - "code_sample": "", - "documentation": "Sends an HTTP request using the given url and / or parameters, and returns a dictionary that describes the response received.\n\nOnly throws an error if a miscellaneous network or I/O error occurs, never for unsuccessful status codes.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/net.request/param/0", - "name": "config" - } - ], - "returns": [ - "@roblox/global/net.request/return/0" - ] + "@roblox/global/fs.isDir/param/0": { + "documentation": "The directory path to check" }, "@roblox/global/net.request/param/0": { "documentation": "The URL or request config to use" }, - "@roblox/global/net.request/return/0": { - "documentation": "A dictionary representing the response for the request" - }, - "@roblox/global/net.serve": { - "code_sample": "", - "documentation": "Creates an HTTP server that listens on the given `port`.\n\nThis will ***not*** block and will keep listening for requests on the given `port`\nuntil the `stop` function on the returned `NetServeHandle` has been called.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/net.serve/param/0", - "name": "port" - }, - { - "documentation": "@roblox/global/net.serve/param/1", - "name": "handlerOrConfig" - } - ], - "returns": [] + "@roblox/global/net.socket/param/0": { + "documentation": "The URL to connect to" }, "@roblox/global/net.serve/param/0": { "documentation": "The port to use for the server" @@ -251,92 +471,18 @@ "@roblox/global/net.serve/param/1": { "documentation": "The handler function or config to use for the server" }, - "@roblox/global/net.socket": { - "code_sample": "", - "documentation": "Connects to a web socket at the given URL.\n\nThrows an error if the server at the given URL does not support\nweb sockets, or if a miscellaneous network or I/O error occurs.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/net.socket/param/0", - "name": "url" - } - ], - "returns": [ - "@roblox/global/net.socket/return/0" - ] + "@roblox/global/net.jsonEncode/param/0": { + "documentation": "The value to encode as JSON" }, - "@roblox/global/net.socket/param/0": { - "documentation": "The URL to connect to" + "@roblox/global/net.jsonEncode/param/1": { + "documentation": "If the encoded JSON string should include newlines and spaces. Defaults to false" }, - "@roblox/global/net.socket/return/0": { - "documentation": "A web socket handle" - }, - "@roblox/global/process": { - "code_sample": "", - "documentation": "Current process & child processes", - "keys": { - "process": "@roblox/global/process.process" - }, - "learn_more_link": "" - }, - "@roblox/global/process.args": { - "code_sample": "", - "documentation": "The arguments given when running the Lune script.", - "learn_more_link": "", - "params": [], - "returns": [] - }, - "@roblox/global/process.cwd": { - "code_sample": "", - "documentation": "The current working directory in which the Lune script is running.", - "learn_more_link": "", - "params": [], - "returns": [] - }, - "@roblox/global/process.env": { - "code_sample": "", - "documentation": "Current environment variables for this process.\n\nSetting a value on this table will set the corresponding environment variable.", - "learn_more_link": "", - "params": [], - "returns": [] - }, - "@roblox/global/process.exit": { - "code_sample": "", - "documentation": "Exits the currently running script as soon as possible with the given exit code.\n\nExit code 0 is treated as a successful exit, any other value is treated as an error.\n\nSetting the exit code using this function will override any otherwise automatic exit code.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/process.exit/param/0", - "name": "code" - } - ], - "returns": [] + "@roblox/global/net.jsonDecode/param/0": { + "documentation": "The JSON string to decode" }, "@roblox/global/process.exit/param/0": { "documentation": "The exit code to set" }, - "@roblox/global/process.spawn": { - "code_sample": "", - "documentation": "Spawns a child process that will run the program `program`, and returns a dictionary that describes the final status and ouput of the child process.\n\nThe second argument, `params`, can be passed as a list of string parameters to give to the program.\n\nThe third argument, `options`, can be passed as a dictionary of options to give to the child process.\nThe available options inside of the `options` dictionary are:\n* `cwd` - The current working directory for the process\n* `env` - Extra environment variables to give to the process\n* `shell` - Whether to run in a shell or not - set to `true` to run using the default shell, or a string to run using a specific shell\n* `stdio` - How to treat output and error streams from the child process - set to \"inherit\" to pass output and error streams to the current process", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/process.spawn/param/0", - "name": "program" - }, - { - "documentation": "@roblox/global/process.spawn/param/1", - "name": "params" - }, - { - "documentation": "@roblox/global/process.spawn/param/2", - "name": "options" - } - ], - "returns": [ - "@roblox/global/process.spawn/return/0" - ] - }, "@roblox/global/process.spawn/param/0": { "documentation": "The program to spawn as a child process" }, @@ -346,91 +492,20 @@ "@roblox/global/process.spawn/param/2": { "documentation": "A dictionary of options for the child process" }, - "@roblox/global/process.spawn/return/0": { - "documentation": "A dictionary representing the result of the child process" - }, - "@roblox/global/stdio": { - "code_sample": "", - "documentation": "Standard input / output & utility functions", - "keys": { - "stdio": "@roblox/global/stdio.stdio" - }, - "learn_more_link": "" - }, - "@roblox/global/stdio.color": { - "code_sample": "", - "documentation": "Return an ANSI string that can be used to modify the persistent output color.\n\nPass `\"reset\"` to get a string that can reset the persistent output color.\n\n### Example usage\n\n```lua\nstdio.write(stdio.color(\"red\"))\nprint(\"This text will be red\")\nstdio.write(stdio.color(\"reset\"))\nprint(\"This text will be normal\")\n```", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/stdio.color/param/0", - "name": "color" - } - ], - "returns": [ - "@roblox/global/stdio.color/return/0" - ] - }, "@roblox/global/stdio.color/param/0": { "documentation": "The color to use" }, - "@roblox/global/stdio.color/return/0": { - "documentation": "A printable ANSI string" - }, - "@roblox/global/stdio.ewrite": { - "code_sample": "", - "documentation": "Writes a string directly to stderr, without any newline.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/stdio.ewrite/param/0", - "name": "s" - } - ], - "returns": [] - }, - "@roblox/global/stdio.ewrite/param/0": { - "documentation": "The string to write to stderr" - }, - "@roblox/global/stdio.format": { - "code_sample": "", - "documentation": "Formats arguments into a human-readable string with syntax highlighting for tables.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/stdio.format/param/0", - "name": "..." - } - ], - "returns": [ - "@roblox/global/stdio.format/return/0" - ] + "@roblox/global/stdio.style/param/0": { + "documentation": "The style to use" }, "@roblox/global/stdio.format/param/0": { "documentation": "The values to format" }, - "@roblox/global/stdio.format/return/0": { - "documentation": "The formatted string" + "@roblox/global/stdio.write/param/0": { + "documentation": "The string to write to stdout" }, - "@roblox/global/stdio.prompt": { - "code_sample": "", - "documentation": "Prompts for user input using the wanted kind of prompt:\n\n* `\"text\"` - Prompts for a plain text string from the user\n* `\"confirm\"` - Prompts the user to confirm with y / n\n* `\"select\"` - Prompts the user to select *one* value from a list\n* `\"multiselect\"` - Prompts the user to select *one or more* values from a list\n* `nil` - Equivalent to `\"text\"` with no extra arguments", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/stdio.prompt/param/0", - "name": "kind" - }, - { - "documentation": "@roblox/global/stdio.prompt/param/1", - "name": "message" - }, - { - "documentation": "@roblox/global/stdio.prompt/param/2", - "name": "defaultOrOptions" - } - ], - "returns": [] + "@roblox/global/stdio.ewrite/param/0": { + "documentation": "The string to write to stderr" }, "@roblox/global/stdio.prompt/param/0": { "documentation": "The kind of prompt to use" @@ -441,141 +516,66 @@ "@roblox/global/stdio.prompt/param/2": { "documentation": "The default value for the prompt, or options to choose from for selection prompts" }, - "@roblox/global/stdio.style": { - "code_sample": "", - "documentation": "Return an ANSI string that can be used to modify the persistent output style.\n\nPass `\"reset\"` to get a string that can reset the persistent output style.\n\n### Example usage\n\n```lua\nstdio.write(stdio.style(\"bold\"))\nprint(\"This text will be bold\")\nstdio.write(stdio.style(\"reset\"))\nprint(\"This text will be normal\")\n```", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/stdio.style/param/0", - "name": "style" - } - ], - "returns": [ - "@roblox/global/stdio.style/return/0" - ] - }, - "@roblox/global/stdio.style/param/0": { - "documentation": "The style to use" - }, - "@roblox/global/stdio.style/return/0": { - "documentation": "A printable ANSI string" - }, - "@roblox/global/stdio.write": { - "code_sample": "", - "documentation": "Writes a string directly to stdout, without any newline.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/stdio.write/param/0", - "name": "s" - } - ], - "returns": [] - }, - "@roblox/global/stdio.write/param/0": { - "documentation": "The string to write to stdout" - }, - "@roblox/global/task": { - "code_sample": "", - "documentation": "Task scheduler & thread spawning", - "keys": { - "task": "@roblox/global/task.task" - }, - "learn_more_link": "" - }, - "@roblox/global/task.cancel": { - "code_sample": "", - "documentation": "Stops a currently scheduled thread from resuming.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/task.cancel/param/0", - "name": "thread" - } - ], - "returns": [] - }, "@roblox/global/task.cancel/param/0": { "documentation": "The thread to cancel" }, - "@roblox/global/task.defer": { - "code_sample": "", - "documentation": "Defers a thread or function to run at the end of the current task queue.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/task.defer/param/0", - "name": "functionOrThread" - } - ], - "returns": [ - "@roblox/global/task.defer/return/0" - ] - }, "@roblox/global/task.defer/param/0": { "documentation": "The function or thread to defer" }, - "@roblox/global/task.defer/return/0": { - "documentation": "The thread that will be deferred" - }, - "@roblox/global/task.delay": { - "code_sample": "", - "documentation": "Delays a thread or function to run after `duration` seconds.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/task.delay/param/0", - "name": "functionOrThread" - } - ], - "returns": [ - "@roblox/global/task.delay/return/0" - ] - }, "@roblox/global/task.delay/param/0": { "documentation": "The function or thread to delay" }, - "@roblox/global/task.delay/return/0": { - "documentation": "The thread that will be delayed" - }, - "@roblox/global/task.spawn": { - "code_sample": "", - "documentation": "Instantly runs a thread or function.\n\nIf the spawned task yields, the thread that spawned the task\nwill resume, letting the spawned task run in the background.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/task.spawn/param/0", - "name": "functionOrThread" - } - ], - "returns": [ - "@roblox/global/task.spawn/return/0" - ] - }, "@roblox/global/task.spawn/param/0": { "documentation": "The function or thread to spawn" }, - "@roblox/global/task.spawn/return/0": { - "documentation": "The thread that was spawned" - }, - "@roblox/global/task.wait": { - "code_sample": "", - "documentation": "Waits for the given duration, with a minimum wait time of 10 milliseconds.", - "learn_more_link": "", - "params": [ - { - "documentation": "@roblox/global/task.wait/param/0", - "name": "duration" - } - ], - "returns": [ - "@roblox/global/task.wait/return/0" - ] - }, "@roblox/global/task.wait/param/0": { "documentation": "The amount of time to wait" }, + "@roblox/global/fs.readFile/return/0": { + "documentation": "The contents of the file" + }, + "@roblox/global/fs.readDir/return/0": { + "documentation": "A list of files & directories found" + }, + "@roblox/global/fs.isFile/return/0": { + "documentation": "If the path is a file or not" + }, + "@roblox/global/fs.isDir/return/0": { + "documentation": "If the path is a directory or not" + }, + "@roblox/global/net.request/return/0": { + "documentation": "A dictionary representing the response for the request" + }, + "@roblox/global/net.socket/return/0": { + "documentation": "A web socket handle" + }, + "@roblox/global/net.jsonEncode/return/0": { + "documentation": "The encoded JSON string" + }, + "@roblox/global/net.jsonDecode/return/0": { + "documentation": "The decoded lua value" + }, + "@roblox/global/process.spawn/return/0": { + "documentation": "A dictionary representing the result of the child process" + }, + "@roblox/global/stdio.color/return/0": { + "documentation": "A printable ANSI string" + }, + "@roblox/global/stdio.style/return/0": { + "documentation": "A printable ANSI string" + }, + "@roblox/global/stdio.format/return/0": { + "documentation": "The formatted string" + }, + "@roblox/global/task.defer/return/0": { + "documentation": "The thread that will be deferred" + }, + "@roblox/global/task.delay/return/0": { + "documentation": "The thread that will be delayed" + }, + "@roblox/global/task.spawn/return/0": { + "documentation": "The thread that was spawned" + }, "@roblox/global/task.wait/return/0": { "documentation": "The exact amount of time waited" } diff --git a/packages/cli/src/gen/doc.rs b/packages/cli/src/gen/doc/mod.rs similarity index 95% rename from packages/cli/src/gen/doc.rs rename to packages/cli/src/gen/doc/mod.rs index 07eb511..2514123 100644 --- a/packages/cli/src/gen/doc.rs +++ b/packages/cli/src/gen/doc/mod.rs @@ -2,6 +2,12 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; +mod tag; +mod visitor; + +pub use tag::*; +pub use visitor::*; + #[derive(Serialize, Deserialize, Default, Debug, Clone)] pub struct DocsGlobal { pub documentation: String, diff --git a/packages/cli/src/gen/tag.rs b/packages/cli/src/gen/doc/tag.rs similarity index 100% rename from packages/cli/src/gen/tag.rs rename to packages/cli/src/gen/doc/tag.rs diff --git a/packages/cli/src/gen/visitor.rs b/packages/cli/src/gen/doc/visitor.rs similarity index 87% rename from packages/cli/src/gen/visitor.rs rename to packages/cli/src/gen/doc/visitor.rs index 6923207..678bbb0 100644 --- a/packages/cli/src/gen/visitor.rs +++ b/packages/cli/src/gen/doc/visitor.rs @@ -1,13 +1,15 @@ +use anyhow::Result; use full_moon::{ ast::types::{ExportedTypeDeclaration, TypeField, TypeFieldKey}, + parse as parse_luau_ast, tokenizer::{Token, TokenType}, visitors::Visitor, }; use regex::Regex; use super::{ - doc::{DocsFunction, DocsFunctionParamLink, DocsGlobal, DocsParam, DocsReturn}, - tag::{DocsTag, DocsTagKind, DocsTagList}, + {DocsFunction, DocsFunctionParamLink, DocsGlobal, DocsParam, DocsReturn}, + {DocsTag, DocsTagKind, DocsTagList}, }; #[derive(Debug, Clone)] @@ -31,6 +33,25 @@ impl DocumentationVisitor { } } + pub fn from_definitions(definitions_file_contents: &str) -> Result { + // TODO: Properly handle the "declare class" syntax, for now we just skip it + let mut no_declares = definitions_file_contents.to_string(); + while let Some(dec) = no_declares.find("\ndeclare class") { + let end = no_declares.find("\nend").unwrap(); + let before = &no_declares[0..dec]; + let after = &no_declares[end + 4..]; + no_declares = format!("{before}{after}"); + } + let (regex, replacement) = ( + Regex::new(r#"declare (?P\w+): "#).unwrap(), + r#"export type $n = "#, + ); + let defs_ast = parse_luau_ast(®ex.replace_all(&no_declares, replacement))?; + let mut visitor = DocumentationVisitor::new(); + visitor.visit_ast(&defs_ast); + Ok(visitor) + } + pub fn parse_moonwave_style_tag(&self, line: &str) -> Option { if self.tag_regex.is_match(line) { let captures = self.tag_regex.captures(line).unwrap(); diff --git a/packages/cli/src/gen/mod.rs b/packages/cli/src/gen/mod.rs index d637d16..4da1f3a 100644 --- a/packages/cli/src/gen/mod.rs +++ b/packages/cli/src/gen/mod.rs @@ -1,47 +1,24 @@ use std::{collections::HashMap, fmt::Write, path::PathBuf}; use anyhow::{Context, Result}; -use regex::Regex; -use serde_json::{Map, Value}; +use serde_json::{Map as JsonMap, Value as JsonValue}; -use full_moon::{parse as parse_luau_ast, visitors::Visitor}; use tokio::fs::{create_dir_all, write}; mod doc; -mod tag; -mod visitor; const GENERATED_COMMENT_TAG: &str = "@generated with lune-cli"; -use self::{doc::DocsFunctionParamLink, visitor::DocumentationVisitor}; - -pub fn parse_definitions(contents: &str) -> Result { - // TODO: Properly handle the "declare class" syntax, for now we just skip it - let mut no_declares = contents.to_string(); - while let Some(dec) = no_declares.find("\ndeclare class") { - let end = no_declares.find("\nend").unwrap(); - let before = &no_declares[0..dec]; - let after = &no_declares[end + 4..]; - no_declares = format!("{before}{after}"); - } - let (regex, replacement) = ( - Regex::new(r#"declare (?P\w+): "#).unwrap(), - r#"export type $n = "#, - ); - let defs_ast = parse_luau_ast(®ex.replace_all(&no_declares, replacement))?; - let mut visitor = DocumentationVisitor::new(); - visitor.visit_ast(&defs_ast); - Ok(visitor) -} +use self::doc::{DocsFunctionParamLink, DocumentationVisitor}; pub fn generate_docs_json_from_definitions(contents: &str, namespace: &str) -> Result { - let visitor = parse_definitions(contents)?; + let visitor = DocumentationVisitor::from_definitions(contents)?; /* Extract globals, functions, params, returns from the visitor Here we will also convert the plain names into proper namespaced names according to the spec at https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/roblox/api-docs/en-us.json */ - let mut map = Map::new(); + let mut map = JsonMap::new(); for (name, mut doc) in visitor.globals { doc.keys = doc .keys @@ -90,7 +67,7 @@ pub fn generate_docs_json_from_definitions(contents: &str, namespace: &str) -> R serde_json::to_value(doc)?, ); } - serde_json::to_string_pretty(&Value::Object(map)).context("Failed to encode docs as json") + serde_json::to_string_pretty(&JsonValue::Object(map)).context("Failed to encode docs as json") } pub async fn generate_wiki_dir_from_definitions(contents: &str) -> Result<()> { @@ -102,7 +79,7 @@ pub async fn generate_wiki_dir_from_definitions(contents: &str) -> Result<()> { create_dir_all(&root.join("wiki")) .await .context("Failed to create wiki dir")?; - let visitor = parse_definitions(contents)?; + let visitor = DocumentationVisitor::from_definitions(contents)?; for global in &visitor.globals { // Create the dir for this global let global_dir_path = root.join("wiki").join("api-reference").join(&global.0);