ts-repo-utils 7.8.1 → 7.9.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.
Files changed (73) hide show
  1. package/README.md +10 -0
  2. package/dist/cmd/assert-repo-is-clean.mjs +2 -1
  3. package/dist/cmd/assert-repo-is-clean.mjs.map +1 -1
  4. package/dist/cmd/check-should-run-type-checks.mjs +2 -1
  5. package/dist/cmd/check-should-run-type-checks.mjs.map +1 -1
  6. package/dist/cmd/format-diff-from.mjs +2 -1
  7. package/dist/cmd/format-diff-from.mjs.map +1 -1
  8. package/dist/cmd/format-uncommitted.mjs +2 -1
  9. package/dist/cmd/format-uncommitted.mjs.map +1 -1
  10. package/dist/cmd/gen-index-ts.mjs +2 -1
  11. package/dist/cmd/gen-index-ts.mjs.map +1 -1
  12. package/dist/entry-point.d.mts.map +1 -1
  13. package/dist/functions/assert-ext.d.mts +0 -1
  14. package/dist/functions/assert-ext.d.mts.map +1 -1
  15. package/dist/functions/assert-ext.mjs.map +1 -1
  16. package/dist/functions/assert-path-exists.d.mts.map +1 -1
  17. package/dist/functions/assert-path-exists.mjs.map +1 -1
  18. package/dist/functions/assert-repo-is-clean.d.mts.map +1 -1
  19. package/dist/functions/assert-repo-is-clean.mjs.map +1 -1
  20. package/dist/functions/create-result-assert.d.mts +0 -1
  21. package/dist/functions/create-result-assert.d.mts.map +1 -1
  22. package/dist/functions/create-result-assert.mjs.map +1 -1
  23. package/dist/functions/diff.d.mts +0 -1
  24. package/dist/functions/diff.d.mts.map +1 -1
  25. package/dist/functions/exec-async.d.mts +0 -1
  26. package/dist/functions/exec-async.d.mts.map +1 -1
  27. package/dist/functions/exec-async.mjs.map +1 -1
  28. package/dist/functions/format.d.mts +4 -5
  29. package/dist/functions/format.d.mts.map +1 -1
  30. package/dist/functions/format.mjs +3 -3
  31. package/dist/functions/format.mjs.map +1 -1
  32. package/dist/functions/gen-index.d.mts +0 -1
  33. package/dist/functions/gen-index.d.mts.map +1 -1
  34. package/dist/functions/gen-index.mjs.map +1 -1
  35. package/dist/functions/should-run.d.mts.map +1 -1
  36. package/dist/functions/should-run.mjs.map +1 -1
  37. package/dist/functions/workspace-utils/execute-parallel.d.mts.map +1 -1
  38. package/dist/functions/workspace-utils/execute-parallel.mjs +4 -5
  39. package/dist/functions/workspace-utils/execute-parallel.mjs.map +1 -1
  40. package/dist/functions/workspace-utils/get-workspace-packages.d.mts.map +1 -1
  41. package/dist/functions/workspace-utils/get-workspace-packages.mjs.map +1 -1
  42. package/dist/functions/workspace-utils/run-cmd-in-parallel.d.mts.map +1 -1
  43. package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs +2 -1
  44. package/dist/functions/workspace-utils/run-cmd-in-parallel.mjs.map +1 -1
  45. package/dist/functions/workspace-utils/run-cmd-in-stages.d.mts.map +1 -1
  46. package/dist/functions/workspace-utils/run-cmd-in-stages.mjs +2 -1
  47. package/dist/functions/workspace-utils/run-cmd-in-stages.mjs.map +1 -1
  48. package/dist/node-global.d.mts +0 -1
  49. package/dist/node-global.d.mts.map +1 -1
  50. package/package.json +25 -26
  51. package/src/cmd/assert-repo-is-clean.mts +2 -1
  52. package/src/cmd/check-should-run-type-checks.mts +2 -1
  53. package/src/cmd/format-diff-from.mts +2 -1
  54. package/src/cmd/format-uncommitted.mts +3 -1
  55. package/src/cmd/gen-index-ts.mts +8 -2
  56. package/src/entry-point.mts +1 -0
  57. package/src/functions/assert-ext.mts +4 -0
  58. package/src/functions/assert-path-exists.mts +2 -0
  59. package/src/functions/assert-repo-is-clean.mts +9 -0
  60. package/src/functions/create-result-assert.mts +1 -0
  61. package/src/functions/diff.test.mts +136 -8
  62. package/src/functions/exec-async.mts +4 -0
  63. package/src/functions/exec-async.test.mts +59 -2
  64. package/src/functions/format.mts +26 -7
  65. package/src/functions/format.test.mts +166 -9
  66. package/src/functions/gen-index.mts +16 -0
  67. package/src/functions/should-run.mts +2 -0
  68. package/src/functions/workspace-utils/execute-parallel.mts +27 -5
  69. package/src/functions/workspace-utils/get-workspace-packages.mts +5 -0
  70. package/src/functions/workspace-utils/run-cmd-in-parallel.mts +7 -1
  71. package/src/functions/workspace-utils/run-cmd-in-stages.mts +7 -1
  72. package/src/functions/workspace-utils/run-cmd-in-stages.test.mts +17 -3
  73. package/src/node-global.mts +7 -1
@@ -91,28 +91,35 @@ export const genIndex = async (
91
91
  // Step 1: Verify target directories exist
92
92
  for (const dir of targetDirs) {
93
93
  const resolvedDir = path.resolve(dir);
94
+
94
95
  // eslint-disable-next-line no-await-in-loop
95
96
  await assertPathExists(resolvedDir, `Target directory: ${dir}`);
96
97
  }
97
98
 
98
99
  // Step 2: Generate index files
99
100
  conditionalEcho('Generating index files...');
101
+
100
102
  for (const dir of targetDirs) {
101
103
  const resolvedDir = path.resolve(dir);
104
+
102
105
  // eslint-disable-next-line no-await-in-loop
103
106
  await generateIndexFileForDir(resolvedDir, filledConfig);
104
107
  }
108
+
105
109
  conditionalEcho('✓ Index files generated\n');
106
110
 
107
111
  // Step 3: Format generated files
108
112
  if (filledConfig.formatCommand !== undefined) {
109
113
  conditionalEcho('Formatting generated files...');
114
+
110
115
  const fmtResult = await $(filledConfig.formatCommand, {
111
116
  silent: filledConfig.silent,
112
117
  });
118
+
113
119
  if (Result.isErr(fmtResult)) {
114
120
  throw new Error(`Formatting failed: ${fmtResult.value.message}`);
115
121
  }
122
+
116
123
  conditionalEcho('✓ Formatting completed\n');
117
124
  }
118
125
 
@@ -121,6 +128,7 @@ export const genIndex = async (
121
128
  return Result.ok(undefined);
122
129
  } catch (error) {
123
130
  conditionalEcho(`❌ Index generation failed: ${String(error)}\n`);
131
+
124
132
  return Result.err(error);
125
133
  }
126
134
  };
@@ -148,6 +156,7 @@ const fillConfig = (config: GenIndexConfig): GenIndexConfigInternal => {
148
156
  if (exclude !== undefined && Array.isArray(exclude)) {
149
157
  yield* exclude;
150
158
  }
159
+
151
160
  yield* defaultConfig.exclude;
152
161
  }),
153
162
  ),
@@ -169,6 +178,7 @@ const fillConfig = (config: GenIndexConfig): GenIndexConfigInternal => {
169
178
  return true;
170
179
  }
171
180
  }
181
+
172
182
  return false;
173
183
  },
174
184
  ).value,
@@ -198,14 +208,18 @@ const generateIndexFileForDir = async (
198
208
  ): Promise<void> => {
199
209
  try {
200
210
  const actualBaseDir = baseDir ?? dirPath;
211
+
201
212
  const entries = await fs.readdir(dirPath, { withFileTypes: true });
202
213
 
203
214
  const mut_subDirectories: string[] = [];
215
+
204
216
  const mut_filesToExport: string[] = [];
205
217
 
206
218
  for (const entry of entries) {
207
219
  const entryName = entry.name;
220
+
208
221
  const entryPath = path.join(dirPath, entryName);
222
+
209
223
  const relativePath = path.relative(actualBaseDir, entryPath);
210
224
 
211
225
  if (
@@ -220,6 +234,7 @@ const generateIndexFileForDir = async (
220
234
 
221
235
  if (entry.isDirectory()) {
222
236
  mut_subDirectories.push(entryName);
237
+
223
238
  // Recursively call for subdirectories first
224
239
  // eslint-disable-next-line no-await-in-loop
225
240
  await generateIndexFileForDir(entryPath, config, actualBaseDir);
@@ -244,6 +259,7 @@ const generateIndexFileForDir = async (
244
259
  const indexPath = path.join(dirPath, `index${config.indexFileExtension}`);
245
260
 
246
261
  await fs.writeFile(indexPath, indexContent);
262
+
247
263
  echo(`Generated: ${path.relative(process.cwd(), indexPath)}`);
248
264
  } catch (error) {
249
265
  throw new Error(
@@ -84,6 +84,7 @@ export const checkShouldRunTypeChecks = async (
84
84
 
85
85
  if (Result.isErr(files)) {
86
86
  console.error('Error getting diff:', files.value);
87
+
87
88
  process.exit(1);
88
89
  }
89
90
 
@@ -102,6 +103,7 @@ export const checkShouldRunTypeChecks = async (
102
103
  // File extension pattern match (pattern starts with '**.')
103
104
  if (pattern.startsWith('**.')) {
104
105
  const extension = pattern.slice(2); // Remove '**'
106
+
105
107
  return path.basename(file).endsWith(extension);
106
108
  }
107
109
 
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable require-atomic-updates */
2
+ import { isError } from '@sindresorhus/is';
2
3
  import { spawn } from 'node:child_process';
3
4
  import {
4
5
  createPromise,
@@ -35,6 +36,7 @@ export const executeParallel = async (
35
36
  >[] = [];
36
37
 
37
38
  const mut_executing = new Set<Promise<unknown>>();
39
+
38
40
  let mut_failed = false as boolean;
39
41
 
40
42
  for (const pkg of packages) {
@@ -48,8 +50,10 @@ export const executeParallel = async (
48
50
  // Check for failure immediately
49
51
  if (Result.isErr(result)) {
50
52
  mut_failed = true;
53
+
51
54
  throw result.value; // Throw the error to trigger fail-fast
52
55
  }
56
+
53
57
  return result.value; // Return the unwrapped value for success
54
58
  });
55
59
 
@@ -59,10 +63,12 @@ export const executeParallel = async (
59
63
  // eslint-disable-next-line @typescript-eslint/no-loop-func
60
64
  .catch((error: unknown) => {
61
65
  mut_failed = true;
66
+
62
67
  throw error; // Re-throw to ensure fail-fast propagation
63
68
  })
64
69
  .finally(() => {
65
70
  mut_executing.delete(wrappedPromise);
71
+
66
72
  if (DEBUG) {
67
73
  console.debug('executing size', mut_executing.size);
68
74
  }
@@ -83,6 +89,7 @@ export const executeParallel = async (
83
89
  // If any process fails, cancel remaining processes and throw immediately
84
90
  // eslint-disable-next-line no-useless-assignment
85
91
  mut_failed = true;
92
+
86
93
  throw error;
87
94
  }
88
95
  }
@@ -116,6 +123,7 @@ export const executeStages = async (
116
123
  const sorted = topologicalSortPackages(packages, dependencyGraph);
117
124
 
118
125
  const mut_stages: (readonly Package[])[] = [];
126
+
119
127
  const mut_completed = new Set<string>();
120
128
 
121
129
  while (mut_completed.size < sorted.length) {
@@ -125,6 +133,7 @@ export const executeStages = async (
125
133
  if (mut_completed.has(pkg.name)) continue;
126
134
 
127
135
  const deps = dependencyGraph.get(pkg.name) ?? [];
136
+
128
137
  const depsCompleted = deps.every((dep) => mut_completed.has(dep));
129
138
 
130
139
  if (depsCompleted) {
@@ -137,6 +146,7 @@ export const executeStages = async (
137
146
  }
138
147
 
139
148
  mut_stages.push(mut_stage);
149
+
140
150
  for (const pkg of mut_stage) {
141
151
  mut_completed.add(pkg.name);
142
152
  }
@@ -149,6 +159,7 @@ export const executeStages = async (
149
159
  for (const [i, stage] of mut_stages.entries()) {
150
160
  if (stage.length > 0) {
151
161
  console.log(`Stage ${i + 1}: ${stage.map((p) => p.name).join(', ')}`);
162
+
152
163
  try {
153
164
  // eslint-disable-next-line no-await-in-loop
154
165
  const results = await executeParallel(stage, scriptName, concurrency);
@@ -160,11 +171,12 @@ export const executeStages = async (
160
171
  );
161
172
  } catch (error) {
162
173
  // executeParallel will throw immediately on any failure (fail-fast)
163
- const errorMessage = Error.isError(error)
164
- ? error.message
165
- : String(error);
174
+ const errorMessage = isError(error) ? error.message : String(error);
175
+
166
176
  console.error(`\n❌ Stage ${i + 1} failed (fail-fast):`);
177
+
167
178
  console.error(errorMessage);
179
+
168
180
  throw new Error(`Stage ${i + 1} failed: ${errorMessage}`, {
169
181
  cause: error,
170
182
  });
@@ -203,12 +215,15 @@ const executeScript = (
203
215
  : {};
204
216
 
205
217
  const hasScript = hasKey(packageJsonScripts, scriptName);
218
+
206
219
  if (!hasScript) {
207
220
  resolve({ skipped: true });
221
+
208
222
  return;
209
223
  }
210
224
 
211
225
  const prefixStr = prefix ? `[${pkg.name}] ` : '';
226
+
212
227
  const proc = spawn('npm', ['run', scriptName], {
213
228
  cwd: pkg.path,
214
229
  shell: true,
@@ -227,6 +242,7 @@ const executeScript = (
227
242
  if (DEBUG) {
228
243
  console.debug(`${pkg.name} process closed with code: ${code}`);
229
244
  }
245
+
230
246
  if (code === 0 || code === null) {
231
247
  resolve({ code: code ?? 0 });
232
248
  } else {
@@ -240,14 +256,15 @@ const executeScript = (
240
256
  ).map((result) =>
241
257
  result.then(
242
258
  Result.mapErr((err) => {
243
- const errorMessage: string = Error.isError(err)
259
+ const errorMessage: string = isError(err)
244
260
  ? err.message
245
261
  : isRecord(err) && hasKey(err, 'message')
246
262
  ? (err.message?.toString() ?? 'Unknown error message')
247
263
  : 'Unknown error';
248
264
 
249
265
  console.error(`\nError in ${pkg.name}:`, errorMessage);
250
- return Error.isError(err) ? err : new Error(errorMessage);
266
+
267
+ return isError(err) ? err : new Error(errorMessage);
251
268
  }),
252
269
  ),
253
270
  ).value;
@@ -264,15 +281,18 @@ const topologicalSortPackages = (
264
281
  dependencyGraph: ReadonlyMap<string, readonly string[]>,
265
282
  ): readonly Package[] => {
266
283
  const mut_visited = new Set<string>();
284
+
267
285
  const mut_result: string[] = [];
268
286
 
269
287
  const packageMap = new Map(packages.map((p) => [p.name, p]));
270
288
 
271
289
  const visit = (pkgName: string): void => {
272
290
  if (mut_visited.has(pkgName)) return;
291
+
273
292
  mut_visited.add(pkgName);
274
293
 
275
294
  const deps = dependencyGraph.get(pkgName) ?? [];
295
+
276
296
  for (const dep of deps) {
277
297
  visit(dep);
278
298
  }
@@ -301,12 +321,14 @@ const buildDependencyGraph = (
301
321
  packages: readonly Package[],
302
322
  ): ReadonlyMap<string, readonly string[]> => {
303
323
  const packageMap = new Map(packages.map((p) => [p.name, p]));
324
+
304
325
  const mut_graph = new Map<string, readonly string[]>();
305
326
 
306
327
  for (const pkg of packages) {
307
328
  const deps = Object.keys(pkg.dependencies).filter((depName) =>
308
329
  packageMap.has(depName),
309
330
  );
331
+
310
332
  mut_graph.set(pkg.name, deps);
311
333
  }
312
334
 
@@ -80,6 +80,7 @@ export const getWorkspacePackages = async (
80
80
  });
81
81
 
82
82
  const allPackageArrays = await Promise.all(packagePromises);
83
+
83
84
  const finalPackages = allPackageArrays.flat();
84
85
 
85
86
  return finalPackages;
@@ -108,12 +109,16 @@ const getKeyValueRecordFromJsonValue = (
108
109
  if (!isRecord(value) || !hasKey(value, key)) {
109
110
  return {};
110
111
  }
112
+
111
113
  const obj = value[key];
114
+
112
115
  if (!isRecord(obj)) {
113
116
  return {};
114
117
  }
118
+
115
119
  const entries = Object.entries(obj).filter(
116
120
  (entry): entry is [string, string] => isString(entry[1]),
117
121
  );
122
+
118
123
  return Object.fromEntries(entries);
119
124
  };
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
+ import { isError } from '@sindresorhus/is';
3
4
  import { executeParallel } from './execute-parallel.mjs';
4
5
  import { getWorkspacePackages } from './get-workspace-packages.mjs';
5
6
 
@@ -40,14 +41,19 @@ export const runCmdInParallelAcrossWorkspaces = async ({
40
41
  console.log(
41
42
  `\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast parallel mode)...`,
42
43
  );
44
+
43
45
  await executeParallel(filteredPackages, cmd, concurrency);
46
+
44
47
  console.log(`\n✅ ${cmd} completed successfully (all packages)`);
45
48
  } catch (error) {
46
- const errorMessage = Error.isError(error)
49
+ const errorMessage = isError(error)
47
50
  ? error.message
48
51
  : (error?.toString() ?? '');
52
+
49
53
  console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
54
+
50
55
  console.error(errorMessage);
56
+
51
57
  process.exit(1);
52
58
  }
53
59
  };
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
+ import { isError } from '@sindresorhus/is';
3
4
  import { executeStages } from './execute-parallel.mjs';
4
5
  import { getWorkspacePackages } from './get-workspace-packages.mjs';
5
6
 
@@ -42,14 +43,19 @@ export const runCmdInStagesAcrossWorkspaces = async ({
42
43
  console.log(
43
44
  `\nStarting ${cmd} across ${filteredPackages.length} packages (fail-fast mode)...`,
44
45
  );
46
+
45
47
  await executeStages(filteredPackages, cmd, concurrency);
48
+
46
49
  console.log(`\n✅ ${cmd} completed successfully (all stages)`);
47
50
  } catch (error) {
48
- const errorMessage = Error.isError(error)
51
+ const errorMessage = isError(error)
49
52
  ? error.message
50
53
  : (error?.toString() ?? '');
54
+
51
55
  console.error(`\n❌ ${cmd} failed (fail-fast mode stopped execution):`);
56
+
52
57
  console.error(errorMessage);
58
+
53
59
  process.exit(1);
54
60
  }
55
61
  };
@@ -7,15 +7,15 @@ import { runCmdInStagesAcrossWorkspaces } from './run-cmd-in-stages.mjs';
7
7
  import { type Package } from './types.mjs';
8
8
 
9
9
  // Mock the dependencies
10
- vi.mock('./execute-parallel.mjs', () => ({
10
+ vi.mock(import('./execute-parallel.mjs'), () => ({
11
11
  executeStages: vi.fn(),
12
12
  }));
13
13
 
14
- vi.mock('./get-workspace-packages.mjs', () => ({
14
+ vi.mock(import('./get-workspace-packages.mjs'), () => ({
15
15
  getWorkspacePackages: vi.fn(),
16
16
  }));
17
17
 
18
- describe('runCmdInStagesAcrossWorkspaces', () => {
18
+ describe(runCmdInStagesAcrossWorkspaces, () => {
19
19
  type MockedSpies = Readonly<{
20
20
  consoleLogSpy: MockInstance<typeof console.log>;
21
21
  consoleErrorSpy: MockInstance<typeof console.error>;
@@ -24,9 +24,11 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
24
24
 
25
25
  const setupSpies = (): MockedSpies => {
26
26
  vi.clearAllMocks();
27
+
27
28
  const consoleLogSpy = vi
28
29
  .spyOn(console, 'log')
29
30
  .mockImplementation((): void => {});
31
+
30
32
  const consoleErrorSpy = vi
31
33
  .spyOn(console, 'error')
32
34
  .mockImplementation((): void => {});
@@ -42,7 +44,9 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
42
44
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
43
45
  const cleanupSpies = (spies: MockedSpies): void => {
44
46
  spies.consoleLogSpy.mockRestore();
47
+
45
48
  spies.consoleErrorSpy.mockRestore();
49
+
46
50
  spies.processExitSpy.mockRestore();
47
51
  };
48
52
 
@@ -76,6 +80,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
76
80
 
77
81
  // Mock executeStages to throw an error (simulating a failed command)
78
82
  const mockError = new Error('package-a exited with code 1');
83
+
79
84
  vi.mocked(executeStages).mockRejectedValue(mockError);
80
85
 
81
86
  // Record start time
@@ -90,6 +95,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
90
95
 
91
96
  // Record end time
92
97
  const endTime = Date.now();
98
+
93
99
  const executionTime = endTime - startTime;
94
100
 
95
101
  // Verify that execution was fast (fail-fast behavior)
@@ -103,6 +109,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
103
109
  expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
104
110
  '\n❌ test failed (fail-fast mode stopped execution):',
105
111
  );
112
+
106
113
  expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
107
114
  'package-a exited with code 1',
108
115
  );
@@ -140,6 +147,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
140
147
  ];
141
148
 
142
149
  vi.mocked(getWorkspacePackages).mockResolvedValue(mockPackages);
150
+
143
151
  vi.mocked(executeStages).mockResolvedValue(undefined);
144
152
 
145
153
  // Execute the function
@@ -156,6 +164,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
156
164
  expect(spies.consoleLogSpy).toHaveBeenCalledWith(
157
165
  '\nStarting test across 2 packages (fail-fast mode)...',
158
166
  );
167
+
159
168
  expect(spies.consoleLogSpy).toHaveBeenCalledWith(
160
169
  '\n✅ test completed successfully (all stages)',
161
170
  );
@@ -200,6 +209,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
200
209
  ];
201
210
 
202
211
  vi.mocked(getWorkspacePackages).mockResolvedValue(mockPackages);
212
+
203
213
  vi.mocked(executeStages).mockResolvedValue(undefined);
204
214
 
205
215
  // Filter to only packages starting with 'package-'
@@ -217,6 +227,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
217
227
  const expectedFilteredPackages = mockPackages.filter((pkg) =>
218
228
  pkg.name.startsWith('package-'),
219
229
  );
230
+
220
231
  expect(executeStages).toHaveBeenCalledWith(
221
232
  expectedFilteredPackages,
222
233
  'test',
@@ -238,6 +249,7 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
238
249
  try {
239
250
  // Mock getWorkspacePackages to throw an error
240
251
  const mockError = new Error('Failed to load workspace packages');
252
+
241
253
  vi.mocked(getWorkspacePackages).mockRejectedValue(mockError);
242
254
 
243
255
  // Execute the function
@@ -254,9 +266,11 @@ describe('runCmdInStagesAcrossWorkspaces', () => {
254
266
  expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
255
267
  '\n❌ test failed (fail-fast mode stopped execution):',
256
268
  );
269
+
257
270
  expect(spies.consoleErrorSpy).toHaveBeenCalledWith(
258
271
  'Failed to load workspace packages',
259
272
  );
273
+
260
274
  expect(spies.processExitSpy).toHaveBeenCalledWith(1);
261
275
  } finally {
262
276
  cleanupSpies(spies);
@@ -29,14 +29,20 @@ Object.assign(globalThis, globalsDef);
29
29
 
30
30
  declare global {
31
31
  const path: typeof path_;
32
+
32
33
  const fs: typeof fs_;
34
+
33
35
  const os: typeof os_;
36
+
34
37
  const glob: typeof glob_;
35
38
 
36
39
  const $: typeof $_;
40
+
37
41
  const Result: typeof Result_;
38
- type Result<S, E> = Result_<S, E>;
42
+
39
43
  const echo: typeof console.log;
44
+
40
45
  const cd: typeof chdir_;
46
+
41
47
  const isDirectlyExecuted: typeof isDirectlyExecuted_;
42
48
  }