@isentinel/jest-roblox 0.0.2 → 0.0.4

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/dist/index.d.mts CHANGED
@@ -1,17 +1,9 @@
1
- import { a as Argv, i as ResolvedConfig, n as Config, r as DEFAULT_CONFIG, t as CliOptions } from "./schema-CEsyg-FX.mjs";
2
- import { WebSocketServer } from "ws";
1
+ import { a as SnapshotFormatOptions, i as ResolvedConfig, n as Config, o as Argv, r as DEFAULT_CONFIG, t as CliOptions } from "./schema-ua9HqdbX.mjs";
2
+ import { WebSocket, WebSocketServer } from "ws";
3
3
  import buffer from "node:buffer";
4
4
 
5
5
  //#region src/types/jest-result.d.ts
6
- interface JestResult {
7
- numFailedTests: number;
8
- numPassedTests: number;
9
- numPendingTests: number;
10
- numTotalTests: number;
11
- startTime: number;
12
- success: boolean;
13
- testResults: Array<TestFileResult>;
14
- }
6
+ type TestStatus = "failed" | "passed" | "pending" | "skipped";
15
7
  interface TestCaseResult {
16
8
  ancestorTitles: Array<string>;
17
9
  duration?: number;
@@ -21,32 +13,51 @@ interface TestCaseResult {
21
13
  title: string;
22
14
  }
23
15
  interface TestFileResult {
16
+ failureMessage?: string;
24
17
  numFailingTests: number;
25
18
  numPassingTests: number;
26
19
  numPendingTests: number;
27
20
  testFilePath: string;
28
21
  testResults: Array<TestCaseResult>;
29
22
  }
30
- type TestStatus = "failed" | "passed" | "pending" | "skipped";
23
+ interface SnapshotSummary {
24
+ added: number;
25
+ matched: number;
26
+ total: number;
27
+ unmatched: number;
28
+ updated: number;
29
+ }
30
+ interface JestResult {
31
+ numFailedTests: number;
32
+ numPassedTests: number;
33
+ numPendingTests: number;
34
+ numTotalTests: number;
35
+ snapshot?: SnapshotSummary;
36
+ startTime: number;
37
+ success: boolean;
38
+ testResults: Array<TestFileResult>;
39
+ }
31
40
  //#endregion
32
41
  //#region src/reporter/parser.d.ts
42
+ type SnapshotWrites = Record<string, string>;
33
43
  interface ParseResult {
34
44
  luauTiming?: Record<string, number>;
35
45
  result: JestResult;
36
46
  snapshotWrites?: SnapshotWrites;
37
47
  }
38
- type SnapshotWrites = Record<string, string>;
39
48
  declare function extractJsonFromOutput(output: string): string | undefined;
40
49
  declare function parseJestOutput(output: string): ParseResult;
41
50
  //#endregion
42
51
  //#region src/backends/interface.d.ts
43
- interface Backend {
44
- runTests(options: BackendOptions): Promise<BackendResult>;
45
- }
46
52
  interface BackendOptions {
47
53
  config: ResolvedConfig;
48
54
  testFiles: Array<string>;
49
55
  }
56
+ interface BackendTiming {
57
+ executionMs: number;
58
+ uploadCached?: boolean;
59
+ uploadMs?: number;
60
+ }
50
61
  interface BackendResult {
51
62
  gameOutput?: string;
52
63
  luauTiming?: Record<string, number>;
@@ -54,16 +65,11 @@ interface BackendResult {
54
65
  snapshotWrites?: SnapshotWrites;
55
66
  timing: BackendTiming;
56
67
  }
57
- interface BackendTiming {
58
- executionMs: number;
59
- uploadCached?: boolean;
60
- uploadMs?: number;
68
+ interface Backend {
69
+ runTests(options: BackendOptions): Promise<BackendResult>;
61
70
  }
62
71
  //#endregion
63
72
  //#region src/backends/http-client.d.ts
64
- interface HttpClient {
65
- request(method: string, url: string, options?: RequestOptions): Promise<HttpResponse>;
66
- }
67
73
  interface HttpResponse {
68
74
  body: unknown;
69
75
  headers?: Record<string, string | undefined>;
@@ -74,6 +80,9 @@ interface RequestOptions {
74
80
  body?: unknown;
75
81
  headers?: Record<string, string>;
76
82
  }
83
+ interface HttpClient {
84
+ request(method: string, url: string, options?: RequestOptions): Promise<HttpResponse>;
85
+ }
77
86
  //#endregion
78
87
  //#region src/backends/open-cloud.d.ts
79
88
  interface OpenCloudCredentials {
@@ -101,15 +110,21 @@ declare class OpenCloudBackend implements Backend {
101
110
  declare function createOpenCloudBackend(): OpenCloudBackend;
102
111
  //#endregion
103
112
  //#region src/backends/studio.d.ts
113
+ interface PreConnected {
114
+ server: WebSocketServer;
115
+ socket: WebSocket;
116
+ }
104
117
  interface StudioOptions {
105
118
  createServer?: (port: number) => WebSocketServer;
106
119
  port: number;
120
+ preConnected?: PreConnected;
107
121
  timeout?: number;
108
122
  }
109
123
  declare class StudioBackend implements Backend {
110
124
  private readonly createServer;
111
125
  private readonly port;
112
126
  private readonly timeout;
127
+ private preConnected?;
113
128
  constructor(options: StudioOptions);
114
129
  runTests(options: BackendOptions): Promise<BackendResult>;
115
130
  private executeViaPlugin;
@@ -118,8 +133,8 @@ declare class StudioBackend implements Backend {
118
133
  declare function createStudioBackend(options: StudioOptions): StudioBackend;
119
134
  //#endregion
120
135
  //#region src/config/loader.d.ts
121
- declare function loadConfig(configPath?: string, cwd?: string): Promise<ResolvedConfig>;
122
136
  declare function resolveConfig(config: Config): ResolvedConfig;
137
+ declare function loadConfig(configPath?: string, cwd?: string): Promise<ResolvedConfig>;
123
138
  //#endregion
124
139
  //#region src/executor.d.ts
125
140
  interface ExecuteOptions {
@@ -137,20 +152,22 @@ interface ExecuteResult {
137
152
  declare function execute(options: ExecuteOptions): Promise<ExecuteResult>;
138
153
  //#endregion
139
154
  //#region src/source-mapper/index.d.ts
140
- interface MappedFailure {
141
- locations: Array<MappedLocation>;
142
- message: string;
143
- }
144
155
  interface MappedLocation {
145
156
  luauLine: number;
146
157
  luauPath: string;
158
+ sourceContent?: string;
147
159
  tsColumn?: number;
148
160
  tsLine: number;
149
161
  tsPath: string;
150
162
  }
163
+ interface MappedFailure {
164
+ locations: Array<MappedLocation>;
165
+ message: string;
166
+ }
151
167
  interface SourceMapper {
152
168
  mapFailureMessage(message: string): string;
153
169
  mapFailureWithLocations(message: string): MappedFailure;
170
+ resolveTestFilePath(testFilePath: string): string | undefined;
154
171
  }
155
172
  //#endregion
156
173
  //#region src/types/timing.d.ts
@@ -166,6 +183,8 @@ interface TimingResult {
166
183
  //#region src/formatters/formatter.d.ts
167
184
  interface FormatOptions {
168
185
  color: boolean;
186
+ gameOutput?: string;
187
+ outputFile?: string;
169
188
  rootDir: string;
170
189
  showLuau?: boolean;
171
190
  sourceMapper?: SourceMapper;
@@ -217,8 +236,8 @@ declare function formatFailure({
217
236
  totalFailures?: number;
218
237
  useColor?: boolean;
219
238
  }): string;
220
- declare function formatResult(result: JestResult, timing: TimingResult, options: FormatOptions): string;
221
239
  declare function formatTestSummary(result: JestResult, timing: TimingResult, styles?: Styles): string;
240
+ declare function formatResult(result: JestResult, timing: TimingResult, options: FormatOptions): string;
222
241
  //#endregion
223
242
  //#region src/formatters/json.d.ts
224
243
  declare function formatJson(result: JestResult): string;
@@ -226,11 +245,36 @@ declare function writeJsonFile(result: JestResult, filePath: string): Promise<vo
226
245
  //#endregion
227
246
  //#region src/test-script.d.ts
228
247
  type JestArgv = Argv & {
248
+ snapshotFormat?: SnapshotFormatOptions;
229
249
  testMatch: Array<string>;
230
250
  };
231
251
  declare function buildJestArgv(options: BackendOptions): JestArgv;
232
252
  declare function generateTestScript(options: BackendOptions): string;
233
253
  //#endregion
254
+ //#region src/typecheck/types.d.ts
255
+ interface TscErrorInfo {
256
+ column: number;
257
+ errCode: number;
258
+ errMsg: string;
259
+ filePath: string;
260
+ line: number;
261
+ }
262
+ interface TestDefinition {
263
+ name: string;
264
+ ancestorNames: Array<string>;
265
+ end: number;
266
+ start: number;
267
+ type: "suite" | "test";
268
+ }
269
+ //#endregion
270
+ //#region src/typecheck/runner.d.ts
271
+ interface TypecheckOptions {
272
+ files: Array<string>;
273
+ rootDir: string;
274
+ tsconfig?: string;
275
+ }
276
+ declare function runTypecheck(options: TypecheckOptions): JestResult;
277
+ //#endregion
234
278
  //#region src/types/game-output.d.ts
235
279
  interface GameOutputEntry {
236
280
  message: string;
@@ -243,4 +287,4 @@ declare function formatGameOutputNotice(filePath: string, entryCount: number): s
243
287
  declare function parseGameOutput(raw: string | undefined): Array<GameOutputEntry>;
244
288
  declare function writeGameOutput(filePath: string, entries: Array<GameOutputEntry>): void;
245
289
  //#endregion
246
- export { type Backend, type BackendOptions, type CliOptions, type Config, DEFAULT_CONFIG, type ExecuteOptions, type ExecuteResult, type GameOutputEntry, type JestArgv, type JestResult, OpenCloudBackend, type ResolvedConfig, StudioBackend, type TestCaseResult, type TestFileResult, type TestStatus, buildJestArgv, createOpenCloudBackend, createStudioBackend, execute, extractJsonFromOutput, formatFailure, formatGameOutputNotice, formatJson, formatResult, formatTestSummary, generateTestScript, loadConfig, parseGameOutput, parseJestOutput, resolveConfig, writeGameOutput, writeJsonFile };
290
+ export { type Backend, type BackendOptions, type CliOptions, type Config, DEFAULT_CONFIG, type ExecuteOptions, type ExecuteResult, type GameOutputEntry, type JestArgv, type JestResult, OpenCloudBackend, type ResolvedConfig, StudioBackend, type TestCaseResult, type TestDefinition, type TestFileResult, type TestStatus, type TscErrorInfo, type TypecheckOptions, buildJestArgv, createOpenCloudBackend, createStudioBackend, execute, extractJsonFromOutput, formatFailure, formatGameOutputNotice, formatJson, formatResult, formatTestSummary, generateTestScript, loadConfig, parseGameOutput, parseJestOutput, resolveConfig, runTypecheck, writeGameOutput, writeJsonFile };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { _ as buildJestArgv, a as formatJson, b as extractJsonFromOutput, c as formatResult, d as resolveConfig, f as DEFAULT_CONFIG, g as createOpenCloudBackend, h as OpenCloudBackend, i as execute, l as formatTestSummary, m as createStudioBackend, n as parseGameOutput, o as writeJsonFile, p as StudioBackend, r as writeGameOutput, s as formatFailure, t as formatGameOutputNotice, u as loadConfig, v as generateTestScript, x as parseJestOutput } from "./game-output-BDatGA9S.mjs";
1
+ import { C as extractJsonFromOutput, _ as createStudioBackend, a as execute, b as buildJestArgv, c as formatFailure, d as loadConfig, f as resolveConfig, g as StudioBackend, i as runTypecheck, l as formatResult, n as parseGameOutput, o as formatJson, p as DEFAULT_CONFIG, r as writeGameOutput, s as writeJsonFile, t as formatGameOutputNotice, u as formatTestSummary, v as OpenCloudBackend, w as parseJestOutput, x as generateTestScript, y as createOpenCloudBackend } from "./game-output-DO5fOpW3.mjs";
2
2
 
3
- export { DEFAULT_CONFIG, OpenCloudBackend, StudioBackend, buildJestArgv, createOpenCloudBackend, createStudioBackend, execute, extractJsonFromOutput, formatFailure, formatGameOutputNotice, formatJson, formatResult, formatTestSummary, generateTestScript, loadConfig, parseGameOutput, parseJestOutput, resolveConfig, writeGameOutput, writeJsonFile };
3
+ export { DEFAULT_CONFIG, OpenCloudBackend, StudioBackend, buildJestArgv, createOpenCloudBackend, createStudioBackend, execute, extractJsonFromOutput, formatFailure, formatGameOutputNotice, formatJson, formatResult, formatTestSummary, generateTestScript, loadConfig, parseGameOutput, parseJestOutput, resolveConfig, runTypecheck, writeGameOutput, writeJsonFile };
@@ -757,7 +757,18 @@ type Except<ObjectType, KeysType extends keyof ObjectType, Options extends Excep
757
757
  type _Except<ObjectType, KeysType extends keyof ObjectType, Options extends Required<ExceptOptions>> = { [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType] } & (Options['requireExactProps'] extends true ? Partial<Record<KeysType, never>> : {});
758
758
  //#endregion
759
759
  //#region src/config/schema.d.ts
760
- interface Config extends Except<Argv, "rootDir" | "setupFiles" | "testPathPattern"> {
760
+ type Backend = "auto" | "open-cloud" | "studio";
761
+ interface SnapshotFormatOptions {
762
+ callToJSON?: boolean;
763
+ escapeRegex?: boolean;
764
+ escapeString?: boolean;
765
+ indent?: number;
766
+ maxDepth?: number;
767
+ min?: boolean;
768
+ printBasicPrototype?: boolean;
769
+ printFunctionName?: boolean;
770
+ }
771
+ interface Config extends Except<Argv, "rootDir" | "setupFiles" | "setupFilesAfterEnv" | "testPathPattern"> {
761
772
  backend?: Backend;
762
773
  cache?: boolean;
763
774
  compact?: boolean;
@@ -770,14 +781,19 @@ interface Config extends Except<Argv, "rootDir" | "setupFiles" | "testPathPatter
770
781
  rojoProject?: string;
771
782
  rootDir?: string;
772
783
  setupFiles?: Array<string>;
784
+ setupFilesAfterEnv?: Array<string>;
773
785
  showLuau?: boolean;
786
+ snapshotFormat?: SnapshotFormatOptions;
774
787
  sourceMap?: boolean;
775
788
  testPathPattern?: string;
776
789
  timeout?: number;
790
+ typecheck?: boolean;
791
+ typecheckOnly?: boolean;
792
+ typecheckTsconfig?: string;
777
793
  updateSnapshot?: boolean;
778
794
  }
779
795
  interface ResolvedConfig extends Config {
780
- backend: "auto" | "open-cloud" | "studio";
796
+ backend: Backend;
781
797
  cache: boolean;
782
798
  color: boolean;
783
799
  compact: boolean;
@@ -794,9 +810,11 @@ interface ResolvedConfig extends Config {
794
810
  testMatch: Array<string>;
795
811
  testPathIgnorePatterns: Array<string>;
796
812
  timeout: number;
813
+ typecheck: boolean;
814
+ typecheckOnly: boolean;
815
+ typecheckTsconfig?: string;
797
816
  verbose: boolean;
798
817
  }
799
- type Backend = "auto" | "open-cloud" | "studio";
800
818
  declare const DEFAULT_CONFIG: ResolvedConfig;
801
819
  interface CliOptions {
802
820
  backend?: Backend;
@@ -815,15 +833,19 @@ interface CliOptions {
815
833
  projects?: Array<string>;
816
834
  rojoProject?: string;
817
835
  setupFiles?: Array<string>;
836
+ setupFilesAfterEnv?: Array<string>;
818
837
  showLuau?: boolean;
819
838
  silent?: boolean;
820
839
  sourceMap?: boolean;
821
840
  testNamePattern?: string;
822
841
  testPathPattern?: string;
823
842
  timeout?: number;
843
+ typecheck?: boolean;
844
+ typecheckOnly?: boolean;
845
+ typecheckTsconfig?: string;
824
846
  updateSnapshot?: boolean;
825
847
  verbose?: boolean;
826
848
  version?: boolean;
827
849
  }
828
850
  //#endregion
829
- export { Argv as a, ResolvedConfig as i, Config as n, DEFAULT_CONFIG as r, CliOptions as t };
851
+ export { SnapshotFormatOptions as a, ResolvedConfig as i, Config as n, Argv as o, DEFAULT_CONFIG as r, CliOptions as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isentinel/jest-roblox",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Jest-compatible CLI for running roblox-ts tests via Roblox Open Cloud",
5
5
  "keywords": [
6
6
  "jest",
@@ -9,6 +9,9 @@
9
9
  "testing",
10
10
  "cli"
11
11
  ],
12
+ "bugs": {
13
+ "email": "christopher.buss@pm.me"
14
+ },
12
15
  "license": "MIT",
13
16
  "author": "Christopher Buss <christopher.buss@pm.me> (https://github.com/christopher-buss)",
14
17
  "sideEffects": false,
@@ -30,18 +33,25 @@
30
33
  "!dist/**/*.tsbuildinfo"
31
34
  ],
32
35
  "dependencies": {
36
+ "@jridgewell/trace-mapping": "^0.3.25",
33
37
  "arktype": "2.1.29",
38
+ "get-tsconfig": "4.13.6",
34
39
  "highlight.js": "11.11.1",
35
40
  "jiti": "2.6.1",
41
+ "oxc-parser": "0.116.0",
36
42
  "tinyrainbow": "3.0.3",
37
43
  "ws": "8.18.0"
38
44
  },
39
45
  "devDependencies": {
40
- "@isentinel/eslint-config": "4.7.6",
46
+ "@isentinel/eslint-config": "5.0.0-beta.8",
47
+ "@oxc-project/types": "0.116.0",
41
48
  "@rbxts/jest": "3.13.3-ts.1",
42
- "@rbxts/types": "1.0.896",
43
- "@types/node": "24.10.4",
49
+ "@rbxts/types": "1.0.911",
50
+ "@total-typescript/shoehorn": "^0.1.2",
51
+ "@types/node": "24.10.13",
44
52
  "@types/ws": "8.5.13",
53
+ "@typescript/native-preview": "7.0.0-dev.20260308.1",
54
+ "@vitest/eslint-plugin": "1.6.9",
45
55
  "better-typescript-lib": "2.12.0",
46
56
  "bumpp": "10.4.1",
47
57
  "publint": "0.3.15",
@@ -53,18 +63,37 @@
53
63
  "node": ">=20.0.0"
54
64
  },
55
65
  "nx": {
66
+ "name": "jest-roblox-cli",
56
67
  "tags": [
57
68
  "scope:tooling",
58
69
  "type:cli"
59
70
  ],
60
71
  "projectType": "application",
72
+ "includedScripts": [
73
+ "!build"
74
+ ],
61
75
  "targets": {
76
+ "build": {
77
+ "command": "pnpm build:bundle && tsdown && pnpm build:plugin",
78
+ "options": {
79
+ "cwd": "tools/jest-roblox-cli"
80
+ }
81
+ },
62
82
  "lint": {
63
83
  "command": "eslint",
64
84
  "hasTypeAwareRules": true
65
85
  },
86
+ "build:bundle": {
87
+ "command": "pnpm build:bundle",
88
+ "options": {
89
+ "cwd": "tools/jest-roblox-cli"
90
+ }
91
+ },
66
92
  "test": {
67
93
  "command": "vitest run",
94
+ "dependsOn": [
95
+ "build:bundle"
96
+ ],
68
97
  "options": {
69
98
  "cwd": "tools/jest-roblox-cli"
70
99
  }
@@ -72,8 +101,9 @@
72
101
  }
73
102
  },
74
103
  "scripts": {
75
- "build": "tsdown",
76
- "build:plugin": "rojo build plugin/plugin.project.json -o plugin/JestRobloxRunner.rbxm",
104
+ "build": "pnpm build:bundle && tsdown && pnpm build:plugin",
105
+ "build:bundle": "darklua process -c .darklua-bundle.json luau/entry.luau src/test-runner.bundled.luau",
106
+ "build:plugin": "rm -rf plugin/out && darklua process -c .darklua-plugin.json luau/ plugin/out/shared/ && rojo build plugin/plugin.project.json -o plugin/JestRobloxRunner.rbxm",
77
107
  "release": "bumpp",
78
108
  "watch": "tsdown --watch"
79
109
  }
Binary file
@@ -0,0 +1,8 @@
1
+ --!strict
2
+ local HttpService = game:GetService("HttpService")
3
+
4
+ local Runner = require(script.Parent:FindFirstChild('runner'))
5
+
6
+ local config = HttpService:JSONDecode([=[__CONFIG_JSON__]=])
7
+
8
+ return Runner.run(script, config)
@@ -0,0 +1,93 @@
1
+ --!strict
2
+ local ReplicatedStorage = game:GetService("ReplicatedStorage")
3
+
4
+ local module = {}
5
+
6
+ function module.findInstance(path: string): Instance
7
+ local parts = string.split(path, "/")
8
+
9
+ local success, current = pcall(function()
10
+ return game:FindService(parts[1])
11
+ end)
12
+ assert(success, `Failed to find service {parts[1]}: {current}`)
13
+
14
+ for i = 2, #parts do
15
+ assert(current, `Failed to find '{parts[i - 1]}' in path {path}`)
16
+ current = current:FindFirstChild(parts[i])
17
+ end
18
+
19
+ assert(current, `Failed to find instance at path {path}`)
20
+
21
+ return current
22
+ end
23
+
24
+ function module.getJest(config: { jestPath: string? }): ModuleScript
25
+ local jestPath = config.jestPath
26
+ if jestPath then
27
+ local instance = module.findInstance(jestPath)
28
+ assert(instance, `Failed to find Jest instance at path {jestPath}`)
29
+ assert(instance:IsA("ModuleScript"), `Instance at path {jestPath} is not a ModuleScript`)
30
+ return instance :: ModuleScript
31
+ end
32
+
33
+ local jestInstance = ReplicatedStorage:FindFirstChild("Jest", true)
34
+ assert(jestInstance, "Failed to find Jest instance in ReplicatedStorage")
35
+ assert(
36
+ jestInstance:IsA("ModuleScript"),
37
+ "Jest instance in ReplicatedStorage is not a ModuleScript"
38
+ )
39
+ return jestInstance
40
+ end
41
+
42
+ function module.findRobloxShared(jestModule: ModuleScript): Instance?
43
+ local parent = jestModule.Parent
44
+ if parent then
45
+ local found = parent:FindFirstChild("RobloxShared")
46
+ or parent:FindFirstChild("jest-roblox-shared")
47
+ if found then
48
+ return found
49
+ end
50
+
51
+ if parent.Parent then
52
+ found = parent.Parent:FindFirstChild("RobloxShared")
53
+ or parent.Parent:FindFirstChild("jest-roblox-shared")
54
+ if found then
55
+ return found
56
+ end
57
+ end
58
+ end
59
+
60
+ return game:FindFirstChild("RobloxShared", true)
61
+ end
62
+
63
+ function module.findSiblingPackage(jestModule: ModuleScript, ...: string): Instance?
64
+ local parent = jestModule.Parent
65
+ if parent then
66
+ for _, name in { ... } do
67
+ local found = parent:FindFirstChild(name)
68
+ if found then
69
+ return found
70
+ end
71
+ end
72
+
73
+ if parent.Parent then
74
+ for _, name in { ... } do
75
+ local found = parent.Parent:FindFirstChild(name)
76
+ if found then
77
+ return found
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ for _, name in { ... } do
84
+ local found = game:FindFirstChild(name, true)
85
+ if found then
86
+ return found
87
+ end
88
+ end
89
+
90
+ return nil
91
+ end
92
+
93
+ return module
@@ -0,0 +1,19 @@
1
+ --!strict
2
+ local function getInstancePath(instance: Instance): string
3
+ local parts = {} :: { string }
4
+ local current: Instance? = instance
5
+ while current and current ~= game do
6
+ table.insert(parts, 1, current.Name)
7
+ current = current.Parent
8
+ end
9
+
10
+ return table.concat(parts, "/")
11
+ end
12
+
13
+ local CoreScriptSyncService = {}
14
+
15
+ function CoreScriptSyncService:GetScriptFilePath(instance: Instance): string
16
+ return getInstancePath(instance)
17
+ end
18
+
19
+ return CoreScriptSyncService
@@ -0,0 +1,30 @@
1
+ --!strict
2
+ local function normalizeSnapPath(path: string): string
3
+ return (string.gsub(path, "%.snap%.lua$", ".snap.luau"))
4
+ end
5
+
6
+ local function create(snapshotWrites: { [string]: string })
7
+ local FileSystemService = {}
8
+
9
+ function FileSystemService:WriteFile(path: string, contents: string)
10
+ snapshotWrites[normalizeSnapPath(path)] = contents
11
+ end
12
+
13
+ function FileSystemService:CreateDirectories(_path: string) end
14
+
15
+ function FileSystemService:Exists(path: string): boolean
16
+ return snapshotWrites[normalizeSnapPath(path)] ~= nil
17
+ end
18
+
19
+ function FileSystemService:Remove(path: string)
20
+ snapshotWrites[normalizeSnapPath(path)] = nil
21
+ end
22
+
23
+ function FileSystemService:IsRegularFile(path: string): boolean
24
+ return snapshotWrites[normalizeSnapPath(path)] ~= nil
25
+ end
26
+
27
+ return FileSystemService
28
+ end
29
+
30
+ return create