@quenty/nevermore-cli 4.23.0 → 4.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/build-scripts/combine-test-places.luau +21 -54
- package/dist/utils/testing/parsers/roblox-path-resolver.js +4 -5
- package/dist/utils/testing/parsers/roblox-path-resolver.js.map +1 -1
- package/dist/utils/testing/runner/combined-project-generator.d.ts +1 -1
- package/dist/utils/testing/runner/combined-project-generator.d.ts.map +1 -1
- package/dist/utils/testing/runner/combined-project-generator.js +5 -5
- package/dist/utils/testing/runner/combined-project-generator.js.map +1 -1
- package/package.json +2 -2
- package/src/utils/testing/parsers/roblox-path-resolver.ts +4 -7
- package/src/utils/testing/runner/combined-project-generator.ts +10 -7
- package/templates/game-template/src/scripts/Server/ServerMain.server.lua +4 -3
- package/templates/nevermore-service-package-template/package.json +4 -1
- package/templates/nevermore-service-package-template/src/jest.config.lua +3 -0
- package/templates/nevermore-service-package-template/test/default.project.json +3 -0
- package/templates/nevermore-service-package-template/test/scripts/Server/ServerMain.server.lua +8 -2
- package/templates/plugin-template/src/init.server.lua +4 -3
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [4.24.0](https://github.com/Quenty/Nevermore/compare/@quenty/nevermore-cli@4.23.0...@quenty/nevermore-cli@4.24.0) (2026-04-23)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/nevermore-cli
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# [4.23.0](https://github.com/Quenty/Nevermore/compare/@quenty/nevermore-cli@4.22.0...@quenty/nevermore-cli@4.23.0) (2026-02-23)
|
|
7
15
|
|
|
8
16
|
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
--
|
|
6
6
|
-- For each triple (slug, rbxl, scriptPath):
|
|
7
7
|
-- 1. Deserializes the .rbxl
|
|
8
|
-
-- 2. Reparents
|
|
9
|
-
-- 3. Reads the test script file and creates a Script under
|
|
8
|
+
-- 2. Reparents ServerScriptService children (the package root) into the combined ServerScriptService
|
|
9
|
+
-- 3. Reads the test script file and creates a Script under ReplicatedStorage._BatchScripts
|
|
10
10
|
|
|
11
11
|
local fs = require("@lune/fs")
|
|
12
12
|
local process = require("@lune/process")
|
|
@@ -38,38 +38,20 @@ end
|
|
|
38
38
|
-- Use the first package's place as the base (preserves DataModel properties)
|
|
39
39
|
local baseContents = fs.readFile(packages[1].rbxlPath)
|
|
40
40
|
local game = roblox.deserializePlace(baseContents)
|
|
41
|
-
local sss = game:GetService("ServerScriptService")
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
local HttpService = game:GetService("HttpService")
|
|
43
|
+
local ServerScriptService = game:GetService("ServerScriptService")
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
local rs = game:GetService("ReplicatedStorage")
|
|
48
|
-
local batchScriptsFolder = roblox.Instance.new("Folder")
|
|
49
|
-
batchScriptsFolder.Name = "_BatchScripts"
|
|
50
|
-
batchScriptsFolder.Parent = rs
|
|
45
|
+
ServerScriptService.LoadStringEnabled = true
|
|
51
46
|
|
|
52
|
-
-- Process
|
|
53
|
-
do
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-- SSS children are already in place from the base build.
|
|
57
|
-
-- Read the test script and add to _BatchScripts.
|
|
58
|
-
local scriptSource = fs.readFile(pkg.scriptPath)
|
|
59
|
-
local scriptInst = roblox.Instance.new("Script")
|
|
60
|
-
scriptInst.Name = pkg.slug
|
|
61
|
-
scriptInst:AddTag("_BatchTest_" .. pkg.slug)
|
|
62
|
-
local ok, err = pcall(function()
|
|
63
|
-
(scriptInst :: any).Source = scriptSource
|
|
64
|
-
end)
|
|
65
|
-
if not ok then
|
|
66
|
-
warn("[CombinePlaces] Cannot set Source on " .. pkg.slug .. ": " .. tostring(err))
|
|
67
|
-
scriptInst:SetAttribute("ScriptSource", scriptSource)
|
|
47
|
+
-- Process first package
|
|
48
|
+
for _, descendant in ServerScriptService:GetDescendants() do
|
|
49
|
+
if descendant:IsA("Script") then
|
|
50
|
+
descendant:AddTag("_BatchTest_" .. packages[1].slug)
|
|
68
51
|
end
|
|
69
|
-
scriptInst.Parent = batchScriptsFolder
|
|
70
52
|
end
|
|
71
53
|
|
|
72
|
-
-- Process remaining packages: deserialize each and reparent
|
|
54
|
+
-- Process remaining packages: deserialize each and reparent ServerScriptService children.
|
|
73
55
|
-- NOTE: ObjectValues (links) within each package's subtree are preserved when the
|
|
74
56
|
-- whole subtree is reparented as a unit. This works because all ObjectValue targets
|
|
75
57
|
-- are siblings within the same tree. If this breaks in a future Lune version, the
|
|
@@ -80,37 +62,22 @@ for idx = 2, #packages do
|
|
|
80
62
|
|
|
81
63
|
local contents = fs.readFile(pkg.rbxlPath)
|
|
82
64
|
local pkgGame = roblox.deserializePlace(contents)
|
|
83
|
-
local
|
|
65
|
+
local packageServerScriptService = pkgGame:GetService("ServerScriptService")
|
|
66
|
+
local packageHttpService = pkgGame:GetService("HttpService")
|
|
84
67
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-- Skip Script instances (these are test entry points, not package roots)
|
|
88
|
-
if child.ClassName == "Script" and child.Name == "Script" then
|
|
89
|
-
continue
|
|
90
|
-
end
|
|
91
|
-
child.Parent = sss
|
|
68
|
+
if packageHttpService.HttpEnabled then
|
|
69
|
+
HttpService.HttpEnabled = true
|
|
92
70
|
end
|
|
93
71
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
scriptInst:AddTag("_BatchTest_" .. pkg.slug)
|
|
99
|
-
local ok, err = pcall(function()
|
|
100
|
-
(scriptInst :: any).Source = scriptSource
|
|
101
|
-
end)
|
|
102
|
-
if not ok then
|
|
103
|
-
warn("[CombinePlaces] Cannot set Source on " .. pkg.slug .. ": " .. tostring(err))
|
|
104
|
-
scriptInst:SetAttribute("ScriptSource", scriptSource)
|
|
72
|
+
for _, descendant in packageServerScriptService:GetDescendants() do
|
|
73
|
+
if descendant:IsA("Script") then
|
|
74
|
+
descendant:AddTag("_BatchTest_" .. pkg.slug)
|
|
75
|
+
end
|
|
105
76
|
end
|
|
106
|
-
scriptInst.Parent = batchScriptsFolder
|
|
107
|
-
end
|
|
108
77
|
|
|
109
|
-
--
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if child.ClassName == "Script" and child.Name == "Script" then
|
|
113
|
-
child.Parent = nil
|
|
78
|
+
-- Reparent all ServerScriptService children (non-recursively, just move the roots)
|
|
79
|
+
for _, child in packageServerScriptService:GetChildren() do
|
|
80
|
+
child.Parent = ServerScriptService
|
|
114
81
|
end
|
|
115
82
|
end
|
|
116
83
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* hard-codes `.spec`/`.story` as known dotted suffixes. Works when no
|
|
13
13
|
* sourcemap is available.
|
|
14
14
|
*/
|
|
15
|
-
const
|
|
15
|
+
const SERVER_SCRIPT_SERVICE_PREFIX = 'ServerScriptService.';
|
|
16
16
|
/**
|
|
17
17
|
* Resolve a Roblox instance path (from Jest-lua or a stack trace) to a
|
|
18
18
|
* repo-relative filesystem path.
|
|
@@ -37,8 +37,8 @@ function _resolveHeuristic(instancePath) {
|
|
|
37
37
|
// Strip :LINE suffix if present
|
|
38
38
|
let path = instancePath.replace(/:\d+$/, '');
|
|
39
39
|
// Strip ServerScriptService. prefix
|
|
40
|
-
if (path.startsWith(
|
|
41
|
-
path = path.slice(
|
|
40
|
+
if (path.startsWith(SERVER_SCRIPT_SERVICE_PREFIX)) {
|
|
41
|
+
path = path.slice(SERVER_SCRIPT_SERVICE_PREFIX.length);
|
|
42
42
|
}
|
|
43
43
|
// First dot-separated segment is the package slug
|
|
44
44
|
const dotIndex = path.indexOf('.');
|
|
@@ -57,8 +57,7 @@ function _resolveHeuristic(instancePath) {
|
|
|
57
57
|
for (let i = 0; i < segments.length; i++) {
|
|
58
58
|
const seg = segments[i];
|
|
59
59
|
// If this segment is a known file suffix, merge it with the previous
|
|
60
|
-
if (i > 0 &&
|
|
61
|
-
(seg === 'spec' || seg === 'story')) {
|
|
60
|
+
if (i > 0 && (seg === 'spec' || seg === 'story')) {
|
|
62
61
|
rejoined[rejoined.length - 1] += `.${seg}`;
|
|
63
62
|
}
|
|
64
63
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roblox-path-resolver.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/roblox-path-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,
|
|
1
|
+
{"version":3,"file":"roblox-path-resolver.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/roblox-path-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,4BAA4B,GAAG,sBAAsB,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,YAAoB,EACpB,iBAAqC;IAErC,IAAI,iBAAiB,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACzD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;IAChC,CAAC;IAED,OAAO,iBAAiB,CAAC,YAAY,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,YAAoB;IAC7C,gCAAgC;IAChC,IAAI,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAE7C,oCAAoC;IACpC,IAAI,IAAI,CAAC,UAAU,CAAC,4BAA4B,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IAED,kDAAkD;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,4DAA4D;QAC5D,OAAO,OAAO,IAAI,MAAM,CAAC;IAC3B,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IAE3C,wEAAwE;IACxE,4EAA4E;IAC5E,sEAAsE;IACtE,sBAAsB;IACtB,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxB,qEAAqE;QACrE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,OAAO,CAAC,EAAE,CAAC;YACjD,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,OAAO,WAAW,QAAQ,OAAO,MAAM,CAAC;AACjD,CAAC"}
|
|
@@ -4,7 +4,7 @@ import { type TargetPackage } from '../../batch/changed-packages-utils.js';
|
|
|
4
4
|
export interface CombinedProjectResult {
|
|
5
5
|
/** Absolute path to the combined .rbxl file. */
|
|
6
6
|
rbxlPath: string;
|
|
7
|
-
/** packageName →
|
|
7
|
+
/** packageName → ServerScriptService slug mapping. */
|
|
8
8
|
slugMap: Map<string, string>;
|
|
9
9
|
/** First package's deploy target (provides placeId/universeId for upload). */
|
|
10
10
|
primaryTarget: DeployTarget;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combined-project-generator.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EAEb,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"combined-project-generator.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EAEb,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,8EAA8E;IAC9E,aAAa,EAAE,YAAY,CAAC;IAC5B,sFAAsF;IACtF,YAAY,EAAE,YAAY,CAAC;CAC5B;AAMD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,sBAAsB,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACnD,cAAc,CAAC,IAAI,IAAI,CAAC;IACxB,cAAc,CAAC,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/C;AASD;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,EAAE;IAC1D,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA2GjC"}
|
|
@@ -34,7 +34,7 @@ export async function generateCombinedProjectAsync(options) {
|
|
|
34
34
|
if (batchUniverseId)
|
|
35
35
|
primaryTarget.universeId = batchUniverseId;
|
|
36
36
|
}
|
|
37
|
-
// Parse the rojo project to extract the
|
|
37
|
+
// Parse the rojo project to extract the ServerScriptService slug
|
|
38
38
|
const projectPath = path.resolve(pkg.path, target.project);
|
|
39
39
|
const slug = await _extractSlugAsync(pkg.name, projectPath);
|
|
40
40
|
// Validate slug uniqueness
|
|
@@ -101,15 +101,15 @@ async function _extractSlugAsync(packageName, projectPath) {
|
|
|
101
101
|
throw new Error(`Cannot read test project for ${packageName}: ${projectPath}`);
|
|
102
102
|
}
|
|
103
103
|
const project = JSON.parse(content);
|
|
104
|
-
const
|
|
105
|
-
if (!
|
|
104
|
+
const serverScriptService = project.tree?.ServerScriptService;
|
|
105
|
+
if (!serverScriptService) {
|
|
106
106
|
throw new Error(`Test project for ${packageName} is missing ServerScriptService in tree`);
|
|
107
107
|
}
|
|
108
|
-
for (const key of Object.keys(
|
|
108
|
+
for (const key of Object.keys(serverScriptService)) {
|
|
109
109
|
if (!key.startsWith('$') && key !== 'Script') {
|
|
110
110
|
return key;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
|
-
throw new Error(`Test project for ${packageName} has no package entry under
|
|
113
|
+
throw new Error(`Test project for ${packageName} has no package entry under ServerScriptService`);
|
|
114
114
|
}
|
|
115
115
|
//# sourceMappingURL=combined-project-generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combined-project-generator.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EACL,YAAY,EACZ,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAEL,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAmCtC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,OAMlD;IACC,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAEtE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC;QAClD,MAAM,EAAE,gBAAgB;KACzB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,IAAI,aAAuC,CAAC;IAC5C,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,iDAAiD;IAEjD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEnD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,aAAa,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;YAC9B,IAAI,YAAY;gBAAE,aAAa,CAAC,OAAO,GAAG,YAAY,CAAC;YACvD,IAAI,eAAe;gBAAE,aAAa,CAAC,UAAU,GAAG,eAAe,CAAC;QAClE,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"combined-project-generator.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/nevermore-cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.24.0",
|
|
4
4
|
"description": "CLI interface for Nevermore",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"engines": {
|
|
58
58
|
"node": ">=16"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "9413391da8b6f9026762285b601fd1d37d385a54"
|
|
61
61
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import type { SourcemapResolver } from '../../sourcemap/index.js';
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const SERVER_SCRIPT_SERVICE_PREFIX = 'ServerScriptService.';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Resolve a Roblox instance path (from Jest-lua or a stack trace) to a
|
|
@@ -46,8 +46,8 @@ function _resolveHeuristic(instancePath: string): string {
|
|
|
46
46
|
let path = instancePath.replace(/:\d+$/, '');
|
|
47
47
|
|
|
48
48
|
// Strip ServerScriptService. prefix
|
|
49
|
-
if (path.startsWith(
|
|
50
|
-
path = path.slice(
|
|
49
|
+
if (path.startsWith(SERVER_SCRIPT_SERVICE_PREFIX)) {
|
|
50
|
+
path = path.slice(SERVER_SCRIPT_SERVICE_PREFIX.length);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// First dot-separated segment is the package slug
|
|
@@ -70,10 +70,7 @@ function _resolveHeuristic(instancePath: string): string {
|
|
|
70
70
|
for (let i = 0; i < segments.length; i++) {
|
|
71
71
|
const seg = segments[i];
|
|
72
72
|
// If this segment is a known file suffix, merge it with the previous
|
|
73
|
-
if (
|
|
74
|
-
i > 0 &&
|
|
75
|
-
(seg === 'spec' || seg === 'story')
|
|
76
|
-
) {
|
|
73
|
+
if (i > 0 && (seg === 'spec' || seg === 'story')) {
|
|
77
74
|
rejoined[rejoined.length - 1] += `.${seg}`;
|
|
78
75
|
} else {
|
|
79
76
|
rejoined.push(seg);
|
|
@@ -16,7 +16,7 @@ import { type TargetPackage } from '../../batch/changed-packages-utils.js';
|
|
|
16
16
|
export interface CombinedProjectResult {
|
|
17
17
|
/** Absolute path to the combined .rbxl file. */
|
|
18
18
|
rbxlPath: string;
|
|
19
|
-
/** packageName →
|
|
19
|
+
/** packageName → ServerScriptService slug mapping. */
|
|
20
20
|
slugMap: Map<string, string>;
|
|
21
21
|
/** First package's deploy target (provides placeId/universeId for upload). */
|
|
22
22
|
primaryTarget: DeployTarget;
|
|
@@ -87,7 +87,7 @@ export async function generateCombinedProjectAsync(options: {
|
|
|
87
87
|
if (batchUniverseId) primaryTarget.universeId = batchUniverseId;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
// Parse the rojo project to extract the
|
|
90
|
+
// Parse the rojo project to extract the ServerScriptService slug
|
|
91
91
|
const projectPath = path.resolve(pkg.path, target.project);
|
|
92
92
|
const slug = await _extractSlugAsync(pkg.name, projectPath);
|
|
93
93
|
|
|
@@ -150,7 +150,10 @@ export async function generateCombinedProjectAsync(options: {
|
|
|
150
150
|
completed: 0,
|
|
151
151
|
total: builds.length,
|
|
152
152
|
});
|
|
153
|
-
await buildContext.executeLuneTransformScriptAsync(
|
|
153
|
+
await buildContext.executeLuneTransformScriptAsync(
|
|
154
|
+
luneScriptPath,
|
|
155
|
+
...luneArgs
|
|
156
|
+
);
|
|
154
157
|
|
|
155
158
|
OutputHelper.verbose(
|
|
156
159
|
`Combined ${slugMap.size} packages at ${combinedRbxlPath}`
|
|
@@ -184,20 +187,20 @@ async function _extractSlugAsync(
|
|
|
184
187
|
const project = JSON.parse(content) as {
|
|
185
188
|
tree: { ServerScriptService?: RojoNode };
|
|
186
189
|
};
|
|
187
|
-
const
|
|
188
|
-
if (!
|
|
190
|
+
const serverScriptService = project.tree?.ServerScriptService;
|
|
191
|
+
if (!serverScriptService) {
|
|
189
192
|
throw new Error(
|
|
190
193
|
`Test project for ${packageName} is missing ServerScriptService in tree`
|
|
191
194
|
);
|
|
192
195
|
}
|
|
193
196
|
|
|
194
|
-
for (const key of Object.keys(
|
|
197
|
+
for (const key of Object.keys(serverScriptService)) {
|
|
195
198
|
if (!key.startsWith('$') && key !== 'Script') {
|
|
196
199
|
return key;
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
throw new Error(
|
|
201
|
-
`Test project for ${packageName} has no package entry under
|
|
204
|
+
`Test project for ${packageName} has no package entry under ServerScriptService`
|
|
202
205
|
);
|
|
203
206
|
}
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
]]
|
|
5
5
|
local ServerScriptService = game:GetService("ServerScriptService")
|
|
6
6
|
|
|
7
|
-
local
|
|
8
|
-
local
|
|
7
|
+
local root = ServerScriptService.{{gameNameProper}}
|
|
8
|
+
local loader = root:FindFirstChild("LoaderUtils", true).Parent
|
|
9
|
+
local require = require(loader).bootstrapGame(root)
|
|
9
10
|
|
|
10
11
|
local serviceBag = require("ServiceBag").new()
|
|
11
12
|
serviceBag:GetService(require("{{gameNameProper}}Service"))
|
|
12
13
|
serviceBag:Init()
|
|
13
|
-
serviceBag:Start()
|
|
14
|
+
serviceBag:Start()
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
"Quenty"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@quenty/loader": "workspace:*"
|
|
31
|
+
"@quenty/loader": "workspace:*",
|
|
32
|
+
"@quenty/nevermore-test-runner": "workspace:*",
|
|
33
|
+
"@quenty/servicebag": "workspace:*",
|
|
34
|
+
"@quentystudios/jest-lua": "3.10.0-quenty.2"
|
|
32
35
|
},
|
|
33
36
|
"publishConfig": {
|
|
34
37
|
"access": "public"
|
package/templates/nevermore-service-package-template/test/scripts/Server/ServerMain.server.lua
CHANGED
|
@@ -3,8 +3,14 @@
|
|
|
3
3
|
]]
|
|
4
4
|
local ServerScriptService = game:GetService("ServerScriptService")
|
|
5
5
|
|
|
6
|
-
local
|
|
7
|
-
local
|
|
6
|
+
local root = ServerScriptService.{{packageName}}
|
|
7
|
+
local loader = root:FindFirstChild("LoaderUtils", true).Parent
|
|
8
|
+
local require = require(loader).bootstrapGame(root)
|
|
9
|
+
|
|
10
|
+
local NevermoreTestRunnerUtils = require("NevermoreTestRunnerUtils")
|
|
11
|
+
if NevermoreTestRunnerUtils.runTestsIfNeededAsync(root) then
|
|
12
|
+
return
|
|
13
|
+
end
|
|
8
14
|
|
|
9
15
|
local serviceBag = require("ServiceBag").new()
|
|
10
16
|
serviceBag:GetService(require("{{packageNameProper}}Service"))
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
{{pluginName}} initialization script
|
|
4
4
|
]]
|
|
5
5
|
|
|
6
|
-
local
|
|
7
|
-
local
|
|
6
|
+
local root = script.Parent
|
|
7
|
+
local loader = root:FindFirstChild("LoaderUtils", true).Parent
|
|
8
|
+
local require = (require :: any)(loader).bootstrapPlugin(script) :: typeof(require(root.loader).load(script))
|
|
8
9
|
|
|
9
10
|
local ServiceBag = require("ServiceBag")
|
|
10
11
|
|
|
11
12
|
-- Initialize the plugin here
|
|
12
13
|
local serviceBag = ServiceBag.new()
|
|
13
14
|
serviceBag:Init()
|
|
14
|
-
serviceBag:Start()
|
|
15
|
+
serviceBag:Start()
|