diff --git a/.lune/roblox_sync_config_generator.luau b/.lune/roblox_sync_config_generator.luau new file mode 100644 index 0000000..a233ae0 --- /dev/null +++ b/.lune/roblox_sync_config_generator.luau @@ -0,0 +1,19 @@ +local function enter(fn: (args: { string }) -> number?): never + local process = require("@lune/process") + local stdio = require("@lune/stdio") + + local startTime = os.clock() + local exitCode = fn(table.clone(process.args)) + + stdio.write( + `done in {stdio.style("dim")}{string.format("%.2fs", os.clock() - startTime)}{stdio.style("reset")}!\n` + ) + + return process.exit(exitCode) +end + +return enter(function(args: { string }): number? + local ok, _ = require("../src").generators.rojo.syncConfig(table.remove(args, 1), args, true) + + return tonumber(ok) +end) diff --git a/.lune/sourcemap_generator.luau b/.lune/sourcemap_generator.luau new file mode 100644 index 0000000..2037a13 --- /dev/null +++ b/.lune/sourcemap_generator.luau @@ -0,0 +1,19 @@ +local function enter(fn: (args: { string }) -> number?): never + local process = require("@lune/process") + local stdio = require("@lune/stdio") + + local startTime = os.clock() + local exitCode = fn(table.clone(process.args)) + + stdio.ewrite( + `\ndone in {stdio.style("dim")}{string.format("%.2fs", os.clock() - startTime)}{stdio.style("reset")}!\n` + ) + + return process.exit(exitCode) +end + +return enter(function(args: { string }): number? + return tonumber(require("../src").generators.rojo.sourcemap( + args[1] + )) +end) \ No newline at end of file diff --git a/lune/rojo/roblox_sync_config_generator.luau b/lune/rojo/roblox_sync_config_generator.luau deleted file mode 100644 index 3631255..0000000 --- a/lune/rojo/roblox_sync_config_generator.luau +++ /dev/null @@ -1,44 +0,0 @@ -local fs = require("@lune/fs") -local process = require("@lune/process") -local serde = require("@lune/serde") - -local package_directory = process.args[1] - -if fs.isFile(package_directory .. "/default.project.json") then - return -end - -local output = { - tree = {}, -} - -for i, file in process.args do - if i == 1 then - continue - end - - local name = string.gsub(file, ".luau?$", "") - - if name == "init" then - output.tree["$path"] = file - continue - end - - output.tree[name] = { - ["$path"] = file, - } -end - -if not output.tree["$path"] then - output.tree["$className"] = "Folder" -end - -if not output.tree["roblox_packages"] then - output.tree["roblox_packages"] = { - ["$path"] = { - optional = "roblox_packages", - }, - } -end - -fs.writeFile(package_directory .. "/default.project.json", serde.encode("json", output, true)) diff --git a/lune/rojo/sourcemap_generator.luau b/lune/rojo/sourcemap_generator.luau deleted file mode 100644 index 4cf09cd..0000000 --- a/lune/rojo/sourcemap_generator.luau +++ /dev/null @@ -1,19 +0,0 @@ -local fs = require("@lune/fs") -local process = require("@lune/process") -local serde = require("@lune/serde") -local stdio = require("@lune/stdio") - -local package_directory = process.args[1] - -if fs.isFile(package_directory .. "/default.project.json") then - process.spawn("rojo", { "sourcemap", package_directory }, { cwd = process.cwd, stdio = "forward" }) -elseif fs.isFile(package_directory .. "/init.luau") then - local sourcemap = { filePaths = { "init.luau" } } - stdio.write(serde.encode("json", sourcemap, false)) -elseif fs.isFile(package_directory .. "/init.lua") then - local sourcemap = { filePaths = { "init.lua" } } - stdio.write(serde.encode("json", sourcemap, false)) -else - -- use stderr to avoid this being parsed as the output of the sourcemap command - stdio.ewrite("no default.project.json found in " .. package_directory) -end diff --git a/pesde.toml b/pesde.toml index ea575e1..d8d6917 100644 --- a/pesde.toml +++ b/pesde.toml @@ -1,12 +1,15 @@ name = "pesde/scripts" version = "0.1.0" +pesde_version = "0.5.0-rc.14" description = "Scripts and other utilities for use with pesde" authors = ["dai (https://www.daimond113.com/)", "Erica Marigold "] repository = "https://github.com/pesde-pkg/scripts" license = "MIT" +includes = ["src/**/*.luau"] [target] environment = "lune" +lib = "src/init.luau" [indices] default = "https://github.com/daimond113/pesde-index" diff --git a/src/generators/rojo/sourcemap.luau b/src/generators/rojo/sourcemap.luau new file mode 100644 index 0000000..d451b24 --- /dev/null +++ b/src/generators/rojo/sourcemap.luau @@ -0,0 +1,43 @@ +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 "/" + +--- Writes a Rojo 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 +--- * Any I/O error occurs +return function(packageDirectory: string?): boolean + packageDirectory = packageDirectory or process.cwd + + -- 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, + + ["init.lua"] = stdio.write(serde.encode("json", { filePaths = { "init.lua" } }, false)), + ["init.luau"] = stdio.write(serde.encode("json", { filePaths = { "init.luau" } }, false)), + } + + -- 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() + 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/rojo/sync_config.luau b/src/generators/rojo/sync_config.luau new file mode 100644 index 0000000..5318724 --- /dev/null +++ b/src/generators/rojo/sync_config.luau @@ -0,0 +1,104 @@ +local fs = require("@lune/fs") +local process = require("@lune/process") +local serde = require("@lune/serde") + +export type TreeProperties = { + Name: never?, + Parent: never?, +} + +export type TreeBase = { + ["$className"]: string?, + ["$ignoreUnknownInstances"]: boolean?, + ["$path"]: string | { optional: string }?, + ["$properties"]: TreeProperties?, +} + +export type TreeNormal = TreeBase & { + [string]: TreeNormal, +} & ({ ["$className"]: string } | { ["$path"]: string | { optional: string } }) + +export type TreeService = TreeBase & { + [string]: TreeNormal, +} + +export type DataModelTree = TreeBase & { + StarterPlayer: (TreeBase & { + StarterPlayerScripts: TreeService?, + StarterCharacterScripts: TreeService?, + [string]: TreeNormal, + })?, + [string]: TreeService, +} + +export type Tree = (DataModelTree & { + ["$className"]: "DataModel", +}) | TreeNormal + +export type SyncConfig = { + 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 "/" + +--- Generates a Rojo 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 }, writeToFile: boolean?): (boolean, string?) + packageDirectory = packageDirectory or process.cwd + local syncConfigPath = `{packageDirectory}{PLATFORM_SEP}default.project.json` + if fs.isFile(syncConfigPath) then + return true, nil + end + + 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?$", "") + + if name == "init" then + syncConfigTree["$path"] = name + continue + 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 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 writeToFile then + fs.writeFile(syncConfigPath, serializedConfig) + end + + return true, serializedConfig +end diff --git a/src/init.luau b/src/init.luau new file mode 100644 index 0000000..a9ff34a --- /dev/null +++ b/src/init.luau @@ -0,0 +1,8 @@ +return { + generators = { + rojo = { + sourcemap = require("./generators/rojo/sourcemap"), + syncConfig = require("./generators/rojo/sync_config"), + }, + }, +}