diff --git a/lib/cli.luau b/lib/cli.luau index 3eaeec5..4f576e1 100644 --- a/lib/cli.luau +++ b/lib/cli.luau @@ -12,7 +12,19 @@ export type CLI = { local cli = {} :: CLI --- parses command line arguments into options +--[[ + Parses command line arguments into an options table. + + ### Example usage + + ```lua + local cli = require("./cli") + + local opts = cli.parseArgs() + ``` + + @return An options table containing parsed command line arguments of type `types.opts`. +]]-- function cli.parseArgs(): types.opts local args: {string} = process.args local opts: types.opts = { @@ -73,7 +85,19 @@ function cli.parseArgs(): types.opts return opts end --- prints usage instructions for the command line tool +--[[ + Prints usage instructions for the command line tool. + + ### Example usage + + ```lua + local cli = require("./cli") + + cli.printUsage() + ``` + + @return none +]]-- function cli.printUsage() stdio.write(stdio.color("red")) stdio.write("Error: Please provide file path(s) or use --directory flag.\n") @@ -90,7 +114,21 @@ function cli.printUsage() stdio.write(stdio.color("reset")) end --- checks if output file exists to prevent overwriting +--[[ + Checks if the specified output file already exists to prevent overwriting. + If the file exists, prints an error message and exits the program. + + ### Example usage + + ```lua + local cli = require("./cli") + + cli.checkOutputFile("output.txt") + ``` + + @param outputFile The path to the output file to check. + @return none +]]-- function cli.checkOutputFile(outputFile: string?) if outputFile and fs.isFile(outputFile) then stdio.write(stdio.color("red")) diff --git a/lib/compression.luau b/lib/compression.luau index b6fdfcc..8046875 100644 --- a/lib/compression.luau +++ b/lib/compression.luau @@ -8,9 +8,28 @@ type CompressionModule = { local compressionModule = {} :: CompressionModule --- take in file contents and zlib decompress them --- if recursive param is true repeatedly zlib decompress the file until it fails --- (modelscrape files are often double/triple zlib decompressed) +--[[ + Decompresses zlib-compressed data. If recursive is true, continues to decompress until data is no longer zlib-compressed. + + ### Example usage + + ```lua + local fs = require("@lune/fs") + local compression = require("./compression") + + local compressedData = fs.readFile("compressedFile.bin") + local decompressedData = compression.zlibDecompress(compressedData, true) + if decompressedData then + print("Decompression successful.") + else + print("Decompression failed.") + end + ``` + + @param contents The zlib-compressed data as a string. + @param opts Options table of type `types.opts` + @return The decompressed data as a string, or false if decompression fails. +]]-- function compressionModule.zlibDecompress(contents: string, opts: types.opts): string | boolean assert(typeof(contents) == "string", "Expected contents to be of type 'string'") assert(typeof(opts) == "table", "Expected opts to be of type 'table'") diff --git a/lib/core.luau b/lib/core.luau index 9e09891..08e7f7b 100644 --- a/lib/core.luau +++ b/lib/core.luau @@ -13,7 +13,27 @@ export type Core = { local core = {} :: Core --- recursively searches a model for a workspace instance +--[[ + Recursively scans a model (table of Instances) for a Workspace instance. + + ### Example usage + + ```lua + local roblox = require("@lune/roblox") + local core = require("./core") + + local model = roblox.deserializeModel(fileContents) + if core.scanForWorkspace(model) then + print("This model contains a Workspace instance.") + else + print("This model does not contain a Workspace instance.") + end + ``` + + @param model The deserialized Roblox model to scan. + @param printInstanceNames If true, prints the full names of all instances in the model during the scan. + @return True if a Workspace instance is found, false otherwise. +]]-- function core.scanForWorkspace(model: types.model, printInstanceNames: boolean): boolean assert(typeof(model) == "table", "Expected model to be of type 'table''") assert(typeof(printInstanceNames) == "boolean", "Expected printInstanceNames to be of type 'boolean'") @@ -28,14 +48,62 @@ function core.scanForWorkspace(model: types.model, printInstanceNames: boolean): return false end --- checks if file has valid extension +--[[ + Returns true if the file has a .rbxm or .rbxmx extension, false otherwise. + + ### Example usage + + ```lua + local fs = require("@lune/fs") + + local modelFile = fs.readFile("filePath.rbxm") + if core.isValidModelFile("filePath.rbxm") then + print("This is a valid Roblox model file.") + else + print("This is not a valid Roblox model file.") + end + ``` + + @param contents The filename of the model file to check. + @return True if the file has a valid model extension, false otherwise. +]]-- function core.isValidModelFile(fileName: string): boolean assert(typeof(fileName) == "string", "Expected fileName to be of type 'string'") local ext = string.match(fileName, "%.([^%.]+)$") return ext == "rbxm" or ext == "rbxmx" end --- takes in fileContents as a string and deserializes them returning the results of scanForWorkspace() on the deserialized model. if it can't be deserialized, it will return the results of a naive search through the xml + +--[[ + Checks if the given file contents contain a Workspace instance. + + If the file is a valid Roblox model file, attempts to deserialize it and scan for a Workspace instance. + If deserialization fails, falls back to a simple string search for the Workspace tag. + + If zlib decompression options are enabled in opts, attempts to decompress the file contents before scanning. + + ### Example usage + + ```lua + local fs = require("@lune/fs") + local core = require("./core") + + local fileContents = fs.readFile("model.rbxm") + local opts = { + printInstanceNames = true, + zlibDecompressFiles = true, + zlibDecompressFilesRecursive = false + } + if core.fileContainsWorkspace(fileContents, opts) then + print("The file contains a Workspace instance.") + else + print("The file does not contain a Workspace instance.") + end + ``` + @param fileContents The contents of the file to check. + @param opts Options table of type `types.opts` + @return True if a Workspace instance is found, false otherwise. +]] function core.fileContainsWorkspace(fileContents: string, opts: types.opts): boolean assert(typeof(fileContents) == "string", "Expected fileContents to be of type 'string'") assert(typeof(opts) == "table", "Expected opts to be of type 'table'") @@ -55,7 +123,13 @@ function core.fileContainsWorkspace(fileContents: string, opts: types.opts): boo end --- formats the workspace detection result as a colored string +--[[ + Formats the workspace detection result as a colored string. + + @param result The boolean result of the workspace detection. + @param fileName The name of the file that was checked. + @return A formatted string indicating whether the file contains a Workspace instance, colored green for true and yellow for false. +]]-- function core.formatResult(result: boolean, fileName: string): string assert(typeof(result) == "boolean", "Expected result to be of type 'boolean'") assert(typeof(fileName) == "string", "Expected fileName to be of type 'string'") diff --git a/lib/fileproc.luau b/lib/fileproc.luau index fda696f..ef54f97 100644 --- a/lib/fileproc.luau +++ b/lib/fileproc.luau @@ -12,7 +12,23 @@ export type FileProc = { local fileproc = {} :: FileProc --- collects files to process from command line args or directory +--[[ + Collects files to process based on command line arguments or directory mode. + + ### Example usage + + ```lua + local cli = require("./cli") + local fileproc = require("./fileproc") + + local opts = cli.parseArgs() + local filesToProcess = fileproc.collectFiles(opts) + print("Files to process:", table.concat(filesToProcess, ", ")) + ``` + + @param opts Options table of type `types.opts`. + @return A list of file paths to process. +]]-- function fileproc.collectFiles(opts: types.opts): {string} assert(typeof(opts) == "table", "Expected opts to be of type 'table'") local filesToProcess = opts.filesToProcess or {} @@ -52,7 +68,25 @@ function fileproc.collectFiles(opts: types.opts): {string} return filesToProcess end --- processes each file and checks for workspace instances +--[[ + Processes each file and checks for workspace instances. + + ### Example usage + + ```lua + local cli = require("./cli") + local fileproc = require("./fileproc") + + local opts = cli.parseArgs() + local filesToProcess = fileproc.collectFiles(opts) + local filesWithWorkspace = fileproc.processFiles(filesToProcess, opts) + print("Files containing Workspace instances:", table.concat(filesWithWorkspace, ", ")) + ``` + + @param filesToProcess A list of file paths to process. + @param opts Options table of type `types.opts`. + @return A list of file paths that contain Workspace instances. +]]-- function fileproc.processFiles(filesToProcess: {string}, opts: types.opts): {string} assert(typeof(filesToProcess) == "table", "Expected filesToProcess to be of type 'table'") assert(typeof(opts) == "table", "Expected opts to be of type 'table'") diff --git a/lib/types.luau b/lib/types.luau index 0c9a6fd..a038a37 100644 --- a/lib/types.luau +++ b/lib/types.luau @@ -2,6 +2,19 @@ local types = {} +--[[ + Options table type definition. + + Will contain these values: + * `outputFile` - The path to the output file, if specified + * `directoryMode` - Whether to operate in directory mode + * `directoryPath` - The path to the directory to scan, if in directory mode + * `forceBinaryRead` - Whether to force reading files even if they lack file extensions + * `printInstanceNames` - Whether to print the names of all instances in the models scanned + * `zlibDecompressFiles` - Whether to decompress zlib-compressed files + * `zlibDecompressFilesRecursive` - Whether to recursively decompress zlib-compressed files + * `filesToProcess` - A list of file paths to process + ]]-- export type opts = { outputFile: string?, directoryMode: boolean, @@ -15,6 +28,15 @@ export type opts = { export type model = {Instance} +--[[ + Callback function type definition. + + A function that takes a file path and options table, and returns either a string (e.g. processed data) or false on failure. + + @param file The path to the file to process. + @param opts Options table of type `types.opts` + @return A string containing processed data, or false if processing fails. +]]-- export type callbackFunction = (file: string, opts: opts) -> string | boolean return types \ No newline at end of file