From d2c41e0d03a934df62211fb80a3b460c0ef697f8 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Wed, 18 Dec 2024 12:32:16 +0000 Subject: [PATCH] feat: include argon core logic in library * Include sourcemap, and sync config generators for Argon as a sync tool. * Add tests for aforementioned Argon generators. * Refactor and fix test discovery logic in test runner script. * Temporarily unpin fixed pesde version. --- .gitmodules | 3 + .lune/tests/init.luau | 25 +++--- pesde.lock | 56 ++++++++++++ pesde.toml | 4 +- src/generators/argon/sourcemap.luau | 52 +++++++++++ src/generators/argon/sourcemap.spec.luau | 100 +++++++++++++++++++++ src/generators/argon/sync_config.luau | 28 ++++++ src/generators/argon/sync_config.spec.luau | 39 ++++++++ test-files/argon | 1 + 9 files changed, 297 insertions(+), 11 deletions(-) create mode 100644 src/generators/argon/sourcemap.luau create mode 100644 src/generators/argon/sourcemap.spec.luau create mode 100644 src/generators/argon/sync_config.luau create mode 100644 src/generators/argon/sync_config.spec.luau create mode 160000 test-files/argon diff --git a/.gitmodules b/.gitmodules index d382b7a..e300662 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "test-files/rojo"] path = test-files/rojo url = https://github.com/rojo-rbx/rojo.git +[submodule "test-files/argon"] + path = test-files/argon + url = https://github.com/argon-rbx/examples.git diff --git a/.lune/tests/init.luau b/.lune/tests/init.luau index 42de320..f54907a 100644 --- a/.lune/tests/init.luau +++ b/.lune/tests/init.luau @@ -21,28 +21,33 @@ local require = require :: ( )) ) -> () -local function discoverTests(dir: string) + +local function discoverTests(dir: string): { string } local tests = {} - for _, file in fs.readDir(dir) do - local fullPath = `{dir}/{file}` + + local entries = fs.readDir(dir) + for _, entry in entries do + local path = `{dir}/{entry}` -- 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) + if fs.isFile(path) and string.match(entry, "%.spec%.luau$") then + table.insert(tests, path) + continue end -- 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) + if fs.isDir(path) then + local dirResults = discoverTests(path) + table.move(dirResults, 1, #dirResults, #tests + 1, tests) + continue end end return tests end +print(discoverTests("src")) + local allowedTests = process.args for _, test in discoverTests("src") do -- If we are given any arguments, we only run those tests, otherwise, diff --git a/pesde.lock b/pesde.lock index aa705e2..cca4e5c 100644 --- a/pesde.lock +++ b/pesde.lock @@ -161,6 +161,34 @@ index_url = "https://github.com/daimond113/pesde-index" environment = "luau" lib = "lib/init.luau" +[graph."pesde/argon"."2.0.21 lune"] +direct = ["argon", { name = "pesde/argon", version = "^2.0.21" }, "dev"] +resolved_ty = "dev" + +[graph."pesde/argon"."2.0.21 lune".target] +environment = "lune" +bin = "init.luau" + +[graph."pesde/argon"."2.0.21 lune".dependencies] +"lukadev_0/option" = ["1.2.0 lune", "option"] +"lukadev_0/result" = ["1.2.0 lune", "result"] +"pesde/toolchainlib" = ["0.1.2 lune", "core"] + +[graph."pesde/argon"."2.0.21 lune".pkg_ref] +ref_ty = "pesde" +name = "pesde/argon" +version = "2.0.21" +index_url = "https://github.com/pesde-pkg/index" + +[graph."pesde/argon"."2.0.21 lune".pkg_ref.dependencies] +core = [{ name = "pesde/toolchainlib", version = "^0.1.2", index = "https://github.com/daimond113/pesde-index", target = "lune" }, "standard"] +option = [{ name = "lukadev_0/option", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "standard"] +result = [{ name = "lukadev_0/result", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "standard"] + +[graph."pesde/argon"."2.0.21 lune".pkg_ref.target] +environment = "lune" +bin = "init.luau" + [graph."pesde/luau_lsp"."1.36.0 lune"] direct = ["luau-lsp", { name = "pesde/luau_lsp", version = "^1.36.0" }, "dev"] resolved_ty = "dev" @@ -189,6 +217,34 @@ result = [{ name = "lukadev_0/result", version = "^1.2.0", index = "https://gith environment = "lune" bin = "init.luau" +[graph."pesde/rojo"."7.4.4 lune"] +direct = ["rojo", { name = "pesde/rojo", version = "^7.4.4" }, "dev"] +resolved_ty = "dev" + +[graph."pesde/rojo"."7.4.4 lune".target] +environment = "lune" +bin = "init.luau" + +[graph."pesde/rojo"."7.4.4 lune".dependencies] +"lukadev_0/option" = ["1.2.0 lune", "option"] +"lukadev_0/result" = ["1.2.0 lune", "result"] +"pesde/toolchainlib" = ["0.1.2 lune", "core"] + +[graph."pesde/rojo"."7.4.4 lune".pkg_ref] +ref_ty = "pesde" +name = "pesde/rojo" +version = "7.4.4" +index_url = "https://github.com/pesde-pkg/index" + +[graph."pesde/rojo"."7.4.4 lune".pkg_ref.dependencies] +core = [{ name = "pesde/toolchainlib", version = "^0.1.1", index = "https://github.com/daimond113/pesde-index", target = "lune" }, "standard"] +option = [{ name = "lukadev_0/option", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "standard"] +result = [{ name = "lukadev_0/result", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "standard"] + +[graph."pesde/rojo"."7.4.4 lune".pkg_ref.target] +environment = "lune" +bin = "init.luau" + [graph."pesde/stylua"."2.0.1 lune"] direct = ["stylua", { name = "pesde/stylua", version = "^2.0.1" }, "dev"] resolved_ty = "dev" diff --git a/pesde.toml b/pesde.toml index a8fa938..7a48a17 100644 --- a/pesde.toml +++ b/pesde.toml @@ -1,6 +1,6 @@ name = "pesde/scripts_core" version = "0.0.1" -pesde_version = "0.5.0-rc.16" +# pesde_version = "0.5.1+registry.0.1.0" # FIXME: pesde needs to fix versioning here description = "Scripts and other utilities for use with pesde" authors = [ "daimond113 (https://www.daimond113.com/)", @@ -31,6 +31,8 @@ frktest = { name = "itsfrank/frktest", version = "^0.0.2" } pathfs = { name = "jiwonz/pathfs", version = "^0.1.0" } luau-lsp = { name = "pesde/luau_lsp", version = "^1.36.0" } stylua = { name = "pesde/stylua", version = "^2.0.1" } +argon = { name = "pesde/argon", version = "^2.0.21" } +rojo = { name = "pesde/rojo", version = "^7.4.4" } [indices] default = "https://github.com/pesde-pkg/index" diff --git a/src/generators/argon/sourcemap.luau b/src/generators/argon/sourcemap.luau new file mode 100644 index 0000000..ea21565 --- /dev/null +++ b/src/generators/argon/sourcemap.luau @@ -0,0 +1,52 @@ +local fs = require("@lune/fs") +local process = require("@lune/process") +local serde = require("@lune/serde") +local stdio = require("@lune/stdio") + +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("argon", { "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, +} + +--- Writes a Argon sourcemap for the project in the provided directory or the current +--- working directory to standard output. + +--- ## Errors +--- * The current process lacks permissions to a file +--- * Failure to spawn `argon` command +--- * Any I/O error occurs +return function(packageDirectory: string?): boolean + 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 + + -- 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/argon/sourcemap.spec.luau b/src/generators/argon/sourcemap.spec.luau new file mode 100644 index 0000000..e40c622 --- /dev/null +++ b/src/generators/argon/sourcemap.spec.luau @@ -0,0 +1,100 @@ +local fs = require("@lune/fs") +local luau = require("@lune/luau") +local process = require("@lune/process") +local regex = require("@lune/regex") +local serde = require("@lune/serde") + +local frktest = require("../../../lune_packages/frktest") +local check = frktest.assert.check + +local TEST_PROJECTS_DIR = "./test-files/argon" + +local BUILTIN_PATCHES: { + [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" + + 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}` + ) + + -- We also make sure that the output JSON was valid + serde.decode("json", result.stdout) + + return result + 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 + + return require(path) +end + +return function(test: typeof(frktest.test)) + test.suite( + "Generates Argon sourcemaps for test projects successfully", + function() + for _, file in fs.readDir(TEST_PROJECTS_DIR) do + local testProject = `{TEST_PROJECTS_DIR}/{file}` + if not fs.isDir(testProject) or file == ".git" then + -- Skip files that are not project directories + continue + end + + 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/argon/sourcemap.luau"), + { + environment = { + require = requireWithPatches, + }, + } + )() + + return check.is_true(sourcemap(testProject)) + end) + end) + end + end + ) +end diff --git a/src/generators/argon/sync_config.luau b/src/generators/argon/sync_config.luau new file mode 100644 index 0000000..f040c46 --- /dev/null +++ b/src/generators/argon/sync_config.luau @@ -0,0 +1,28 @@ +local rojoSyncConfig = require("../rojo/sync_config") + +export type TreeProperties = rojoSyncConfig.TreeProperties +export type TreeBase = rojoSyncConfig.TreeBase +export type TreeNormal = rojoSyncConfig.TreeNormal +export type TreeService = rojoSyncConfig.TreeService +export type DataModelTree = rojoSyncConfig.DataModelTree +export type Tree = rojoSyncConfig.Tree +export type SyncConfig = rojoSyncConfig.SyncConfig + +--- Generates an Argon sync configuration file (`default.project.json`) from a list of +--- input files to be included. + +--- ## Errors +--- * The current process lacks permissions to a file +--- * Any I/O error occurs +return function( + packageDirectory: string?, + files: { string }, + options: { + writeToFile: boolean?, + force: boolean?, + } +): (boolean, string?) + -- Purely alias to the Rojo sync config generator, since Argon uses the same + -- config format + return rojoSyncConfig(packageDirectory, files, options) +end diff --git a/src/generators/argon/sync_config.spec.luau b/src/generators/argon/sync_config.spec.luau new file mode 100644 index 0000000..5726272 --- /dev/null +++ b/src/generators/argon/sync_config.spec.luau @@ -0,0 +1,39 @@ +local fs = require("@lune/fs") +local serde = require("@lune/serde") + +local frktest = require("../../../lune_packages/frktest") +local check = frktest.assert.check + +local syncConfig = require("./sync_config") + +local TEST_PROJECTS_DIR = "./test-files/argon" + +return function(test: typeof(frktest.test)) + test.suite("Generates valid Argon sync configs", function() + for _, dir in fs.readDir(TEST_PROJECTS_DIR) do + local fullPath = `{TEST_PROJECTS_DIR}/{dir}` + if not fs.isDir(fullPath) or dir == ".git" then + continue + end + + test.case(`{dir}`, 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`) + ) + + check.table.contains(realConfig, generatedConfig) + end) + end + end) +end diff --git a/test-files/argon b/test-files/argon new file mode 160000 index 0000000..9c092f0 --- /dev/null +++ b/test-files/argon @@ -0,0 +1 @@ +Subproject commit 9c092f06420d9068bb312c3547dcc3f2f19f2cc4