mirror of
https://github.com/pesde-pkg/scripts.git
synced 2025-01-05 19:29:08 +00:00
refactor: use package project structure (#3)
This commit is contained in:
commit
98b5b554f8
27 changed files with 1354 additions and 66 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Pesde packages
|
||||||
|
*_packages/
|
||||||
|
pesde.lock
|
||||||
|
|
||||||
|
# Generated scripts
|
||||||
|
.pesde/*
|
||||||
|
!.pesde/.gitkeep
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "test-files/rojo"]
|
||||||
|
path = test-files/rojo
|
||||||
|
url = https://github.com/rojo-rbx/rojo.git
|
7
.luaurc
Normal file
7
.luaurc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"languageMode": "nonstrict",
|
||||||
|
"lint": {
|
||||||
|
"*": true,
|
||||||
|
"TableOperations": false
|
||||||
|
}
|
||||||
|
}
|
225
.lune/build.luau
Normal file
225
.lune/build.luau
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
--> Generates sync config and sourcemap scripts for supported tools
|
||||||
|
|
||||||
|
local process = require("@lune/process")
|
||||||
|
local serde = require("@lune/serde")
|
||||||
|
local stdio = require("@lune/stdio")
|
||||||
|
local task = require("@lune/task")
|
||||||
|
|
||||||
|
local lib = require("../src")
|
||||||
|
local manifest = require("./lib/manifest")
|
||||||
|
local pathfs = require("../lune_packages/pathfs")
|
||||||
|
|
||||||
|
type ToolChoice = "rojo"
|
||||||
|
type ManifestExt = {
|
||||||
|
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")
|
||||||
|
|
||||||
|
local args = table.clone(process.args)
|
||||||
|
local ok, _ =
|
||||||
|
require("./lune_packages/core").generators.%s.syncConfig(table.remove(args, 1), args, { writeToFile = true })
|
||||||
|
if not ok then
|
||||||
|
return process.exit(1)
|
||||||
|
end]],
|
||||||
|
|
||||||
|
sourcemapGenerator = [[local process = require("@lune/process")
|
||||||
|
|
||||||
|
local ok = require("./lune_packages/core").generators.%s.sourcemap(process.args[1])
|
||||||
|
if not ok then
|
||||||
|
return process.exit(1)
|
||||||
|
end
|
||||||
|
]],
|
||||||
|
}
|
||||||
|
|
||||||
|
local README_TMPL = [[# `pesde/scripts_%s`
|
||||||
|
Common scripts intended for use with %s.
|
||||||
|
|
||||||
|
## Included scripts
|
||||||
|
### roblox_sync_config_generator
|
||||||
|
|
||||||
|
Generates a %s sync config for pesde Roblox packages.
|
||||||
|
|
||||||
|
### sourcemap_generator
|
||||||
|
|
||||||
|
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}`)
|
||||||
|
|
||||||
|
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 =
|
||||||
|
{ "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
-- 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",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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`
|
||||||
|
)
|
||||||
|
|
||||||
|
return child.code
|
||||||
|
end
|
||||||
|
|
||||||
|
for tool, generators in lib.generators do
|
||||||
|
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]
|
||||||
|
|
||||||
|
if not pathfs.isDir(toolScriptsDir) then
|
||||||
|
pathfs.writeDir(toolScriptsDir)
|
||||||
|
end
|
||||||
|
|
||||||
|
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 <contact@daimond113.com> (https://www.daimond113.com/)",
|
||||||
|
"Erica Marigold <hi@devcomp.xyz>",
|
||||||
|
},
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
peer_dependencies = toolMeta.tool_dependencies,
|
||||||
|
dependencies = {
|
||||||
|
core = { workspace = "pesde/scripts_core", version = "^" },
|
||||||
|
},
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- 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`
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Now we install the dependencies for the newly created projects
|
||||||
|
process.exit(installDeps())
|
13
.lune/fmt.luau
Normal file
13
.lune/fmt.luau
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
--> Run stylua to check for formatting errors
|
||||||
|
|
||||||
|
local process = require("@lune/process")
|
||||||
|
|
||||||
|
local CommandBuilder = require("./lib/exec")
|
||||||
|
|
||||||
|
process.exit(
|
||||||
|
CommandBuilder.new("stylua")
|
||||||
|
:withArg(".")
|
||||||
|
:withArgs(process.args)
|
||||||
|
:withStdioStrategy("forward")
|
||||||
|
:exec().code
|
||||||
|
)
|
48
.lune/lib/channel.luau
Normal file
48
.lune/lib/channel.luau
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
--- An MPSC synchronization primitive powered by Lua upvalues which retains only
|
||||||
|
--- one value at a time.
|
||||||
|
|
||||||
|
--- ## Usage
|
||||||
|
--- ```luau
|
||||||
|
--- local send, recv = watch((nil :: any) :: string)
|
||||||
|
--- task.delay(5, send, "hello, world!")
|
||||||
|
--- task.spawn(function()
|
||||||
|
--- local value = recv()
|
||||||
|
--- print("received value:", value)
|
||||||
|
--- end)
|
||||||
|
--- ```
|
||||||
|
type Watch<T> = {
|
||||||
|
value: T?,
|
||||||
|
receivers: { thread },
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Creates a new `Watch` channel, returning its send and receive handles.
|
||||||
|
local function chan<T>(_phantom: T): ((T) -> (), () -> T?)
|
||||||
|
local watch: Watch<T> = {
|
||||||
|
value = nil,
|
||||||
|
receivers = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
local function send(value: T)
|
||||||
|
watch.value = value
|
||||||
|
|
||||||
|
for _, receiver in watch.receivers do
|
||||||
|
coroutine.resume(receiver, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
return value :: T
|
||||||
|
end
|
||||||
|
|
||||||
|
return send, recv
|
||||||
|
end
|
||||||
|
|
||||||
|
return chan
|
123
.lune/lib/exec.luau
Normal file
123
.lune/lib/exec.luau
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
--> lib: Builder pattern class to spawn child processes
|
||||||
|
|
||||||
|
local process = require("@lune/process")
|
||||||
|
local stdio = require("@lune/stdio")
|
||||||
|
|
||||||
|
local CommandBuilder = {}
|
||||||
|
|
||||||
|
export type CommandBuilder = typeof(setmetatable(
|
||||||
|
{} :: CommandBuilderFields,
|
||||||
|
{ __index = CommandBuilder }
|
||||||
|
))
|
||||||
|
type CommandBuilderFields = {
|
||||||
|
program: string,
|
||||||
|
args: { string },
|
||||||
|
stdioStrategy: IoStrategyMapping?,
|
||||||
|
}
|
||||||
|
export type StdioStrategy = "pipe" | "forward" | "none"
|
||||||
|
export type IoStrategyMapping = {
|
||||||
|
stdout: StdioStrategy?,
|
||||||
|
stderr: StdioStrategy?,
|
||||||
|
}
|
||||||
|
|
||||||
|
local DEFAULT_STDIO_STRATEGY: IoStrategyMapping = {
|
||||||
|
stdout = "pipe",
|
||||||
|
stderr = "pipe",
|
||||||
|
}
|
||||||
|
function CommandBuilder.new(program: string)
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
function CommandBuilder.withArgs(
|
||||||
|
self: CommandBuilder,
|
||||||
|
args: { string }
|
||||||
|
): CommandBuilder
|
||||||
|
for _, arg in args do
|
||||||
|
self:withArg(arg)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function CommandBuilder.withStdioStrategy(
|
||||||
|
self: CommandBuilder,
|
||||||
|
strategy: StdioStrategy | IoStrategyMapping
|
||||||
|
): CommandBuilder
|
||||||
|
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
|
||||||
|
|
||||||
|
if strategy == "forward" then
|
||||||
|
return "forward"
|
||||||
|
end
|
||||||
|
|
||||||
|
if strategy == "none" then
|
||||||
|
return "none"
|
||||||
|
end
|
||||||
|
|
||||||
|
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")
|
||||||
|
)
|
||||||
|
|
||||||
|
local function translateIoStrategyMappings(mappings: IoStrategyMapping)
|
||||||
|
local translatedMappings: process.SpawnOptionsStdio = {}
|
||||||
|
for field, value in mappings do
|
||||||
|
translatedMappings[field] = intoSpawnOptionsStdioKind(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
return translatedMappings
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
return child
|
||||||
|
end
|
||||||
|
|
||||||
|
return CommandBuilder
|
80
.lune/lib/manifest.luau
Normal file
80
.lune/lib/manifest.luau
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
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"
|
||||||
|
|
||||||
|
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: "luau" | "lune",
|
||||||
|
lib: string,
|
||||||
|
bin: string,
|
||||||
|
scripts: { [string]: string },
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PesdeManifest<T = {}> = {
|
||||||
|
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<T>(path: string?, _phantom: T): PesdeManifest<T>
|
||||||
|
local manifestContents = fs.readFile(path or "pesde.toml")
|
||||||
|
local decoded = serde.decode("toml", manifestContents)
|
||||||
|
|
||||||
|
return decoded :: PesdeManifest<T>
|
||||||
|
end
|
81
.lune/tests/init.luau
Normal file
81
.lune/tests/init.luau
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
--> Run tests using frktest runner
|
||||||
|
|
||||||
|
local fs = require("@lune/fs")
|
||||||
|
local process = require("@lune/process")
|
||||||
|
|
||||||
|
local frktest = require("../../lune_packages/frktest")
|
||||||
|
local reporter = require("./reporter")
|
||||||
|
|
||||||
|
-- HACK: Cast require to allow for dynamic paths in strict mode
|
||||||
|
-- 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
|
||||||
|
) -> (
|
||||||
|
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}`
|
||||||
|
|
||||||
|
-- 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)
|
||||||
|
|
||||||
|
-- Why are the indices starting at 0???? What????
|
||||||
|
table.move(moreTests, 0, #moreTests, #tests, tests)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-- 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 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
if not isAllowed then
|
||||||
|
constructors.case = frktest.test.skip.case
|
||||||
|
constructors.suite = frktest.test.skip.suite
|
||||||
|
end
|
||||||
|
|
||||||
|
require(`../../{test}`)(
|
||||||
|
setmetatable(constructors, { __index = frktest.test })
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
reporter.init()
|
||||||
|
process.exit(tonumber(frktest.run()))
|
69
.lune/tests/reporter.luau
Normal file
69
.lune/tests/reporter.luau
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
local stdio = require("@lune/stdio")
|
||||||
|
|
||||||
|
local frktest = require("../../lune_packages/frktest")
|
||||||
|
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,
|
||||||
|
|
||||||
|
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_leave(function()
|
||||||
|
stdio.write("\n")
|
||||||
|
end)
|
||||||
|
|
||||||
|
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_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)
|
||||||
|
|
||||||
|
frktest.test.on_test_skipped(function(test)
|
||||||
|
print(STYLE.report(test.name, "skip", 0))
|
||||||
|
end)
|
||||||
|
|
||||||
|
Reporter.init()
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable(ReporterExt, { __index = Reporter })
|
16
.lune/typecheck.luau
Normal file
16
.lune/typecheck.luau
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--> Run luau-lsp analysis to check for type errors
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
0
.pesde/.gitkeep
Normal file
0
.pesde/.gitkeep
Normal file
1
.styluaignore
Normal file
1
.styluaignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
!.lune/
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"luau-lsp.require.mode": "relativeToFile",
|
||||||
|
"luau-lsp.require.directoryAliases": {
|
||||||
|
"@lune/": "~/.lune/.typedefs/0.8.9/"
|
||||||
|
},
|
||||||
|
"stylua.targetReleaseVersion": "latest"
|
||||||
|
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 pesde-pkg
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
39
README.md
39
README.md
|
@ -1,3 +1,38 @@
|
||||||
# pesde scripts
|
# pesde/scripts_core
|
||||||
|
|
||||||
This repository hosts scripts & utilities for [pesde](https://github.com/daimond113/pesde)
|
<a href="https://discord.gg/ATVVsNNv3u"><img alt="Discord" src="https://img.shields.io/discord/385151591524597761?style=plastic&logo=discord&color=%235865F2" /></a>
|
||||||
|
<a href="https://lune-org.github.io/docs"><img alt="Lune" src="https://raw.githubusercontent.com/pesde-pkg/tooling/refs/heads/main/.lune/assets/powered-by-lune.svg" /></a>
|
||||||
|
<a href="https://pesde.dev/packages/pesde/scripts_core"><img alt="pesde/scripts_core" src="https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpesde-pkg%2Fscripts%2Frefs%2Fheads%2Fmaster%2Fpesde.toml&query=version&prefix=pesde%2Fscripts_core%40&style=plastic&label=pesde&color=F19D1E&logo=data:image/svg%2bxml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00OS42MDI1IDBMOTIuOTAzOCAyNVY3NUw0OS42MDI1IDEwMEw2LjMwMTI3IDc1VjI1TDQ5LjYwMjUgMFpNMTQuMzAxMyAyOS42MTg4TDQ5LjYwMjUgOS4yMzc2TDg0LjkwMzggMjkuNjE4OFY3MC4zODEyTDQ5LjYwMjUgOTAuNzYyNEwzMy42MTQ4IDgxLjUzMTlWNjcuMzg0OEMzNC41MTY3IDY4LjUwNzEgMzUuNjM4OCA2OS40MjE1IDM2Ljk4MSA3MC4xMjc5QzM4Ljk3MDEgNzEuMTQ4IDQxLjAzNTcgNzEuNjU4IDQzLjE3NzkgNzEuNjU4QzQ2LjQ0MiA3MS42NTggNDkuMTQ1MiA3MC44OTI5IDUxLjI4NzMgNjkuMzYyOUM1My40ODA1IDY3Ljc4MTggNTUuMTEyNiA2NS43NjcyIDU2LjE4MzYgNjMuMzE5QzU3LjA5MTUgNjEuMzM4MiA1Ny42MzIgNTkuMjc0IDU3LjgwNTQgNTcuMTI2M0M1OS44NzIzIDU3Ljc0NTcgNjIuMjE1NyA1OC4wNTU0IDY0LjgzNTYgNTguMDU1NEM2Ny42OTE4IDU4LjA1NTQgNzAuMzY5NSA1Ny42NDczIDcyLjg2ODYgNTYuODMxM0M3NS4zNjc4IDU1Ljk2NDIgNzcuNDA3OSA1NC44MTY3IDc4Ljk4OSA1My4zODg2TDc1Ljc3NTggNDcuODAzOEM3NC41NTE3IDQ4LjkyNTggNzIuOTk2MSA0OS44NDM5IDcxLjEwOSA1MC41NTc5QzY5LjIyMTkgNTEuMjIxIDY3LjIwNzMgNTEuNTUyNSA2NS4wNjUyIDUxLjU1MjVDNjEuMzkyOSA1MS41NTI1IDU4LjY2NDMgNTAuNjg1NCA1Ni44NzkyIDQ4Ljk1MTNDNTYuNzE5NSA0OC43OTYyIDU2LjU2NyA0OC42MzY1IDU2LjQyMTcgNDguNDcyQzU1LjYxMDIgNDcuNTUzOSA1NS4wMjExIDQ2LjQ4OTYgNTQuNjU0NiA0NS4yNzkxTDU0LjY0NDMgNDUuMjQ1Mkw1NC42NjkgNDUuMjc5MUg3OS4yMTg1VjQxLjk4OTRDNzkuMjE4NSAzOS4wMzEzIDc4LjU1NTUgMzYuMzUzNiA3Ny4yMjk0IDMzLjk1NjVDNzUuOTU0MyAzMS41NTkzIDc0LjA5MjcgMjkuNjQ2NyA3MS42NDQ1IDI4LjIxODZDNjkuMjQ3NCAyNi43Mzk1IDY2LjM2NTcgMjYgNjIuOTk5NSAyNkM1OS42ODQzIDI2IDU2LjgwMjcgMjYuNzM5NSA1NC4zNTQ1IDI4LjIxODZDNTEuOTA2NCAyOS42NDY3IDUwLjAxOTMgMzEuNTU5MyA0OC42OTMyIDMzLjk1NjVDNDcuNjc0MyAzNS43OTgzIDQ3LjA0NjkgMzcuODA1NyA0Ni44MTA4IDM5Ljk3ODhDNDUuNjg4OCAzOS43MjggNDQuNDc3OCAzOS42MDI2IDQzLjE3NzkgMzkuNjAyNkM0MS4wMzU3IDM5LjYwMjYgMzguOTcwMSA0MC4xMTI3IDM2Ljk4MSA0MS4xMzI3QzM1LjMxNjIgNDEuOTY1MSAzMy45OTAyIDQzLjE1NDkgMzMuMDAyOCA0NC43MDIzVjQwLjM2NzdIMjAuNjg1NVY0Ni4yNTg1SDI1LjgxMTNWNzcuMDI2NkwxNC4zMDEzIDcwLjM4MTJWMjkuNjE4OFpNNTUuMTk2MSAzNi4wOTg2QzU0LjY1MjggMzcuMTAxNSA1NC4zMzIxIDM4LjEyMTYgNTQuMjM0IDM5LjE1ODhINzEuNzk3NkM3MS43OTc2IDM4LjAzNjcgNzEuNDQwNSAzNi45NDAxIDcwLjcyNjUgMzUuODY5MUM3MC4wNjM0IDM0Ljc0NyA2OS4wNjg5IDMzLjgwMzUgNjcuNzQyOCAzMy4wMzg0QzY2LjQ2NzcgMzIuMjczNCA2NC44ODY3IDMxLjg5MDggNjIuOTk5NSAzMS44OTA4QzYxLjExMjQgMzEuODkwOCA1OS41MDU4IDMyLjI5ODkgNTguMTc5OCAzMy4xMTQ5QzU2LjkwNDcgMzMuODggNTUuOTEwMSAzNC44NzQ1IDU1LjE5NjEgMzYuMDk4NlpNNDkuNjQ1MSA1MS41NjkyQzQ5LjMwNzYgNTAuNjY0MSA0OC44MzgxIDQ5Ljg3MSA0OC4yMzY3IDQ5LjE4OThDNDguMDg4NSA0OS4wMjE5IDQ3LjkzMjMgNDguODYwOSA0Ny43NjgxIDQ4LjcwNjdDNDYuMDg1IDQ3LjA3NDYgNDQuMDQ0OSA0Ni4yNTg1IDQxLjY0NzggNDYuMjU4NUM0MC4xMTc3IDQ2LjI1ODUgMzguNjEzMSA0Ni41NjQ1IDM3LjEzNCA0Ny4xNzY2QzM1Ljg1OTQgNDcuNjc3MyAzNC42ODYzIDQ4LjU0MzggMzMuNjE0OCA0OS43NzU5VjYxLjQ3QzM0LjY4NjMgNjIuNjY2NCAzNS44NTk0IDYzLjUzNzggMzcuMTM0IDY0LjA4NEMzOC42MTMxIDY0LjY5NjEgNDAuMTE3NyA2NS4wMDIxIDQxLjY0NzggNjUuMDAyMUM0NC4wNDQ5IDY1LjAwMjEgNDYuMDg1IDY0LjE4NjEgNDcuNzY4MSA2Mi41NTRDNDkuNDUxMiA2MC45MjE5IDUwLjI5MjggNTguNjAxMiA1MC4yOTI4IDU1LjU5MjFDNTAuMjkyOCA1NC4wNjc5IDUwLjA3NjkgNTIuNzI3IDQ5LjY0NTEgNTEuNTY5MloiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KPC9zdmc+">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- TODO: CI workflow status -->
|
||||||
|
|
||||||
|
Scripts and other utilities for use with pesde.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
To ensure proper functionality, please make sure you have the following dependencies installed:
|
||||||
|
|
||||||
|
- **pesde**: Version `>= 0.5.0-rc.15`
|
||||||
|
- **lune**: Version `>= 0.8.9`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
For example, to install Rojo scripts, run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Add the scripts themselves
|
||||||
|
pesde add --dev pesde/scripts_rojo --target lune
|
||||||
|
# Add the Rojo CLI
|
||||||
|
pesde add --dev pesde/rojo --target lune
|
||||||
|
# Install dependencies
|
||||||
|
pesde install
|
||||||
|
```
|
||||||
|
|
||||||
|
If a sync tool you would like is not present here, please open an issue or submit a PR, following the format of one of the existing tools.
|
||||||
|
|
||||||
|
<!-- TODO: Recommend contributors to read CONTRIBUTING.md when that is a thing -->
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
This project is licensed under the [MIT](https://github.com/pesde-pkg/scripts/blob/master/LICENSE) license.
|
||||||
|
|
|
@ -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))
|
|
|
@ -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
|
|
249
pesde.lock
Normal file
249
pesde.lock
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
name = "pesde/scripts_core"
|
||||||
|
version = "0.0.1"
|
||||||
|
target = "lune"
|
||||||
|
|
||||||
|
[workspace."pesde/scripts_core"]
|
||||||
|
lune = ""
|
||||||
|
|
||||||
|
[workspace."pesde/scripts_rojo"]
|
||||||
|
lune = ".pesde/rojo"
|
||||||
|
|
||||||
|
[graph."0x5eal/semver"."0.1.1 luau"]
|
||||||
|
resolved_ty = "peer"
|
||||||
|
|
||||||
|
[graph."0x5eal/semver"."0.1.1 luau".target]
|
||||||
|
environment = "luau"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."0x5eal/semver"."0.1.1 luau".dependencies]
|
||||||
|
"lukadev_0/option" = ["1.2.0 luau", "option"]
|
||||||
|
"lukadev_0/result" = ["1.2.0 luau", "result"]
|
||||||
|
|
||||||
|
[graph."0x5eal/semver"."0.1.1 luau".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "0x5eal/semver"
|
||||||
|
version = "0.1.1"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."0x5eal/semver"."0.1.1 luau".pkg_ref.dependencies]
|
||||||
|
frktest = [{ name = "itsfrank/frktest", version = "^0.0.2", index = "https://github.com/daimond113/pesde-index", target = "lune" }, "dev"]
|
||||||
|
option = [{ name = "lukadev_0/option", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "peer"]
|
||||||
|
result = [{ name = "lukadev_0/result", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "peer"]
|
||||||
|
|
||||||
|
[graph."0x5eal/semver"."0.1.1 luau".pkg_ref.target]
|
||||||
|
environment = "luau"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."itsfrank/frktest"."0.0.2 lune"]
|
||||||
|
direct = ["frktest", { name = "itsfrank/frktest", version = "^0.0.2" }, "dev"]
|
||||||
|
resolved_ty = "dev"
|
||||||
|
|
||||||
|
[graph."itsfrank/frktest"."0.0.2 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/_pesde_init.luau"
|
||||||
|
|
||||||
|
[graph."itsfrank/frktest"."0.0.2 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "itsfrank/frktest"
|
||||||
|
version = "0.0.2"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."itsfrank/frktest"."0.0.2 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/_pesde_init.luau"
|
||||||
|
|
||||||
|
[graph."jiwonz/dirs"."0.1.2 lune"]
|
||||||
|
resolved_ty = "standard"
|
||||||
|
|
||||||
|
[graph."jiwonz/dirs"."0.1.2 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/init.luau"
|
||||||
|
|
||||||
|
[graph."jiwonz/dirs"."0.1.2 lune".dependencies]
|
||||||
|
"jiwonz/pathfs" = ["0.1.0 lune", "pathfs"]
|
||||||
|
|
||||||
|
[graph."jiwonz/dirs"."0.1.2 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "jiwonz/dirs"
|
||||||
|
version = "0.1.2"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."jiwonz/dirs"."0.1.2 lune".pkg_ref.dependencies]
|
||||||
|
pathfs = [{ name = "jiwonz/pathfs", version = "^0.1.0", index = "https://github.com/daimond113/pesde-index" }, "standard"]
|
||||||
|
|
||||||
|
[graph."jiwonz/dirs"."0.1.2 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/init.luau"
|
||||||
|
|
||||||
|
[graph."jiwonz/pathfs"."0.1.0 lune"]
|
||||||
|
direct = ["pathfs", { name = "jiwonz/pathfs", version = "^0.1.0" }, "dev"]
|
||||||
|
resolved_ty = "dev"
|
||||||
|
|
||||||
|
[graph."jiwonz/pathfs"."0.1.0 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "init.luau"
|
||||||
|
|
||||||
|
[graph."jiwonz/pathfs"."0.1.0 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "jiwonz/pathfs"
|
||||||
|
version = "0.1.0"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."jiwonz/pathfs"."0.1.0 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 lune"]
|
||||||
|
resolved_ty = "standard"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "lukadev_0/option"
|
||||||
|
version = "1.2.0"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 luau"]
|
||||||
|
resolved_ty = "peer"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 luau".target]
|
||||||
|
environment = "luau"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 luau".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "lukadev_0/option"
|
||||||
|
version = "1.2.0"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."lukadev_0/option"."1.2.0 luau".pkg_ref.target]
|
||||||
|
environment = "luau"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 lune"]
|
||||||
|
resolved_ty = "standard"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "lukadev_0/result"
|
||||||
|
version = "1.2.0"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 luau"]
|
||||||
|
resolved_ty = "peer"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 luau".target]
|
||||||
|
environment = "luau"
|
||||||
|
lib = "lib/init.luau"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 luau".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "lukadev_0/result"
|
||||||
|
version = "1.2.0"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."lukadev_0/result"."1.2.0 luau".pkg_ref.target]
|
||||||
|
environment = "luau"
|
||||||
|
lib = "lib/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"
|
||||||
|
|
||||||
|
[graph."pesde/luau_lsp"."1.36.0 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
bin = "init.luau"
|
||||||
|
|
||||||
|
[graph."pesde/luau_lsp"."1.36.0 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/luau_lsp"."1.36.0 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "pesde/luau_lsp"
|
||||||
|
version = "1.36.0"
|
||||||
|
index_url = "https://github.com/pesde-pkg/index"
|
||||||
|
|
||||||
|
[graph."pesde/luau_lsp"."1.36.0 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/luau_lsp"."1.36.0 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"
|
||||||
|
|
||||||
|
[graph."pesde/stylua"."2.0.1 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
bin = "init.luau"
|
||||||
|
|
||||||
|
[graph."pesde/stylua"."2.0.1 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/stylua"."2.0.1 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "pesde/stylua"
|
||||||
|
version = "2.0.1"
|
||||||
|
index_url = "https://github.com/pesde-pkg/index"
|
||||||
|
|
||||||
|
[graph."pesde/stylua"."2.0.1 lune".pkg_ref.dependencies]
|
||||||
|
core = [{ name = "pesde/toolchainlib", version = "^0.1.0", 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/stylua"."2.0.1 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
bin = "init.luau"
|
||||||
|
|
||||||
|
[graph."pesde/toolchainlib"."0.1.2 lune"]
|
||||||
|
resolved_ty = "standard"
|
||||||
|
|
||||||
|
[graph."pesde/toolchainlib"."0.1.2 lune".target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/init.luau"
|
||||||
|
|
||||||
|
[graph."pesde/toolchainlib"."0.1.2 lune".dependencies]
|
||||||
|
"0x5eal/semver" = ["0.1.1 luau", "semver"]
|
||||||
|
"jiwonz/dirs" = ["0.1.2 lune", "dirs"]
|
||||||
|
"jiwonz/pathfs" = ["0.1.0 lune", "pathfs"]
|
||||||
|
"lukadev_0/option" = ["1.2.0 lune", "option"]
|
||||||
|
"lukadev_0/result" = ["1.2.0 lune", "result"]
|
||||||
|
|
||||||
|
[graph."pesde/toolchainlib"."0.1.2 lune".pkg_ref]
|
||||||
|
ref_ty = "pesde"
|
||||||
|
name = "pesde/toolchainlib"
|
||||||
|
version = "0.1.2"
|
||||||
|
index_url = "https://github.com/daimond113/pesde-index"
|
||||||
|
|
||||||
|
[graph."pesde/toolchainlib"."0.1.2 lune".pkg_ref.dependencies]
|
||||||
|
dirs = [{ name = "jiwonz/dirs", version = "^0.1.1", index = "https://github.com/daimond113/pesde-index" }, "standard"]
|
||||||
|
option = [{ name = "lukadev_0/option", version = "^1.2.0", index = "https://github.com/daimond113/pesde-index" }, "peer"]
|
||||||
|
pathfs = [{ name = "jiwonz/pathfs", version = "^0.1.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" }, "peer"]
|
||||||
|
semver = [{ name = "0x5eal/semver", version = "^0.1.1", index = "https://github.com/daimond113/pesde-index", target = "luau" }, "peer"]
|
||||||
|
|
||||||
|
[graph."pesde/toolchainlib"."0.1.2 lune".pkg_ref.target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/init.luau"
|
36
pesde.toml
Normal file
36
pesde.toml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
name = "pesde/scripts_core"
|
||||||
|
version = "0.0.1"
|
||||||
|
pesde_version = "0.5.0-rc.16"
|
||||||
|
description = "Scripts and other utilities for use with pesde"
|
||||||
|
authors = [
|
||||||
|
"dai <contact@daimond113.com> (https://www.daimond113.com/)",
|
||||||
|
"Erica Marigold <hi@devcomp.xyz>",
|
||||||
|
]
|
||||||
|
repository = "https://github.com/pesde-pkg/scripts"
|
||||||
|
license = "MIT"
|
||||||
|
includes = [
|
||||||
|
"src/**/*.luau",
|
||||||
|
"!src/**/*.spec.luau",
|
||||||
|
"pesde.toml",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE",
|
||||||
|
]
|
||||||
|
|
||||||
|
workspace_members = [".", ".pesde/rojo"]
|
||||||
|
|
||||||
|
[meta.scripts.rojo]
|
||||||
|
version = "0.1.0"
|
||||||
|
tool_dependencies = { rojo = { name = "pesde/rojo", version = "^7.4.4" } }
|
||||||
|
|
||||||
|
[target]
|
||||||
|
environment = "lune"
|
||||||
|
lib = "src/init.luau"
|
||||||
|
|
||||||
|
[dev_dependencies]
|
||||||
|
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" }
|
||||||
|
|
||||||
|
[indices]
|
||||||
|
default = "https://github.com/pesde-pkg/index"
|
52
src/generators/rojo/sourcemap.luau
Normal file
52
src/generators/rojo/sourcemap.luau
Normal file
|
@ -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("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,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- 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
|
||||||
|
--- * Failure to spawn `rojo` 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
|
106
src/generators/rojo/sourcemap.spec.luau
Normal file
106
src/generators/rojo/sourcemap.spec.luau
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
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/rojo/test-projects"
|
||||||
|
local TEST_PROJECT_EXCLUDES = {
|
||||||
|
"json_model",
|
||||||
|
"bad_json_model",
|
||||||
|
"plugins",
|
||||||
|
"legacy-0.5.x-unknown-names",
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
end
|
115
src/generators/rojo/sync_config.luau
Normal file
115
src/generators/rojo/sync_config.luau
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
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 },
|
||||||
|
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
|
||||||
|
|
||||||
|
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 options.writeToFile then
|
||||||
|
fs.writeFile(syncConfigPath, serializedConfig)
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, serializedConfig
|
||||||
|
end
|
40
src/generators/rojo/sync_config.spec.luau
Normal file
40
src/generators/rojo/sync_config.spec.luau
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
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_DIRS = {
|
||||||
|
"./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)
|
||||||
|
|
||||||
|
-- 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)
|
||||||
|
end
|
8
src/init.luau
Normal file
8
src/init.luau
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
return {
|
||||||
|
generators = {
|
||||||
|
rojo = {
|
||||||
|
sourcemap = require("./generators/rojo/sourcemap"),
|
||||||
|
syncConfig = require("./generators/rojo/sync_config"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
10
stylua.toml
10
stylua.toml
|
@ -1,2 +1,10 @@
|
||||||
|
line_endings = "Unix"
|
||||||
|
quote_style = "AutoPreferDouble"
|
||||||
|
indent_type = "Tabs"
|
||||||
|
call_parentheses = "Always"
|
||||||
|
|
||||||
|
indent_width = 4
|
||||||
|
column_width = 80
|
||||||
|
|
||||||
[sort_requires]
|
[sort_requires]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
1
test-files/rojo
Submodule
1
test-files/rojo
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit b7d3394464e0ffb350b9c8481399cc5845c10f07
|
Loading…
Reference in a new issue