refactor: use package project structure (#3)

This commit is contained in:
Erica Marigold 2024-12-09 00:03:56 +05:30 committed by GitHub
commit 98b5b554f8
Signed by untrusted user who does not match committer: DevComp
GPG key ID: 429EF1C337871656
27 changed files with 1354 additions and 66 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# Pesde packages
*_packages/
pesde.lock
# Generated scripts
.pesde/*
!.pesde/.gitkeep

3
.gitmodules vendored Normal file
View 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
View file

@ -0,0 +1,7 @@
{
"languageMode": "nonstrict",
"lint": {
"*": true,
"TableOperations": false
}
}

225
.lune/build.luau Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

1
.styluaignore Normal file
View file

@ -0,0 +1 @@
!.lune/

7
.vscode/settings.json vendored Normal file
View 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
View 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.

View file

@ -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.

View file

@ -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))

View file

@ -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
View 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
View 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"

View 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

View 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

View 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

View 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
View file

@ -0,0 +1,8 @@
return {
generators = {
rojo = {
sourcemap = require("./generators/rojo/sourcemap"),
syncConfig = require("./generators/rojo/sync_config"),
},
},
}

View file

@ -1,2 +1,10 @@
line_endings = "Unix"
quote_style = "AutoPreferDouble"
indent_type = "Tabs"
call_parentheses = "Always"
indent_width = 4
column_width = 80
[sort_requires]
enabled = true
enabled = true

1
test-files/rojo Submodule

@ -0,0 +1 @@
Subproject commit b7d3394464e0ffb350b9c8481399cc5845c10f07