@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 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 SSS children (the package root) into the combined SSS
9
- -- 3. Reads the test script file and creates a Script under RS._BatchScripts
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
- -- Enable LoadStringEnabled on SSS
44
- sss:SetAttribute("LoadStringEnabled", true)
42
+ local HttpService = game:GetService("HttpService")
43
+ local ServerScriptService = game:GetService("ServerScriptService")
45
44
 
46
- -- Create _BatchScripts folder in ReplicatedStorage
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 the first package (already loaded as the base)
53
- do
54
- local pkg = packages[1]
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 SSS children.
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 pkgSSS = pkgGame:GetService("ServerScriptService")
65
+ local packageServerScriptService = pkgGame:GetService("ServerScriptService")
66
+ local packageHttpService = pkgGame:GetService("HttpService")
84
67
 
85
- -- Reparent all SSS children (non-recursively, just move the roots)
86
- for _, child in pkgSSS:GetChildren() do
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
- -- Read the test script and add to _BatchScripts
95
- local scriptSource = fs.readFile(pkg.scriptPath)
96
- local scriptInst = roblox.Instance.new("Script")
97
- scriptInst.Name = pkg.slug
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
- -- Also remove any Script instances from the base build's SSS
110
- -- (the batch runner uses loadstring, not auto-executed scripts)
111
- for _, child in sss:GetChildren() do
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 SSS_PREFIX = 'ServerScriptService.';
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(SSS_PREFIX)) {
41
- path = path.slice(SSS_PREFIX.length);
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,UAAU,GAAG,sBAAsB,CAAC;AAE1C;;;;;;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,UAAU,CAAC,EAAE,CAAC;QAChC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACvC,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,IACE,CAAC,GAAG,CAAC;YACL,CAAC,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,OAAO,CAAC,EACnC,CAAC;YACD,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"}
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 → SSS slug mapping. */
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,sCAAsC;IACtC,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,CAwGjC"}
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 SSS slug
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 sss = project.tree?.ServerScriptService;
105
- if (!sss) {
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(sss)) {
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 SSS`);
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":"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"}
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.23.0",
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": "7f6f73dc51f43fa1050f76f86a5935f5a64ab99f"
60
+ "gitHead": "9413391da8b6f9026762285b601fd1d37d385a54"
61
61
  }
@@ -15,7 +15,7 @@
15
15
 
16
16
  import type { SourcemapResolver } from '../../sourcemap/index.js';
17
17
 
18
- const SSS_PREFIX = 'ServerScriptService.';
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(SSS_PREFIX)) {
50
- path = path.slice(SSS_PREFIX.length);
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 → SSS slug mapping. */
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 SSS slug
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(luneScriptPath, ...luneArgs);
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 sss = project.tree?.ServerScriptService;
188
- if (!sss) {
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(sss)) {
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 SSS`
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 loader = ServerScriptService.{{gameNameProper}}:FindFirstChild("LoaderUtils", true).Parent
8
- local require = require(loader).bootstrapGame(ServerScriptService.{{gameNameProper}})
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"
@@ -0,0 +1,3 @@
1
+ return {
2
+ testMatch = { "**/*.spec" },
3
+ }
@@ -11,6 +11,9 @@
11
11
  "tree": {
12
12
  "$className": "DataModel",
13
13
  "ServerScriptService": {
14
+ "$properties": {
15
+ "LoadStringEnabled": true
16
+ },
14
17
  "{{packageName}}": {
15
18
  "$path": ".."
16
19
  },
@@ -3,8 +3,14 @@
3
3
  ]]
4
4
  local ServerScriptService = game:GetService("ServerScriptService")
5
5
 
6
- local loader = ServerScriptService:FindFirstChild("LoaderUtils", true).Parent
7
- local require = require(loader).bootstrapGame(ServerScriptService.{{packageName}})
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 loader = script.Parent:FindFirstChild("LoaderUtils", true).Parent
7
- local require = (require :: any)(loader).bootstrapPlugin(script) :: typeof(require(script.Parent.loader).load(script))
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()