From ef8953fdcc3bdacdc90633b7e3519ec8e1b61bc4 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sun, 8 Dec 2024 18:30:38 +0000 Subject: [PATCH] style: apply stylua formatter --- .lune/build.luau | 259 ++++++++++++---------- .lune/fmt.luau | 8 +- .lune/lib/channel.luau | 44 ++-- .lune/lib/exec.luau | 144 ++++++------ .lune/lib/manifest.luau | 121 +++++----- .lune/tests/init.luau | 92 ++++---- .lune/tests/reporter.luau | 82 ++++--- .lune/typecheck.luau | 16 +- src/generators/rojo/sourcemap.luau | 54 ++--- src/generators/rojo/sourcemap.spec.luau | 131 ++++++----- src/generators/rojo/sync_config.luau | 138 ++++++------ src/generators/rojo/sync_config.spec.luau | 43 ++-- src/init.luau | 12 +- 13 files changed, 625 insertions(+), 519 deletions(-) diff --git a/.lune/build.luau b/.lune/build.luau index baa11a0..a3577cd 100644 --- a/.lune/build.luau +++ b/.lune/build.luau @@ -11,18 +11,18 @@ local pathfs = require("../lune_packages/pathfs") type ToolChoice = "rojo" type ManifestExt = { - scripts: { - [ToolChoice]: { - version: string, - tool_dependencies: { { [string]: manifest.DependencySpecifier } }, - }, - }, + scripts: { + [ToolChoice]: { + version: string, + tool_dependencies: { { [string]: manifest.DependencySpecifier } }, + }, + }, } local SCRIPTS_DIR = pathfs.getAbsolutePathOf(pathfs.Path.from(".pesde")) local MANIFEST = manifest(nil, (nil :: any) :: { meta: ManifestExt }) local SCRIPTS = { - syncConfigGenerator = [[local process = require("@lune/process") + syncConfigGenerator = [[local process = require("@lune/process") local args = table.clone(process.args) local ok, _ = @@ -31,7 +31,7 @@ if not ok then return process.exit(1) end]], - sourcemapGenerator = [[local process = require("@lune/process") + sourcemapGenerator = [[local process = require("@lune/process") local ok = require("./lune_packages/core").generators.%s.sourcemap(process.args[1]) if not ok then @@ -54,142 +54,171 @@ Prints out a sourcemap for Wally dependencies for type extraction. ]] local function logPrefix(type: "error" | "info") - local statusColor: stdio.Color = if type == "error" - then "red" - elseif type == "info" then "green" - else error(`Invalid type: {type}`) + local statusColor: stdio.Color = if type == "error" + then "red" + elseif type == "info" then "green" + else error(`Invalid type: {type}`) - return `main::{stdio.style("bold")}{stdio.color(statusColor)}{type}{stdio.color("reset")}` + return `main::{stdio.style("bold")}{stdio.color(statusColor)}{type}{stdio.color( + "reset" + )}` end local INFO_PREFIX = `[ {logPrefix("info")}]` local _ERROR_PREFIX = `[{logPrefix("error")}]` local function installDeps(): number - local PESDE_INFO_PREFIX = string.gsub(`[{logPrefix("info")}]`, "main", "pesde") - local PESDE_ERROR_PREFIX = string.gsub(`[{logPrefix("error")}]`, "main", "pesde") - local SPINNER_STATES = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" } + local PESDE_INFO_PREFIX = + string.gsub(`[{logPrefix("info")}]`, "main", "pesde") + local PESDE_ERROR_PREFIX = + string.gsub(`[{logPrefix("error")}]`, "main", "pesde") + local SPINNER_STATES = + { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" } - stdio.write(`{PESDE_INFO_PREFIX} Installing dependencies with pesde`) + stdio.write(`{PESDE_INFO_PREFIX} Installing dependencies with pesde`) - -- Spawn our thread to display the spinner - local spinnerThread = task.spawn(function() - -- Hide the cursor - stdio.write("\x1b[?25l") + -- Spawn our thread to display the spinner + local spinnerThread = task.spawn(function() + -- Hide the cursor + stdio.write("\x1b[?25l") - -- Display the spinner - while true do - for _, state in SPINNER_STATES do - stdio.write(` {state}`) - stdio.write( - -- Moves the cursor back 1 spot and clears everything after - "\x1b[2D\x1b[0K" - ) - end - end - end) + -- Display the spinner + while true do + for _, state in SPINNER_STATES do + stdio.write(` {state}`) + stdio.write( + -- Moves the cursor back 1 spot and clears everything after + "\x1b[2D\x1b[0K" + ) + end + end + end) - -- `process_spawn` is an async rust function, so tokio spawns a hardware - -- thread and mlua will yield the current thread, allowing for `spinnerThread` - -- to continue executing - local child = process.spawn("pesde", { "install" }, { - stdio = "default", - }) + -- `process_spawn` is an async rust function, so tokio spawns a hardware + -- thread and mlua will yield the current thread, allowing for `spinnerThread` + -- to continue executing + local child = process.spawn("pesde", { "install" }, { + stdio = "default", + }) - -- If we reach this point, that means mlua resumed the current thread and - -- `process_spawn` returned or errored. We can now close `spinnerThread` and - -- clean up + -- If we reach this point, that means mlua resumed the current thread and + -- `process_spawn` returned or errored. We can now close `spinnerThread` and + -- clean up - task.cancel(spinnerThread) - stdio.write( - -- Clear the current line, move cursor back to its beginning and - -- show it - "\x1b[2K\x1b[1G\x1b[?25h" - ) + task.cancel(spinnerThread) + stdio.write( + -- Clear the current line, move cursor back to its beginning and + -- show it + "\x1b[2K\x1b[1G\x1b[?25h" + ) - if not child.ok then - stdio.ewrite(`{PESDE_ERROR_PREFIX} Failed to install dependencies with pesde, error:\n`) - stdio.ewrite(child.stderr) - end + if not child.ok then + stdio.ewrite( + `{PESDE_ERROR_PREFIX} Failed to install dependencies with pesde, error:\n` + ) + stdio.ewrite(child.stderr) + end - stdio.write(`{PESDE_INFO_PREFIX} Installed dependencies with pesde successfully\n`) + stdio.write( + `{PESDE_INFO_PREFIX} Installed dependencies with pesde successfully\n` + ) - return child.code + return child.code end for tool, generators in lib.generators do - local startTime = os.clock() + local startTime = os.clock() - -- For each tool, we generate a respective manifests and scripts - local toolChoice = tool :: ToolChoice - local toolScriptsDir = SCRIPTS_DIR:join(toolChoice) - local toolMeta = MANIFEST.meta.scripts[toolChoice] + -- For each tool, we generate a respective manifests and scripts + local toolChoice = tool :: ToolChoice + local toolScriptsDir = SCRIPTS_DIR:join(toolChoice) + local toolMeta = MANIFEST.meta.scripts[toolChoice] - if not pathfs.isDir(toolScriptsDir) then - pathfs.writeDir(toolScriptsDir) - end + if not pathfs.isDir(toolScriptsDir) then + pathfs.writeDir(toolScriptsDir) + end - local capitalisedToolChoice = string.gsub(toolChoice, "^%l", string.upper) + local capitalisedToolChoice = string.gsub(toolChoice, "^%l", string.upper) - -- Define the manifest for the tool - local toolManifest: manifest.PesdeManifest = { - name = `pesde/scripts_{toolChoice}`, - version = toolMeta.version, - -- For the description, we capitalize the first letter of the tool name here - -- since it is a proper noun - description = `Scripts for {capitalisedToolChoice}-based Roblox projects.`, - authors = { - "daimond113 (https://www.daimond113.com/)", - "Erica Marigold ", - }, - repository = "https://github.com/pesde-pkg/scripts", - license = "MIT", - includes = { - "roblox_sync_config_generator.luau", - "sourcemap_generator.luau", - "pesde.toml", - "README.md", - "LICENSE", - }, + -- Define the manifest for the tool + local toolManifest: manifest.PesdeManifest = { + name = `pesde/scripts_{toolChoice}`, + version = toolMeta.version, + -- For the description, we capitalize the first letter of the tool name here + -- since it is a proper noun + description = `Scripts for {capitalisedToolChoice}-based Roblox projects.`, + authors = { + "daimond113 (https://www.daimond113.com/)", + "Erica Marigold ", + }, + repository = "https://github.com/pesde-pkg/scripts", + license = "MIT", + includes = { + "roblox_sync_config_generator.luau", + "sourcemap_generator.luau", + "pesde.toml", + "README.md", + "LICENSE", + }, - target = { - environment = "lune", - scripts = { - roblox_sync_config_generator = "roblox_sync_config_generator.luau", - sourcemap_generator = "sourcemap_generator.luau", - }, - }, + target = { + environment = "lune", + scripts = { + roblox_sync_config_generator = "roblox_sync_config_generator.luau", + sourcemap_generator = "sourcemap_generator.luau", + }, + }, - peer_dependencies = toolMeta.tool_dependencies, - dependencies = { - core = { workspace = "pesde/scripts_core", version = "^" }, - }, + peer_dependencies = toolMeta.tool_dependencies, + dependencies = { + core = { workspace = "pesde/scripts_core", version = "^" }, + }, - indices = { - default = "https://github.com/pesde-pkg/index", - }, - } + indices = { + default = "https://github.com/pesde-pkg/index", + }, + } - -- Format the scripts for the tool - local syncConfigGeneratorScript, sourcemapGeneratorScript = - string.format(SCRIPTS.syncConfigGenerator, toolChoice), string.format(SCRIPTS.sourcemapGenerator, toolChoice) + -- Format the scripts for the tool + local syncConfigGeneratorScript, sourcemapGeneratorScript = + string.format(SCRIPTS.syncConfigGenerator, toolChoice), + string.format(SCRIPTS.sourcemapGenerator, toolChoice) - -- Finally, write all the generated files - pathfs.writeFile(toolScriptsDir:join("pesde.toml"), serde.encode("toml", toolManifest, true)) - pathfs.writeFile(toolScriptsDir:join("roblox_sync_config_generator.luau"), syncConfigGeneratorScript) - pathfs.writeFile(toolScriptsDir:join("sourcemap_generator.luau"), sourcemapGeneratorScript) - pathfs.writeFile( - toolScriptsDir:join("README.md"), - string.format(README_TMPL, toolChoice, capitalisedToolChoice, capitalisedToolChoice) - ) - pathfs.copy(pathfs.cwd:join("LICENSE"), toolScriptsDir:join("LICENSE"), true) + -- Finally, write all the generated files + pathfs.writeFile( + toolScriptsDir:join("pesde.toml"), + serde.encode("toml", toolManifest, true) + ) + pathfs.writeFile( + toolScriptsDir:join("roblox_sync_config_generator.luau"), + syncConfigGeneratorScript + ) + pathfs.writeFile( + toolScriptsDir:join("sourcemap_generator.luau"), + sourcemapGeneratorScript + ) + pathfs.writeFile( + toolScriptsDir:join("README.md"), + string.format( + README_TMPL, + toolChoice, + capitalisedToolChoice, + capitalisedToolChoice + ) + ) + pathfs.copy( + pathfs.cwd:join("LICENSE"), + toolScriptsDir:join("LICENSE"), + true + ) - stdio.write( - `{INFO_PREFIX} Generated script project for tool {toolChoice} ({stdio.style("dim")}{string.format( - "%.2fms", - (os.clock() - startTime) * 1000 - )}{stdio.style("reset")})\n` - ) + stdio.write( + `{INFO_PREFIX} Generated script project for tool {toolChoice} ({stdio.style( + "dim" + )}{string.format("%.2fms", (os.clock() - startTime) * 1000)}{stdio.style( + "reset" + )})\n` + ) end -- Now we install the dependencies for the newly created projects diff --git a/.lune/fmt.luau b/.lune/fmt.luau index 77be22a..1976516 100644 --- a/.lune/fmt.luau +++ b/.lune/fmt.luau @@ -4,4 +4,10 @@ local process = require("@lune/process") local CommandBuilder = require("./lib/exec") -process.exit(CommandBuilder.new("stylua"):withArg("."):withArgs(process.args):withStdioStrategy("forward"):exec().code) +process.exit( + CommandBuilder.new("stylua") + :withArg(".") + :withArgs(process.args) + :withStdioStrategy("forward") + :exec().code +) diff --git a/.lune/lib/channel.luau b/.lune/lib/channel.luau index 8fa1479..bce40c0 100644 --- a/.lune/lib/channel.luau +++ b/.lune/lib/channel.luau @@ -11,38 +11,38 @@ --- end) --- ``` type Watch = { - value: T?, - receivers: { thread }, + value: T?, + receivers: { thread }, } --- Creates a new `Watch` channel, returning its send and receive handles. local function chan(_phantom: T): ((T) -> (), () -> T?) - local watch: Watch = { - value = nil, - receivers = {}, - } + local watch: Watch = { + value = nil, + receivers = {}, + } - local function send(value: T) - watch.value = value + local function send(value: T) + watch.value = value - for _, receiver in watch.receivers do - coroutine.resume(receiver, value) - end - end + for _, receiver in watch.receivers do + coroutine.resume(receiver, value) + end + end - local function recv(): T - local value = watch.value - watch.value = nil + local function recv(): T + local value = watch.value + watch.value = nil - if value == nil then - table.insert(watch.receivers, coroutine.running()) - return coroutine.yield() - end + if value == nil then + table.insert(watch.receivers, coroutine.running()) + return coroutine.yield() + end - return value :: T - end + return value :: T + end - return send, recv + return send, recv end return chan diff --git a/.lune/lib/exec.luau b/.lune/lib/exec.luau index 9550729..0bcc6dd 100644 --- a/.lune/lib/exec.luau +++ b/.lune/lib/exec.luau @@ -5,99 +5,119 @@ local stdio = require("@lune/stdio") local CommandBuilder = {} -export type CommandBuilder = typeof(setmetatable({} :: CommandBuilderFields, { __index = CommandBuilder })) +export type CommandBuilder = typeof(setmetatable( + {} :: CommandBuilderFields, + { __index = CommandBuilder } +)) type CommandBuilderFields = { - program: string, - args: { string }, - stdioStrategy: IoStrategyMapping?, + program: string, + args: { string }, + stdioStrategy: IoStrategyMapping?, } export type StdioStrategy = "pipe" | "forward" | "none" export type IoStrategyMapping = { - stdout: StdioStrategy?, - stderr: StdioStrategy?, + stdout: StdioStrategy?, + stderr: StdioStrategy?, } local DEFAULT_STDIO_STRATEGY: IoStrategyMapping = { - stdout = "pipe", - stderr = "pipe", + stdout = "pipe", + stderr = "pipe", } function CommandBuilder.new(program: string) - return setmetatable( - { - program = program, - args = {}, - stdioStrategy = nil, - } :: CommandBuilderFields, - { - __index = CommandBuilder, - } - ) + return setmetatable( + { + program = program, + args = {}, + stdioStrategy = nil, + } :: CommandBuilderFields, + { + __index = CommandBuilder, + } + ) end -function CommandBuilder.withArg(self: CommandBuilder, arg: string): CommandBuilder - table.insert(self.args, arg) - return self +function CommandBuilder.withArg( + self: CommandBuilder, + arg: string +): CommandBuilder + table.insert(self.args, arg) + return self end -function CommandBuilder.withArgs(self: CommandBuilder, args: { string }): CommandBuilder - for _, arg in args do - self:withArg(arg) - end +function CommandBuilder.withArgs( + self: CommandBuilder, + args: { string } +): CommandBuilder + for _, arg in args do + self:withArg(arg) + end - return self + return self end function CommandBuilder.withStdioStrategy( - self: CommandBuilder, - strategy: StdioStrategy | IoStrategyMapping + self: CommandBuilder, + strategy: StdioStrategy | IoStrategyMapping ): CommandBuilder - self.stdioStrategy = if typeof(strategy) == "string" - then { - stdout = strategy, - stderr = strategy, - } - else strategy - return self + self.stdioStrategy = if typeof(strategy) == "string" + then { + stdout = strategy, + stderr = strategy, + } + else strategy + return self end -local function intoSpawnOptionsStdioKind(strategy: StdioStrategy): process.SpawnOptionsStdioKind - if strategy == "pipe" then - return "default" - end +local function intoSpawnOptionsStdioKind( + strategy: StdioStrategy +): process.SpawnOptionsStdioKind + if strategy == "pipe" then + return "default" + end - if strategy == "forward" then - return "forward" - end + if strategy == "forward" then + return "forward" + end - if strategy == "none" then - return "none" - end + if strategy == "none" then + return "none" + end - error(`Non-strategy provided: {strategy}`) + error(`Non-strategy provided: {strategy}`) end function CommandBuilder.exec(self: CommandBuilder): process.SpawnResult - print("$", stdio.style("dim") .. self.program, table.concat(self.args, " ") .. stdio.style("reset")) + print( + "$", + stdio.style("dim") .. self.program, + table.concat(self.args, " ") .. stdio.style("reset") + ) - local function translateIoStrategyMappings(mappings: IoStrategyMapping) - local translatedMappings: process.SpawnOptionsStdio = {} - for field, value in mappings do - translatedMappings[field] = intoSpawnOptionsStdioKind(value) - end + local function translateIoStrategyMappings(mappings: IoStrategyMapping) + local translatedMappings: process.SpawnOptionsStdio = {} + for field, value in mappings do + translatedMappings[field] = intoSpawnOptionsStdioKind(value) + end - return translatedMappings - end + return translatedMappings + end - local child = process.spawn(self.program, self.args, { - shell = true, - stdio = translateIoStrategyMappings(self.stdioStrategy or DEFAULT_STDIO_STRATEGY), - }) + local child = process.spawn(self.program, self.args, { + shell = true, + stdio = translateIoStrategyMappings( + self.stdioStrategy or DEFAULT_STDIO_STRATEGY + ), + }) - if not child.ok then - print(`\n{stdio.color("red")}[luau-lsp]{stdio.color("reset")} Exited with code`, child.code) - end + if not child.ok then + print( + `\n{stdio.color("red")}[luau-lsp]{stdio.color("reset")} Exited with code`, + child.code + ) + end - return child + return child end return CommandBuilder diff --git a/.lune/lib/manifest.luau b/.lune/lib/manifest.luau index 0c524d7..5380bf1 100644 --- a/.lune/lib/manifest.luau +++ b/.lune/lib/manifest.luau @@ -2,72 +2,79 @@ local fs = require("@lune/fs") local serde = require("@lune/serde") export type SPDXLicense = - "MIT" - | "Apache-2.0" - | "BSD-2-Clause" - | "BSD-3-Clause" - | "GPL-2.0" - | "GPL-3.0" - | "LGPL-2.1" - | "LGPL-3.0" - | "MPL-2.0" - | "ISC" - | "Unlicense" - | "WTFPL" - | "Zlib" - | "CC0-1.0" - | "CC-BY-4.0" - | "CC-BY-SA-4.0" - | "BSL-1.0" - | "EPL-2.0" - | "AGPL-3.0" + "MIT" + | "Apache-2.0" + | "BSD-2-Clause" + | "BSD-3-Clause" + | "GPL-2.0" + | "GPL-3.0" + | "LGPL-2.1" + | "LGPL-3.0" + | "MPL-2.0" + | "ISC" + | "Unlicense" + | "WTFPL" + | "Zlib" + | "CC0-1.0" + | "CC-BY-4.0" + | "CC-BY-SA-4.0" + | "BSL-1.0" + | "EPL-2.0" + | "AGPL-3.0" -export type DependencySpecifier = (( - { name: string, version: string, index: string? } - | { workspace: string, version: string } -) & { - target: string?, -}) - | { wally: string, version: string, index: string? } - | { repo: string, rev: string, path: string? } +export type DependencySpecifier = (({ + name: string, + version: string, + index: string?, +} | { workspace: string, version: string }) & { + target: string?, +}) | { + wally: string, + version: string, + index: string?, +} | { + repo: string, + rev: string, + path: string?, +} export type PackageTarget = { - environment: "roblox" | "roblox_server", - lib: string, + environment: "roblox" | "roblox_server", + lib: string, } | { - environment: "luau" | "lune", - lib: string, - bin: string, - scripts: { [string]: string }, + environment: "luau" | "lune", + lib: string, + bin: string, + scripts: { [string]: string }, } export type PesdeManifest = { - name: string, - version: string, - description: string?, - license: SPDXLicense?, - authors: { string }?, - repository: string?, - private: boolean?, - includes: { string }?, - pesde_version: string?, - workspace_members: { string }?, - target: PackageTarget, - build_files: { string }?, - scripts: { [string]: string }?, - indices: { [string]: string }, - wally_indices: { [string]: string }?, - overrides: { [string]: DependencySpecifier }?, - patches: { [string]: { [string]: string } }?, - place: { [string]: string }?, - dependencies: { [string]: DependencySpecifier }?, - peer_dependencies: { [string]: DependencySpecifier }?, - dev_dependencies: { [string]: DependencySpecifier }?, + name: string, + version: string, + description: string?, + license: SPDXLicense?, + authors: { string }?, + repository: string?, + private: boolean?, + includes: { string }?, + pesde_version: string?, + workspace_members: { string }?, + target: PackageTarget, + build_files: { string }?, + scripts: { [string]: string }?, + indices: { [string]: string }, + wally_indices: { [string]: string }?, + overrides: { [string]: DependencySpecifier }?, + patches: { [string]: { [string]: string } }?, + place: { [string]: string }?, + dependencies: { [string]: DependencySpecifier }?, + peer_dependencies: { [string]: DependencySpecifier }?, + dev_dependencies: { [string]: DependencySpecifier }?, } & T return function(path: string?, _phantom: T): PesdeManifest - local manifestContents = fs.readFile(path or "pesde.toml") - local decoded = serde.decode("toml", manifestContents) + local manifestContents = fs.readFile(path or "pesde.toml") + local decoded = serde.decode("toml", manifestContents) - return decoded :: PesdeManifest + return decoded :: PesdeManifest end diff --git a/.lune/tests/init.luau b/.lune/tests/init.luau index 054ad32..42de320 100644 --- a/.lune/tests/init.luau +++ b/.lune/tests/init.luau @@ -10,69 +10,71 @@ local reporter = require("./reporter") -- A more proper solution would be to use luau.load instead, but -- frktest requires its global state to be modified by test suites local require = require :: ( - path: string + path: string ) -> ( - test: typeof(setmetatable( - {} :: { - case: (name: string, fn: () -> nil) -> (), - suite: (name: string, fn: () -> ()) -> (), - }, - { __index = frktest.test } - )) + test: typeof(setmetatable( + {} :: { + case: (name: string, fn: () -> nil) -> (), + suite: (name: string, fn: () -> ()) -> (), + }, + { __index = frktest.test } + )) ) -> () local function discoverTests(dir: string) - local tests = {} - for _, file in fs.readDir(dir) do - local fullPath = `{dir}/{file}` + local tests = {} + for _, file in fs.readDir(dir) do + local fullPath = `{dir}/{file}` - -- Look for files ending in `.spec.luau` as tests - if fs.isFile(fullPath) and string.sub(file, -10) == ".spec.luau" then - table.insert(tests, fullPath) - end + -- Look for files ending in `.spec.luau` as tests + if fs.isFile(fullPath) and string.sub(file, -10) == ".spec.luau" then + table.insert(tests, fullPath) + end - -- Recurse for directories - if fs.isDir(fullPath) then - local moreTests = discoverTests(fullPath) + -- Recurse for directories + if fs.isDir(fullPath) then + local moreTests = discoverTests(fullPath) - -- Why are the indices starting at 0???? What???? - table.move(moreTests, 0, #moreTests, #tests, tests) - end - end + -- Why are the indices starting at 0???? What???? + table.move(moreTests, 0, #moreTests, #tests, tests) + end + end - return tests + return tests end local allowedTests = process.args for _, test in discoverTests("src") do - -- If we are given any arguments, we only run those tests, otherwise, - -- we run all the tests + -- If we are given any arguments, we only run those tests, otherwise, + -- we run all the tests - -- So, to include only a certain set of test files, you can provide either - -- the full path of the test file or name of the test file, with or without - -- the `.spec.luau` extension - local baseName = string.match(test, "([^/\\]+)$") + -- So, to include only a certain set of test files, you can provide either + -- the full path of the test file or name of the test file, with or without + -- the `.spec.luau` extension + local baseName = string.match(test, "([^/\\]+)$") - local withoutExt = string.sub(test, 1, -11) - local baseNameWithoutExt = string.match(withoutExt, "([^/\\]+)$") + local withoutExt = string.sub(test, 1, -11) + local baseNameWithoutExt = string.match(withoutExt, "([^/\\]+)$") - local isAllowed = #process.args == 0 - or table.find(allowedTests, test) - or table.find(allowedTests, withoutExt) - or table.find(allowedTests, baseName) - or table.find(allowedTests, baseNameWithoutExt) + local isAllowed = #process.args == 0 + or table.find(allowedTests, test) + or table.find(allowedTests, withoutExt) + or table.find(allowedTests, baseName) + or table.find(allowedTests, baseNameWithoutExt) - local constructors = { - case = frktest.test.case, - suite = frktest.test.suite, - } + local constructors = { + case = frktest.test.case, + suite = frktest.test.suite, + } - if not isAllowed then - constructors.case = frktest.test.skip.case - constructors.suite = frktest.test.skip.suite - end + if not isAllowed then + constructors.case = frktest.test.skip.case + constructors.suite = frktest.test.skip.suite + end - require(`../../{test}`)(setmetatable(constructors, { __index = frktest.test })) + require(`../../{test}`)( + setmetatable(constructors, { __index = frktest.test }) + ) end reporter.init() diff --git a/.lune/tests/reporter.luau b/.lune/tests/reporter.luau index ea4160f..ac0cd82 100644 --- a/.lune/tests/reporter.luau +++ b/.lune/tests/reporter.luau @@ -6,54 +6,64 @@ local Reporter = frktest._reporters.lune_console_reporter local watch = require("../lib/channel") local STYLE = table.freeze({ - suite = function(name: string) - return `{stdio.style("bold")}{stdio.color("purple")}SUITE{stdio.style("reset")} {name}` - end, + suite = function(name: string) + return `{stdio.style("bold")}{stdio.color("purple")}SUITE{stdio.style( + "reset" + )} {name}` + end, - report = function(name: string, state: "success" | "error" | "skip", elapsed: number) - local state_color: stdio.Color = if state == "success" - then "green" - elseif state == "error" then "red" - elseif state == "skip" then "yellow" - else error("Invalid test state") - return ` {stdio.style("bold")}{stdio.color(state_color)}{if state == "skip" then "SKIP" else "TEST"}{stdio.style( - "reset" - )} {name} [{stdio.style("dim")}{string.format("%.2fms", elapsed)}{stdio.style("reset")}]` - end, + report = function( + name: string, + state: "success" | "error" | "skip", + elapsed: number + ) + local state_color: stdio.Color = if state == "success" + then "green" + elseif state == "error" then "red" + elseif state == "skip" then "yellow" + else error("Invalid test state") + return ` {stdio.style("bold")}{stdio.color(state_color)}{if state + == "skip" + then "SKIP" + else "TEST"}{stdio.style("reset")} {name} [{stdio.style("dim")}{string.format( + "%.2fms", + elapsed + )}{stdio.style("reset")}]` + end, }) local ReporterExt = {} function ReporterExt.init() - frktest.test.on_suite_enter(function(suite) - print(STYLE.suite(suite.name)) - end) + frktest.test.on_suite_enter(function(suite) + print(STYLE.suite(suite.name)) + end) - frktest.test.on_suite_leave(function() - stdio.write("\n") - end) + frktest.test.on_suite_leave(function() + stdio.write("\n") + end) - local send_ts, recv_ts = watch((nil :: any) :: number) + local send_ts, recv_ts = watch((nil :: any) :: number) - frktest.test.on_test_enter(function() - -- Send over some high precision timestamp when the test starts - return send_ts(os.clock()) - end) + frktest.test.on_test_enter(function() + -- Send over some high precision timestamp when the test starts + return send_ts(os.clock()) + end) - frktest.test.on_test_leave(function(test) - print(STYLE.report( - test.name, - if test.failed then "error" else "success", + frktest.test.on_test_leave(function(test) + print(STYLE.report( + test.name, + if test.failed then "error" else "success", - -- Await receival of the timestamp and convert the difference to ms - (os.clock() - recv_ts()) * 1000 - )) - end) + -- Await receival of the timestamp and convert the difference to ms + (os.clock() - recv_ts()) * 1000 + )) + end) - frktest.test.on_test_skipped(function(test) - print(STYLE.report(test.name, "skip", 0)) - end) + frktest.test.on_test_skipped(function(test) + print(STYLE.report(test.name, "skip", 0)) + end) - Reporter.init() + Reporter.init() end return setmetatable(ReporterExt, { __index = Reporter }) diff --git a/.lune/typecheck.luau b/.lune/typecheck.luau index bb7a176..3ee89d9 100644 --- a/.lune/typecheck.luau +++ b/.lune/typecheck.luau @@ -5,12 +5,12 @@ local process = require("@lune/process") local CommandBuilder = require("./lib/exec") process.exit( - CommandBuilder.new("luau-lsp") - :withArg("analyze") - :withArgs({ "--settings", ".vscode/settings.json" }) - :withArgs({ "--ignore", "'**/.pesde/**'" }) - :withArgs({ "--ignore", "'./test-files/**'" }) - :withArg(".") - :withStdioStrategy("forward") - :exec().code + CommandBuilder.new("luau-lsp") + :withArg("analyze") + :withArgs({ "--settings", ".vscode/settings.json" }) + :withArgs({ "--ignore", "'**/.pesde/**'" }) + :withArgs({ "--ignore", "'./test-files/**'" }) + :withArg(".") + :withStdioStrategy("forward") + :exec().code ) diff --git a/src/generators/rojo/sourcemap.luau b/src/generators/rojo/sourcemap.luau index 4402d9f..7404cad 100644 --- a/src/generators/rojo/sourcemap.luau +++ b/src/generators/rojo/sourcemap.luau @@ -7,20 +7,24 @@ local PLATFORM_SEP = if process.os == "windows" then "\\" else "/" -- A mapping of things to do depending on the file present local PATH_ACTION_MAP: { [string]: (dir: string) -> number? } = { - ["default.project.json"] = function(dir) - return process.spawn("rojo", { "sourcemap", dir }, { - cwd = process.cwd, - env = process.env, - stdio = "forward", - }).code - end, + ["default.project.json"] = function(dir) + return process.spawn("rojo", { "sourcemap", dir }, { + cwd = process.cwd, + env = process.env, + stdio = "forward", + }).code + end, - ["init.lua"] = function() - return stdio.write(serde.encode("json", { filePaths = { "init.lua" } }, false)) - end, - ["init.luau"] = function() - return stdio.write(serde.encode("json", { filePaths = { "init.luau" } }, false)) - end, + ["init.lua"] = function() + return stdio.write( + serde.encode("json", { filePaths = { "init.lua" } }, false) + ) + end, + ["init.luau"] = function() + return stdio.write( + serde.encode("json", { filePaths = { "init.luau" } }, false) + ) + end, } --- Writes a Rojo sourcemap for the project in the provided directory or the current @@ -31,18 +35,18 @@ local PATH_ACTION_MAP: { [string]: (dir: string) -> number? } = { --- * Failure to spawn `rojo` command --- * Any I/O error occurs return function(packageDirectory: string?): boolean - packageDirectory = packageDirectory or process.cwd + packageDirectory = packageDirectory or process.cwd - -- We go through the action mappings in order of priority and check for the - -- file predicates, if present, we execute the action and report our status - for path, action in PATH_ACTION_MAP do - if fs.isFile(`{packageDirectory}{PLATFORM_SEP}{path}`) then - local status = action(packageDirectory) - return if status ~= nil then status == 0 else true - end - end + -- We go through the action mappings in order of priority and check for the + -- file predicates, if present, we execute the action and report our status + for path, action in PATH_ACTION_MAP do + if fs.isFile(`{packageDirectory}{PLATFORM_SEP}{path}`) then + local status = action(packageDirectory) + return if status ~= nil then status == 0 else true + end + end - -- If we reached so far, that must mean none of the file predicates matched, - -- so we return a `false` signifying an error - return false + -- If we reached so far, that must mean none of the file predicates matched, + -- so we return a `false` signifying an error + return false end diff --git a/src/generators/rojo/sourcemap.spec.luau b/src/generators/rojo/sourcemap.spec.luau index bc2bb5f..7f7b497 100644 --- a/src/generators/rojo/sourcemap.spec.luau +++ b/src/generators/rojo/sourcemap.spec.luau @@ -9,79 +9,98 @@ local check = frktest.assert.check local TEST_PROJECTS_DIR = "./test-files/rojo/test-projects" local TEST_PROJECT_EXCLUDES = { - "json_model", - "bad_json_model", - "plugins", - "legacy-0.5.x-unknown-names", + "json_model", + "bad_json_model", + "plugins", + "legacy-0.5.x-unknown-names", } local BUILTIN_PATCHES: { - [string]: { [string]: (...any) -> ...any? }, + [string]: { [string]: (...any) -> ...any? }, } = { - ["@lune/process"] = { - spawn = function(program: string, params: { string }, options: process.SpawnOptions): process.SpawnResult - local patchedOptions: process.SpawnOptions = options or {} - patchedOptions.stdio = "default" + ["@lune/process"] = { + spawn = function( + program: string, + params: { string }, + options: process.SpawnOptions + ): process.SpawnResult + local patchedOptions: process.SpawnOptions = options or {} + patchedOptions.stdio = "default" - local result = process.spawn(program, params, patchedOptions) + local result = process.spawn(program, params, patchedOptions) - -- First we make sure the command exited properly - assert(result.ok, `Expected \`rojo\` command to not error, got:\n{string.rep(" ", 6)}{result.stderr}`) + -- First we make sure the command exited properly + assert( + result.ok, + `Expected \`rojo\` command to not error, got:\n{string.rep( + " ", + 6 + )}{result.stderr}` + ) - -- We also make sure that the output JSON was valid - serde.decode("json", result.stdout) + -- We also make sure that the output JSON was valid + serde.decode("json", result.stdout) - return result - end, - }, + return result + end, + }, - ["@lune/stdio"] = { - write = function(msg: string) - -- Only make sure output JSON is valid - serde.decode("json", msg) - end, - }, + ["@lune/stdio"] = { + write = function(msg: string) + -- Only make sure output JSON is valid + serde.decode("json", msg) + end, + }, } local function requireWithPatches(path: string) - for builtin, patch in BUILTIN_PATCHES do - if path == builtin then - return setmetatable(patch, { __index = require(builtin) }) - end - end + for builtin, patch in BUILTIN_PATCHES do + if path == builtin then + return setmetatable(patch, { __index = require(builtin) }) + end + end - return require(path) + return require(path) end return function(test: typeof(frktest.test)) - test.suite("Generates Rojo sourcemaps for test projects successfully", function() - for _, file in fs.readDir(TEST_PROJECTS_DIR) do - if table.find(TEST_PROJECT_EXCLUDES, file) then - -- It does not make sense to test sourcemap generation for some of the test projects - continue - end + test.suite( + "Generates Rojo sourcemaps for test projects successfully", + function() + for _, file in fs.readDir(TEST_PROJECTS_DIR) do + if table.find(TEST_PROJECT_EXCLUDES, file) then + -- It does not make sense to test sourcemap generation for some of the test projects + continue + end - local testProject = `{TEST_PROJECTS_DIR}/{file}` - test.case(file, function() - -- If a file starts with `bad_` but not `bad_meta_`, we should expect a failure - -- Also, sorry about this shitty regex, regex-rs does not support look-around :( - local isBadMeta = regex.new("^bad_[^m]|^bad_m[^e]|^bad_me[^t]|^bad_met[^a]") - local expect = if isBadMeta:isMatch(file) then check.should_error else check.should_not_error + local testProject = `{TEST_PROJECTS_DIR}/{file}` + test.case(file, function() + -- If a file starts with `bad_` but not `bad_meta_`, we should expect a failure + -- Also, sorry about this shitty regex, regex-rs does not support look-around :( + local isBadMeta = regex.new( + "^bad_[^m]|^bad_m[^e]|^bad_me[^t]|^bad_met[^a]" + ) + local expect = if isBadMeta:isMatch(file) + then check.should_error + else check.should_not_error - expect(function() - -- We override the require which applies some patches to some builtins, mainly preventing - -- command stdout forwarding and `stdio.write` outputs to stdout in order to not fill - -- test ouput with large amounts of JSON data - local sourcemap: (string) -> boolean = - luau.load(fs.readFile("./src/generators/rojo/sourcemap.luau"), { - environment = { - require = requireWithPatches, - }, - })() + expect(function() + -- We override the require which applies some patches to some builtins, mainly preventing + -- command stdout forwarding and `stdio.write` outputs to stdout in order to not fill + -- test ouput with large amounts of JSON data + local sourcemap: (string) -> boolean = luau.load( + fs.readFile("./src/generators/rojo/sourcemap.luau"), + { + environment = { + require = requireWithPatches, + }, + } + )() - return check.is_true(sourcemap(testProject)) - end) - end) - end - end) + return check.is_true(sourcemap(testProject)) + end) + end) + end + end + ) end diff --git a/src/generators/rojo/sync_config.luau b/src/generators/rojo/sync_config.luau index 7b06134..2048bba 100644 --- a/src/generators/rojo/sync_config.luau +++ b/src/generators/rojo/sync_config.luau @@ -3,49 +3,49 @@ local process = require("@lune/process") local serde = require("@lune/serde") export type TreeProperties = { - Name: never?, - Parent: never?, + Name: never?, + Parent: never?, } export type TreeBase = { - ["$className"]: string?, - ["$ignoreUnknownInstances"]: boolean?, - ["$path"]: string | { optional: string }?, - ["$properties"]: TreeProperties?, + ["$className"]: string?, + ["$ignoreUnknownInstances"]: boolean?, + ["$path"]: string | { optional: string }?, + ["$properties"]: TreeProperties?, } export type TreeNormal = TreeBase & { - [string]: TreeNormal, + [string]: TreeNormal, } & ({ ["$className"]: string } | { - ["$path"]: string | { optional: string }, + ["$path"]: string | { optional: string }, }) export type TreeService = TreeBase & { - [string]: TreeNormal, + [string]: TreeNormal, } export type DataModelTree = TreeBase & { - StarterPlayer: (TreeBase & { - StarterPlayerScripts: TreeService?, - StarterCharacterScripts: TreeService?, - [string]: TreeNormal, - })?, - [string]: TreeService, + StarterPlayer: (TreeBase & { + StarterPlayerScripts: TreeService?, + StarterCharacterScripts: TreeService?, + [string]: TreeNormal, + })?, + [string]: TreeService, } export type Tree = (DataModelTree & { - ["$className"]: "DataModel", + ["$className"]: "DataModel", }) | TreeNormal export type SyncConfig = { - name: string, - servePort: number?, - servePlaceIds: { number }?, - placeId: number?, - gameId: number?, - serveAddress: string?, - globIgnorePaths: { string }?, - tree: Tree, + name: string, + servePort: number?, + servePlaceIds: { number }?, + placeId: number?, + gameId: number?, + serveAddress: string?, + globIgnorePaths: { string }?, + tree: Tree, } local PLATFORM_SEP = if process.os == "windows" then "\\" else "/" @@ -57,57 +57,59 @@ local PLATFORM_SEP = if process.os == "windows" then "\\" else "/" --- * The current process lacks permissions to a file --- * Any I/O error occurs return function( - packageDirectory: string?, - files: { string }, - options: { - writeToFile: boolean?, - force: boolean?, - } + packageDirectory: string?, + files: { string }, + options: { + writeToFile: boolean?, + force: boolean?, + } ): (boolean, string?) - packageDirectory = packageDirectory or process.cwd - local syncConfigPath = `{packageDirectory}{PLATFORM_SEP}default.project.json` - if fs.isFile(syncConfigPath) and not options.force then - return true, nil - end + packageDirectory = packageDirectory or process.cwd + local syncConfigPath = + `{packageDirectory}{PLATFORM_SEP}default.project.json` + if fs.isFile(syncConfigPath) and not options.force then + return true, nil + end - local syncConfigTree = {} :: Tree + local syncConfigTree = {} :: Tree - for _, file in files do - -- Remove the `.lua` or `.luau` file extension from the file name - local name = string.gsub(file, ".luau?$", "") + for _, file in files do + -- Remove the `.lua` or `.luau` file extension from the file name + local name = string.gsub(file, ".luau?$", "") - if name == "init" then - syncConfigTree["$path"] = name - continue - end + if name == "init" then + syncConfigTree["$path"] = name + continue + end - syncConfigTree[name] = { - ["$path"] = file, - } - end + syncConfigTree[name] = { + ["$path"] = file, + } + end - -- If there isn't a top level path, we mark the entire thing as a Folder - if not syncConfigTree["$path"] then - syncConfigTree["$className"] = "Folder" - end + -- If there isn't a top level path, we mark the entire thing as a Folder + if not syncConfigTree["$path"] then + syncConfigTree["$className"] = "Folder" + end - -- If the config tree does not include pesde's downloaded roblox dependencies - -- directory, we add it as an optional one for the future, once dependencies - -- are installed - if not syncConfigTree["roblox_packages"] then - syncConfigTree["roblox_packages"] = { - ["$path"] = { - optional = "roblox_packages", - }, - } - end + -- If the config tree does not include pesde's downloaded roblox dependencies + -- directory, we add it as an optional one for the future, once dependencies + -- are installed + if not syncConfigTree["roblox_packages"] then + syncConfigTree["roblox_packages"] = { + ["$path"] = { + optional = "roblox_packages", + }, + } + end - -- Finally, we serialize the config to a JSON string and optionally write it - -- to the sync config path - local serializedConfig = serde.encode("json", { tree = syncConfigTree }, true) - if options.writeToFile then - fs.writeFile(syncConfigPath, serializedConfig) - end + -- Finally, we serialize the config to a JSON string and optionally write it + -- to the sync config path + local serializedConfig = + serde.encode("json", { tree = syncConfigTree }, true) + if options.writeToFile then + fs.writeFile(syncConfigPath, serializedConfig) + end - return true, serializedConfig + return true, serializedConfig end diff --git a/src/generators/rojo/sync_config.spec.luau b/src/generators/rojo/sync_config.spec.luau index 02a5844..014d247 100644 --- a/src/generators/rojo/sync_config.spec.luau +++ b/src/generators/rojo/sync_config.spec.luau @@ -7,27 +7,34 @@ local check = frktest.assert.check local syncConfig = require("./sync_config") local TEST_PROJECTS_DIRS = { - "./test-files/rojo/test-projects", - "./test-files/rojo/rojo-test/serve-tests", + "./test-files/rojo/test-projects", + "./test-files/rojo/rojo-test/serve-tests", } return function(test: typeof(frktest.test)) - test.suite("Generates Rojo valid sync configs", function() - for _, dir in TEST_PROJECTS_DIRS do - for _, file in fs.readDir(dir) do - local fullPath = `{dir}/{file}` - test.case(`{file}`, function() - local ok, config = syncConfig(fullPath, fs.readDir(fullPath), { writeToFile = false, force = true }) - check.is_true(ok) + test.suite("Generates Rojo valid sync configs", function() + for _, dir in TEST_PROJECTS_DIRS do + for _, file in fs.readDir(dir) do + local fullPath = `{dir}/{file}` + test.case(`{file}`, function() + local ok, config = syncConfig( + fullPath, + fs.readDir(fullPath), + { writeToFile = false, force = true } + ) + check.is_true(ok) - -- Make sure that the generated config and the real configs are similar - local generatedConfig, realConfig = - serde.decode("json", config), - serde.decode("json", fs.readFile(`{fullPath}/default.project.json`)) + -- Make sure that the generated config and the real configs are similar + local generatedConfig, realConfig = + serde.decode("json", config), + serde.decode( + "json", + fs.readFile(`{fullPath}/default.project.json`) + ) - check.table.contains(realConfig, generatedConfig) - end) - end - end - end) + check.table.contains(realConfig, generatedConfig) + end) + end + end + end) end diff --git a/src/init.luau b/src/init.luau index cf48aa9..f0d77f3 100644 --- a/src/init.luau +++ b/src/init.luau @@ -1,8 +1,8 @@ return { - generators = { - rojo = { - sourcemap = require("./generators/rojo/sourcemap"), - syncConfig = require("./generators/rojo/sync_config"), - }, - }, + generators = { + rojo = { + sourcemap = require("./generators/rojo/sourcemap"), + syncConfig = require("./generators/rojo/sync_config"), + }, + }, }