@systemfsoftware/stryker-js-vitest-runner 2.0.2 → 3.0.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 (3) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/index.mjs +357 -419
  3. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @systemfsoftware/stryker-js-vitest-runner
2
2
 
3
+ ## 3.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - The dry-run decision moved to a plain kernel (dryRunCell removed); the mutant-run decision splits into branded MutantKilled|MutantSurvived|MutantTimeout|MutantDryError variants
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies:
12
+ - @systemfsoftware/effect-cell-types@6.0.0
13
+ - @systemfsoftware/stryker-js@1.0.0
14
+
15
+ ## 2.1.0
16
+
17
+ ### Minor Changes
18
+
19
+ - Plugin code can now ask for the module-loader service instead of touching the host module API: it exposes the same `createRequire`/`isBuiltin` surface as the host module module, and the Node engine supplies it automatically. Plugins that declare their environment through the engine's plugin declaration get the service without extra wiring; upgrades should move the engine and its plugins in the same release.
20
+
21
+ ### Patch Changes
22
+
23
+ - Refreshed builds on the platform-services dependency graph; the packages no longer reach for host builtins directly. No CLI flags or option names change.
24
+
25
+ - Updated dependencies:
26
+ - @systemfsoftware/stryker-js@0.2.0
27
+
3
28
  ## 2.0.2
4
29
 
5
30
  ### Patch Changes
package/dist/index.mjs CHANGED
@@ -2,89 +2,66 @@ import { RunConfiguration, SandboxDirectory, declarePlugin } from "@systemfsoftw
2
2
  import * as Effect$1 from "effect/Effect";
3
3
  import * as Layer from "effect/Layer";
4
4
  import * as S from "effect/Schema";
5
- import { createRequire } from "module";
6
- import { pathToFileURL } from "node:url";
7
- import path from "path";
8
- import { fileURLToPath } from "url";
9
5
  import { createVitest } from "vitest/node";
10
6
  import { Cell, Workflow } from "@systemfsoftware/effect-cell-types";
7
+ import { Module } from "@systemfsoftware/stryker-js/Module";
11
8
  import { INSTRUMENTER_CONSTANTS, errorToString, normalizeFileName } from "@systemfsoftware/stryker-js/Mutant";
12
9
  import { TestRunner, TestRunnerFailed, testFilesProvided } from "@systemfsoftware/stryker-js/TestRunner";
10
+ import * as Context from "effect/Context";
13
11
  import * as FileSystem from "effect/FileSystem";
14
- import { pipe } from "effect/Function";
12
+ import * as Match from "effect/Match";
15
13
  import * as Option from "effect/Option";
16
14
  import * as Path from "effect/Path";
17
15
  import * as Ref from "effect/Ref";
18
16
  import * as Result from "effect/Result";
19
17
  import { Effect } from "effect";
20
- import * as Match from "effect/Match";
21
- //#region src/Runner.schema.ts
22
- /**
23
- * Runner schemas — declarations for the vitest runner capability.
24
- *
25
- * Houses every Schema/Wire type this capability publishes or decodes
26
- * internally: option validation, coverage/task metadata, sandbox
27
- * manifest, and the dynamic vitest module shape.
28
- */
29
- /**
30
- * The `vitest` option section of the Stryker options document. `related`
31
- * defaults to `true` at decode, the other members are optional.
32
- */
33
- const VitestRunnerOptionsSchema = S.Struct({
34
- dir: S.optional(S.String),
35
- related: S.optional(S.Boolean).pipe(S.withDecodingDefault(Effect.succeed(true))),
36
- configFile: S.optional(S.String)
37
- });
38
- /**
39
- * The `vitest` section of the Stryker options document: absent from the input
40
- * document, or present as a partial, and decoded into the section defaults.
41
- */
42
- const VitestSectionSchema = S.optional(VitestRunnerOptionsSchema).pipe(S.withDecodingDefault(Effect.succeed({ related: true })));
43
- const HitCountMetaSchema = S.Struct({ hitCount: S.optional(S.Finite) });
44
- const MutantCoverageMetaSchema = S.Struct({ mutantCoverage: S.optional(S.Struct({
45
- static: S.Record(S.String, S.Finite),
46
- perTest: S.Record(S.String, S.Record(S.String, S.Finite))
47
- })) });
48
- const MutantCoverageShapeSchema = S.Struct({
49
- static: S.Record(S.String, S.Finite),
50
- perTest: S.Record(S.String, S.Record(S.String, S.Finite))
51
- });
52
- var CoverageDecodeFailed = class extends S.TaggedError()("CoverageDecodeFailed", { cause: S.Unknown }) {};
53
- const ExportEntry = S.Union([S.String, S.Record(S.String, S.Unknown)]);
54
- const PackageManifest = S.StructWithRest(S.Struct({
55
- name: S.optional(S.String),
56
- exports: S.optional(S.Record(S.String, ExportEntry))
57
- }), [S.Record(S.String, S.Unknown)]);
58
- /**
59
- * The dynamically imported project-local `vitest/node` module. The runtime
60
- * check only asserts object-likeness: the module namespace is whatever the
61
- * resolved package exports, and the consumers tolerate a missing
62
- * `createVitest` via their own fallbacks.
63
- */
64
- const VitestNodeModuleSchema = S.declare((input) => input !== null && typeof input === "object" && !Array.isArray(input), { description: "The project-local vitest/node module" });
65
- /** The `package.json` document of a resolved vitest package. */
66
- const VitestPackageSchema = S.Struct({ version: S.String });
67
- //#endregion
68
- //#region src/VitestDryRun.workflow.ts
69
- /**
70
- * VitestDryRun workflow — pure result-mapping for the dry-run phase.
71
- *
72
- * Every function here is pure: it maps raw vitest task payloads to
73
- * Stryker run results without touching the filesystem or spawning
74
- * processes. Impure orchestration lives in `Runner.ts`.
75
- */
18
+ //#region src/interpret-vitest-run.workflow.ts
19
+ var VitestMutantRunCommand = class extends S.TaggedClass()("VitestMutantRunCommand", {
20
+ rawTests: S.Array(S.Unknown),
21
+ projectRoot: S.String,
22
+ hasExternalError: S.Boolean,
23
+ externalErrorText: S.String,
24
+ hitCount: S.optional(S.Finite),
25
+ hitLimit: S.optional(S.Finite),
26
+ reportAllKillers: S.Boolean
27
+ }) {};
28
+ const VitestMutantRunTypeId = Symbol.for("@systemfsoftware/stryker-js-vitest-runner/VitestMutantRun");
29
+ var MutantKilled = class extends S.TaggedClass()("Killed", {
30
+ testsJson: S.String,
31
+ killerIds: S.optional(S.Array(S.String)),
32
+ failureMessage: S.optional(S.String)
33
+ }) {
34
+ [VitestMutantRunTypeId] = VitestMutantRunTypeId;
35
+ };
36
+ var MutantSurvived = class extends S.TaggedClass()("Survived", { testsJson: S.String }) {
37
+ [VitestMutantRunTypeId] = VitestMutantRunTypeId;
38
+ };
39
+ var MutantTimeout = class extends S.TaggedClass()("Timeout", {
40
+ testsJson: S.String,
41
+ reason: S.optional(S.String)
42
+ }) {
43
+ [VitestMutantRunTypeId] = VitestMutantRunTypeId;
44
+ };
45
+ var MutantDryError = class extends S.TaggedClass()("Error", {
46
+ testsJson: S.String,
47
+ errorMessage: S.optional(S.String)
48
+ }) {
49
+ [VitestMutantRunTypeId] = VitestMutantRunTypeId;
50
+ };
51
+ var VitestMutantRunError = class extends S.TaggedError()("VitestMutantRunError", { message: S.String }) {
52
+ [VitestMutantRunTypeId] = VitestMutantRunTypeId;
53
+ };
76
54
  var VitestDryRunCommand$1 = class extends S.TaggedClass()("VitestDryRunCommand", {
77
55
  rawTests: S.Array(S.Unknown),
78
56
  projectRoot: S.String,
79
57
  hasExternalError: S.Boolean,
80
58
  externalErrorText: S.String
81
59
  }) {};
82
- var VitestDryRunOutput$1 = class extends S.TaggedClass()("VitestDryRunOutput", {
60
+ var VitestDryRunOutput = class extends S.TaggedClass()("VitestDryRunOutput", {
83
61
  status: S.Literals(["Complete", "Error"]),
84
62
  testsJson: S.String,
85
63
  errorMessage: S.optional(S.String)
86
64
  }) {};
87
- S.TaggedError()("VitestDryRunError", { message: S.String });
88
65
  const recordOption$1 = (value) => S.decodeUnknownOption(S.Record(S.String, S.Unknown))(value);
89
66
  const getStringField$1 = (record, key) => Option.fromNullishOr(record[key]).pipe(Option.filter((v) => typeof v === "string"));
90
67
  const getNumberField$1 = (record, key) => Option.fromNullishOr(record[key]).pipe(Option.filter((v) => typeof v === "number"));
@@ -133,12 +110,6 @@ const toRawTestIdRaw$1 = (test) => {
133
110
  onSome: (file) => Option.getOrElse(Option.fromNullishOr(getFilepath$1(file)), () => "unknown.js")
134
111
  })}#${collectTestNameRaw$1(test)}`;
135
112
  };
136
- /**
137
- * A test id is `<file>#<test name>`, and the file is reported relative to the
138
- * project root so an id is stable across machines and sandbox directories.
139
- * Vitest reports an absolute path, so the root prefix is stripped here rather
140
- * than resolved — a decision body has no path service and needs none.
141
- */
142
113
  const normalizeTestIdRaw$1 = (id, projectRoot) => {
143
114
  const hash = id.indexOf("#");
144
115
  if (hash === -1) return id;
@@ -223,65 +194,146 @@ const convertTestRaw$1 = (test, projectRoot) => {
223
194
  status
224
195
  })));
225
196
  };
226
- const decideVitestDryRun$1 = (command) => {
227
- const tests = command.rawTests.map((t) => convertTestRaw$1(t, command.projectRoot));
228
- const hasFailure = tests.some((t) => t.status === "failed");
229
- return Match.value({
230
- hasFailure,
231
- hasExternalError: command.hasExternalError
232
- }).pipe(Match.when({
233
- hasFailure: false,
234
- hasExternalError: true
235
- }, () => Result.succeed(VitestDryRunOutput$1.make({
236
- status: "Error",
237
- testsJson: JSON.stringify(tests),
238
- errorMessage: `An error occurred outside of a test run: ${command.externalErrorText}`
239
- }))), Match.orElse(() => Result.succeed(VitestDryRunOutput$1.make({
240
- status: "Complete",
241
- testsJson: JSON.stringify(tests),
242
- errorMessage: void 0
243
- }))));
197
+ const decideVitestDryRun$1 = (command) => Match.value(command.rawTests.map((t) => convertTestRaw$1(t, command.projectRoot))).pipe(Match.when((tests) => tests.some((t) => t.status === "failed") === false && command.hasExternalError === true, (tests) => Result.succeed(VitestDryRunOutput.make({
198
+ status: "Error",
199
+ testsJson: JSON.stringify(tests),
200
+ errorMessage: `An error occurred outside of a test run: ${command.externalErrorText}`
201
+ }))), Match.orElse((tests) => Result.succeed(VitestDryRunOutput.make({
202
+ status: "Complete",
203
+ testsJson: JSON.stringify(tests),
204
+ errorMessage: void 0
205
+ }))));
206
+ const hitLimitReason = (hitCount, hitLimit) => {
207
+ if (hitCount === void 0 || hitLimit === void 0) return Option.none();
208
+ if (hitCount > hitLimit) return Option.some(`Hit limit reached (${hitCount}/${hitLimit})`);
209
+ return Option.none();
244
210
  };
245
- const vitestDryRunWorkflow = Workflow.make(VitestDryRunCommand$1, decideVitestDryRun$1);
211
+ const decideVitestMutantRun = (command) => Match.value(hitLimitReason(command.hitCount, command.hitLimit)).pipe(Match.when(Option.isSome, (hit) => Result.succeed(MutantTimeout.make({
212
+ testsJson: "[]",
213
+ reason: hit.value
214
+ }))), Match.when(Option.isNone, () => {
215
+ const dryOut = decideVitestDryRun$1(VitestDryRunCommand$1.make({
216
+ rawTests: command.rawTests,
217
+ projectRoot: command.projectRoot,
218
+ hasExternalError: command.hasExternalError,
219
+ externalErrorText: command.externalErrorText
220
+ }));
221
+ return Match.value(Result.isFailure(dryOut)).pipe(Match.when(true, () => Result.fail(new VitestMutantRunError({ message: "dry run mapping failed" }))), Match.when(false, () => {
222
+ const dry = Result.getOrElse(dryOut, () => VitestDryRunOutput.make({
223
+ status: "Complete",
224
+ testsJson: "[]",
225
+ errorMessage: void 0
226
+ }));
227
+ return Match.value(dry.status === "Error").pipe(Match.when(true, () => Result.succeed(MutantDryError.make({
228
+ testsJson: "[]",
229
+ errorMessage: dry.errorMessage
230
+ }))), Match.when(false, () => {
231
+ const testsOption = Option.liftThrowable((input) => JSON.parse(input))(dry.testsJson).pipe(Option.filter((v) => Array.isArray(v)));
232
+ const killed = Option.getOrElse(testsOption, () => []).filter((t) => t.status === "failed");
233
+ return Match.value(killed.length > 0).pipe(Match.when(true, () => Match.value(command.reportAllKillers).pipe(Match.when(true, () => {
234
+ const firstKiller = Option.fromNullishOr(killed[0]);
235
+ const failureMessage = Option.match(firstKiller, {
236
+ onNone: () => void 0,
237
+ onSome: (k) => k.failureMessage
238
+ });
239
+ return Result.succeed(MutantKilled.make({
240
+ testsJson: dry.testsJson,
241
+ killerIds: killed.map((t) => t.id),
242
+ failureMessage
243
+ }));
244
+ }), Match.when(false, () => {
245
+ const first = Option.fromNullishOr(killed[0]);
246
+ const failureMessage = Option.match(first, {
247
+ onNone: () => void 0,
248
+ onSome: (k) => k.failureMessage
249
+ });
250
+ return Match.value(Option.isSome(first)).pipe(Match.when(true, () => Result.succeed(MutantKilled.make({
251
+ testsJson: dry.testsJson,
252
+ killerIds: Option.match(first, {
253
+ onNone: () => void 0,
254
+ onSome: (k) => [k.id]
255
+ }),
256
+ failureMessage
257
+ }))), Match.when(false, () => Result.succeed(MutantKilled.make({
258
+ testsJson: dry.testsJson,
259
+ killerIds: Option.getOrUndefined(Option.match(first, {
260
+ onNone: () => Option.none(),
261
+ onSome: (k) => Option.some([k.id])
262
+ })),
263
+ failureMessage
264
+ }))), Match.exhaustive);
265
+ }), Match.exhaustive)), Match.when(false, () => Result.succeed(MutantSurvived.make({ testsJson: dry.testsJson }))), Match.exhaustive);
266
+ }), Match.exhaustive);
267
+ }), Match.exhaustive);
268
+ }), Match.exhaustive);
269
+ const interpretVitestRun = Workflow.make(VitestMutantRunCommand, decideVitestMutantRun);
246
270
  //#endregion
247
- //#region src/VitestMutantRun.workflow.ts
248
- /**
249
- * VitestMutantRun workflow — pure result-mapping for the mutant-run phase.
250
- */
251
- var VitestMutantRunCommand = class extends S.TaggedClass()("VitestMutantRunCommand", {
252
- rawTests: S.Array(S.Unknown),
253
- projectRoot: S.String,
254
- hasExternalError: S.Boolean,
255
- externalErrorText: S.String,
256
- hitCount: S.optional(S.Finite),
257
- hitLimit: S.optional(S.Finite),
258
- reportAllKillers: S.Boolean
259
- }) {};
260
- var VitestMutantRunOutput = class extends S.TaggedClass()("VitestMutantRunOutput", {
261
- status: S.Literals([
262
- "Killed",
263
- "Survived",
264
- "Timeout",
265
- "Error"
266
- ]),
267
- testsJson: S.String,
268
- errorMessage: S.optional(S.String),
269
- killerIds: S.optional(S.Array(S.String)),
270
- failureMessage: S.optional(S.String),
271
- reason: S.optional(S.String)
272
- }) {};
273
- var VitestMutantRunError = class extends S.TaggedError()("VitestMutantRunError", { message: S.String }) {};
271
+ //#region src/Runner.schema.ts
272
+ const VitestRunnerOptionsSchema = S.Struct({
273
+ dir: S.optional(S.String),
274
+ related: S.optional(S.Boolean).pipe(S.withDecodingDefault(Effect.succeed(true))),
275
+ configFile: S.optional(S.String)
276
+ });
277
+ const VitestSectionSchema = S.optional(VitestRunnerOptionsSchema).pipe(S.withDecodingDefault(Effect.succeed({ related: true })));
278
+ const HitCountMetaSchema = S.Struct({ hitCount: S.optional(S.Finite) });
279
+ const MutantCoverageMetaSchema = S.Struct({ mutantCoverage: S.optional(S.Struct({
280
+ static: S.Record(S.String, S.Finite),
281
+ perTest: S.Record(S.String, S.Record(S.String, S.Finite))
282
+ })) });
283
+ const MutantCoverageShapeSchema = S.Struct({
284
+ static: S.Record(S.String, S.Finite),
285
+ perTest: S.Record(S.String, S.Record(S.String, S.Finite))
286
+ });
287
+ var CoverageDecodeFailed = class extends S.TaggedError()("CoverageDecodeFailed", { cause: S.Unknown }) {};
288
+ const ExportEntry = S.Union([S.String, S.Record(S.String, S.Unknown)]);
289
+ const PackageManifest = S.StructWithRest(S.Struct({
290
+ name: S.optional(S.String),
291
+ exports: S.optional(S.Record(S.String, ExportEntry))
292
+ }), [S.Record(S.String, S.Unknown)]);
293
+ const VitestNodeModuleSchema = S.declare((input) => input !== null && typeof input === "object" && !Array.isArray(input), { description: "The project-local vitest/node module" });
294
+ const VitestPackageSchema = S.Struct({ version: S.String });
274
295
  var VitestDryRunCommand = class extends S.TaggedClass()("VitestDryRunCommand", {
275
296
  rawTests: S.Array(S.Unknown),
276
297
  projectRoot: S.String,
277
298
  hasExternalError: S.Boolean,
278
299
  externalErrorText: S.String
279
300
  }) {};
280
- var VitestDryRunOutput = class extends S.TaggedClass()("VitestDryRunOutput", {
281
- status: S.Literals(["Complete", "Error"]),
301
+ var DryRunComplete = class extends S.TaggedClass()("Complete", { testsJson: S.String }) {};
302
+ var DryRunExternalError = class extends S.TaggedClass()("Error", {
282
303
  testsJson: S.String,
283
- errorMessage: S.optional(S.String)
304
+ errorMessage: S.String
284
305
  }) {};
306
+ //#endregion
307
+ //#region src/Runner.ts
308
+ var VitestHarness = class extends Context.Service()("VitestHarness") {};
309
+ function fromTestId(id) {
310
+ const [file, ...name] = id.split("#");
311
+ return {
312
+ file,
313
+ test: name.join("#")
314
+ };
315
+ }
316
+ function normalizeTestId(id, projectRoot, pathService) {
317
+ const { file, test } = fromTestId(id);
318
+ return `${normalizeFileName(pathService.relative(projectRoot, file))}#${test}`;
319
+ }
320
+ function normalizeCoverage(rawCoverage, projectRoot, pathService) {
321
+ return {
322
+ perTest: Object.fromEntries(Object.entries(rawCoverage.perTest).map(([rawTestId, coverageData]) => [normalizeTestId(rawTestId, projectRoot, pathService), coverageData])),
323
+ static: rawCoverage.static
324
+ };
325
+ }
326
+ function collectTestsFromSuite(suite) {
327
+ return suite.tasks.flatMap((task) => {
328
+ if (task.type === "suite") return collectTestsFromSuite(task);
329
+ return task;
330
+ });
331
+ }
332
+ function isErrorCodeError(error) {
333
+ if (error instanceof Error && "code" in error) return typeof Reflect.get(error, "code") === "string";
334
+ return false;
335
+ }
336
+ const VITEST_ERROR_CODES = Object.freeze({ FILES_NOT_FOUND: "VITEST_FILES_NOT_FOUND" });
285
337
  const recordOption = (value) => S.decodeUnknownOption(S.Record(S.String, S.Unknown))(value);
286
338
  const getStringField = (record, key) => Option.fromNullishOr(record[key]).pipe(Option.filter((v) => typeof v === "string"));
287
339
  const getNumberField = (record, key) => Option.fromNullishOr(record[key]).pipe(Option.filter((v) => typeof v === "number"));
@@ -330,12 +382,6 @@ const toRawTestIdRaw = (test) => {
330
382
  onSome: (file) => Option.getOrElse(Option.fromNullishOr(getFilepath(file)), () => "unknown.js")
331
383
  })}#${collectTestNameRaw(test)}`;
332
384
  };
333
- /**
334
- * A test id is `<file>#<test name>`, and the file is reported relative to the
335
- * project root so an id is stable across machines and sandbox directories.
336
- * Vitest reports an absolute path, so the root prefix is stripped here rather
337
- * than resolved — a decision body has no path service and needs none.
338
- */
339
385
  const normalizeTestIdRaw = (id, projectRoot) => {
340
386
  const hash = id.indexOf("#");
341
387
  if (hash === -1) return id;
@@ -420,134 +466,14 @@ const convertTestRaw = (test, projectRoot) => {
420
466
  status
421
467
  })));
422
468
  };
423
- const decideVitestDryRun = (command) => Match.value(command.rawTests.map((t) => convertTestRaw(t, command.projectRoot))).pipe(Match.when((tests) => tests.some((t) => t.status === "failed") === false && command.hasExternalError === true, (tests) => Result.succeed(VitestDryRunOutput.make({
424
- status: "Error",
425
- testsJson: JSON.stringify(tests),
426
- errorMessage: `An error occurred outside of a test run: ${command.externalErrorText}`
427
- }))), Match.orElse((tests) => Result.succeed(VitestDryRunOutput.make({
428
- status: "Complete",
429
- testsJson: JSON.stringify(tests),
430
- errorMessage: void 0
431
- }))));
432
- /**
433
- * The hit-limit cutoff: `Some` iff both numbers are present AND the count
434
- * strictly exceeds the limit. The boundary is `>` and not `>=` on purpose —
435
- * `hitCount === hitLimit` is the last permitted hit, not one too many.
436
- */
437
- const hitLimitReason = (hitCount, hitLimit) => {
438
- if (hitCount === void 0 || hitLimit === void 0) return Option.none();
439
- if (hitCount > hitLimit) return Option.some(`Hit limit reached (${hitCount}/${hitLimit})`);
440
- return Option.none();
441
- };
442
- const decideVitestMutantRun = (command) => Match.value(hitLimitReason(command.hitCount, command.hitLimit)).pipe(Match.when(Option.isSome, (hit) => Result.succeed(VitestMutantRunOutput.make({
443
- status: "Timeout",
444
- testsJson: "[]",
445
- errorMessage: void 0,
446
- killerIds: void 0,
447
- failureMessage: void 0,
448
- reason: hit.value
449
- }))), Match.when(Option.isNone, () => {
450
- const dryOut = decideVitestDryRun(VitestDryRunCommand.make({
451
- rawTests: command.rawTests,
452
- projectRoot: command.projectRoot,
453
- hasExternalError: command.hasExternalError,
454
- externalErrorText: command.externalErrorText
455
- }));
456
- return Match.value(Result.isFailure(dryOut)).pipe(Match.when(true, () => Result.fail(new VitestMutantRunError({ message: "dry run mapping failed" }))), Match.when(false, () => {
457
- const dry = Result.getOrElse(dryOut, () => VitestDryRunOutput.make({
458
- status: "Complete",
459
- testsJson: "[]",
460
- errorMessage: void 0
461
- }));
462
- return Match.value(dry.status === "Error").pipe(Match.when(true, () => Result.succeed(VitestMutantRunOutput.make({
463
- status: "Error",
464
- testsJson: "[]",
465
- errorMessage: dry.errorMessage,
466
- killerIds: void 0,
467
- failureMessage: void 0
468
- }))), Match.when(false, () => {
469
- const testsOption = Option.liftThrowable((input) => JSON.parse(input))(dry.testsJson).pipe(Option.filter((v) => Array.isArray(v)));
470
- const killed = Option.getOrElse(testsOption, () => []).filter((t) => t.status === "failed");
471
- return Match.value(killed.length > 0).pipe(Match.when(true, () => Match.value(command.reportAllKillers).pipe(Match.when(true, () => {
472
- const firstKiller = Option.fromNullishOr(killed[0]);
473
- const failureMessage = Option.match(firstKiller, {
474
- onNone: () => void 0,
475
- onSome: (k) => k.failureMessage
476
- });
477
- return Result.succeed(VitestMutantRunOutput.make({
478
- status: "Killed",
479
- testsJson: dry.testsJson,
480
- errorMessage: void 0,
481
- killerIds: killed.map((t) => t.id),
482
- failureMessage
483
- }));
484
- }), Match.when(false, () => {
485
- const first = Option.fromNullishOr(killed[0]);
486
- const failureMessage = Option.match(first, {
487
- onNone: () => void 0,
488
- onSome: (k) => k.failureMessage
489
- });
490
- return Match.value(Option.isSome(first)).pipe(Match.when(true, () => Result.succeed(VitestMutantRunOutput.make({
491
- status: "Killed",
492
- testsJson: dry.testsJson,
493
- errorMessage: void 0,
494
- killerIds: Option.match(first, {
495
- onNone: () => void 0,
496
- onSome: (k) => [k.id]
497
- }),
498
- failureMessage
499
- }))), Match.when(false, () => Result.succeed(VitestMutantRunOutput.make({
500
- status: "Killed",
501
- testsJson: dry.testsJson,
502
- errorMessage: void 0,
503
- killerIds: Option.getOrUndefined(Option.match(first, {
504
- onNone: () => Option.none(),
505
- onSome: (k) => Option.some([k.id])
506
- })),
507
- failureMessage
508
- }))), Match.exhaustive);
509
- }), Match.exhaustive)), Match.when(false, () => Result.succeed(VitestMutantRunOutput.make({
510
- status: "Survived",
511
- testsJson: dry.testsJson,
512
- errorMessage: void 0,
513
- killerIds: void 0,
514
- failureMessage: void 0
515
- }))), Match.exhaustive);
516
- }), Match.exhaustive);
517
- }), Match.exhaustive);
518
- }), Match.exhaustive);
519
- const vitestMutantRunWorkflow = Workflow.make(VitestMutantRunCommand, decideVitestMutantRun);
520
- //#endregion
521
- //#region src/Runner.ts
522
- function fromTestId(id) {
523
- const [file, ...name] = id.split("#");
524
- return {
525
- file,
526
- test: name.join("#")
527
- };
528
- }
529
- function normalizeTestId(id, projectRoot, pathService) {
530
- const { file, test } = fromTestId(id);
531
- return `${normalizeFileName(pathService.relative(projectRoot, file))}#${test}`;
532
- }
533
- function normalizeCoverage(rawCoverage, projectRoot, pathService) {
534
- return {
535
- perTest: Object.fromEntries(Object.entries(rawCoverage.perTest).map(([rawTestId, coverageData]) => [normalizeTestId(rawTestId, projectRoot, pathService), coverageData])),
536
- static: rawCoverage.static
537
- };
538
- }
539
- function collectTestsFromSuite(suite) {
540
- return suite.tasks.flatMap((task) => {
541
- if (task.type === "suite") return collectTestsFromSuite(task);
542
- return task;
469
+ const decideVitestDryRun = (command) => {
470
+ const tests = command.rawTests.map((t) => convertTestRaw(t, command.projectRoot));
471
+ if (tests.some((t) => t.status === "failed") === false && command.hasExternalError) return DryRunExternalError.make({
472
+ testsJson: JSON.stringify(tests),
473
+ errorMessage: `An error occurred outside of a test run: ${command.externalErrorText}`
543
474
  });
544
- }
545
- function isErrorCodeError(error) {
546
- if (error instanceof Error && "code" in error) return typeof Reflect.get(error, "code") === "string";
547
- return false;
548
- }
549
- /** @see https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/node/errors.ts */
550
- const VITEST_ERROR_CODES = Object.freeze({ FILES_NOT_FOUND: "VITEST_FILES_NOT_FOUND" });
475
+ return DryRunComplete.make({ testsJson: JSON.stringify(tests) });
476
+ };
551
477
  const SOURCE_CONDITION = "@systemfsoftware/source";
552
478
  const sourceTargetOf = (entry) => {
553
479
  if (typeof entry === "string") return (() => {
@@ -595,12 +521,6 @@ const readSandboxSelfAliases = (projectRoot) => Effect$1.gen(function* () {
595
521
  onSome: (manifest) => sandboxSelfAliases(manifest, projectRoot, pathService)
596
522
  });
597
523
  });
598
- /**
599
- * Vite records a package specifier as a bare dep. Vitest related-mode then
600
- * joins that specifier onto the project root, misses the file, and reports
601
- * zero tests. Returning the sandbox source path from `resolveId` makes the
602
- * dep a real filesystem path related-mode can walk.
603
- */
604
524
  const sandboxSelfPlugin = (aliases) => ({
605
525
  name: "stryker-sandbox-self-exports",
606
526
  enforce: "pre",
@@ -608,27 +528,39 @@ const sandboxSelfPlugin = (aliases) => ({
608
528
  for (const alias of aliases) if (alias.find.test(source)) return alias.replacement;
609
529
  }
610
530
  });
611
- const readVitestVersion = (readPackageJson) => S.decodeUnknownSync(VitestPackageSchema)(readPackageJson()).version;
612
- /** Falls back to the Vitest bundled with this package when `dir` has none. */
613
- const resolveVitest = async (dir) => {
614
- try {
615
- const projectRequire = createRequire(path.join(dir, "package.json"));
616
- const vitestNodePath = projectRequire.resolve("vitest/node");
617
- const vitestNodeUrl = pathToFileURL(vitestNodePath).href;
531
+ const isRunnerTestSuite = (value) => typeof value === "object" && value !== null && "tasks" in value && Array.isArray(Reflect.get(value, "tasks"));
532
+ const STRYKER_SETUP_URL = new URL("./stryker-setup.mjs", import.meta.url);
533
+ const resolveVitest = (_dir) => Effect$1.gen(function* () {
534
+ const fallback = Effect$1.gen(function* () {
535
+ const pathService = yield* Path.Path;
536
+ const fs = yield* FileSystem.FileSystem;
537
+ const urlString = import.meta.resolve("vitest/package.json");
538
+ const packageJsonPath = yield* pathService.fromFileUrl(new URL(urlString));
539
+ const content = yield* fs.readFileString(packageJsonPath);
540
+ const parsed = JSON.parse(content);
541
+ const decoded = yield* S.decodeUnknownEffect(VitestPackageSchema)(parsed);
618
542
  return {
619
- createVitest: S.decodeUnknownSync(VitestNodeModuleSchema)(await import(vitestNodeUrl)).createVitest,
620
- version: readVitestVersion(() => projectRequire(projectRequire.resolve("vitest/package.json")))
543
+ createVitest,
544
+ version: decoded.version
621
545
  };
622
- } catch {
623
- const bundledRequire = createRequire(import.meta.url);
546
+ }).pipe(Effect$1.orDie);
547
+ return yield* Effect$1.gen(function* () {
548
+ const module = yield* Module;
549
+ const pathService = yield* Path.Path;
550
+ const fs = yield* FileSystem.FileSystem;
551
+ const requireFromProject = module.createRequire(pathService.join(_dir, "package.json"));
552
+ const imported = requireFromProject("vitest/node");
553
+ const decodedNode = yield* S.decodeUnknownEffect(VitestNodeModuleSchema)(imported);
554
+ const packageJsonPath = requireFromProject.resolve("vitest/package.json");
555
+ const content = yield* fs.readFileString(packageJsonPath);
556
+ const parsed = JSON.parse(content);
557
+ const decodedPackage = yield* S.decodeUnknownEffect(VitestPackageSchema)(parsed);
624
558
  return {
625
- createVitest,
626
- version: readVitestVersion(() => bundledRequire(bundledRequire.resolve("vitest/package.json")))
559
+ createVitest: decodedNode.createVitest,
560
+ version: decodedPackage.version
627
561
  };
628
- }
629
- };
630
- const isRunnerTestSuite = (value) => typeof value === "object" && value !== null && "tasks" in value && Array.isArray(Reflect.get(value, "tasks"));
631
- const STRYKER_SETUP = fileURLToPath(new URL("./stryker-setup.mjs", import.meta.url));
562
+ }).pipe(Effect$1.catchCause(() => fallback), Effect$1.catchDefect(() => fallback));
563
+ }).pipe(Effect$1.orDie);
632
564
  const shouldUseSuiteMetaSecondArg = (version) => {
633
565
  const parts = version.split(".");
634
566
  const major = Number(parts[0] ?? "0");
@@ -704,6 +636,7 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
704
636
  });
705
637
  const fsService = yield* FileSystem.FileSystem;
706
638
  const pathService = yield* Path.Path;
639
+ const moduleService = yield* Module;
707
640
  const getState = Ref.get(stateRef);
708
641
  const requireCtx = Effect$1.gen(function* () {
709
642
  const state = yield* getState;
@@ -739,20 +672,21 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
739
672
  ...s,
740
673
  localSetupFile
741
674
  }));
742
- yield* fsService.copyFile(input.setupFilePath ?? STRYKER_SETUP, localSetupFile).pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
675
+ const defaultSetupPath = yield* pathService.fromFileUrl(STRYKER_SETUP_URL).pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
743
676
  runnerName: "vitest",
744
677
  phase: "init",
745
678
  cause: errorToString(cause)
746
679
  })));
747
- const resolver = input.resolveVitestFor ?? resolveVitest;
748
- const { createVitest, version } = yield* Effect$1.tryPromise({
749
- try: () => resolver(projectRoot),
750
- catch: (cause) => new TestRunnerFailed({
751
- runnerName: "vitest",
752
- phase: "init",
753
- cause: errorToString(cause)
754
- })
755
- });
680
+ yield* fsService.copyFile(input.setupFilePath ?? defaultSetupPath, localSetupFile).pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
681
+ runnerName: "vitest",
682
+ phase: "init",
683
+ cause: errorToString(cause)
684
+ })));
685
+ const { createVitest, version } = yield* (input.resolveVitestFor ?? resolveVitest)(projectRoot).pipe(Effect$1.provideService(Module, moduleService), Effect$1.provideService(FileSystem.FileSystem, fsService), Effect$1.provideService(Path.Path, pathService), Effect$1.catchDefect((cause) => Effect$1.fail(new TestRunnerFailed({
686
+ runnerName: "vitest",
687
+ phase: "init",
688
+ cause: errorToString(cause)
689
+ }))));
756
690
  const namespace = input.globalNamespace ?? INSTRUMENTER_CONSTANTS.NAMESPACE;
757
691
  const scanDir = (() => {
758
692
  if (typeof options.vitest.dir === "string") return pathService.resolve(projectRoot, options.vitest.dir);
@@ -803,7 +737,7 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
803
737
  return new TestRunnerFailed({
804
738
  runnerName: "vitest",
805
739
  phase: "init",
806
- cause
740
+ cause: errorToString(cause)
807
741
  });
808
742
  })()));
809
743
  const resetContext = Effect$1.gen(function* () {
@@ -913,169 +847,173 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
913
847
  })()
914
848
  };
915
849
  });
916
- const dryRunDescription = pipe(Cell.read((command) => Effect$1.gen(function* () {
917
- (yield* requireCtx).provide("mode", "dry-run");
918
- const hasTestFiles = testFilesProvided(command);
850
+ const harnessImpl = {
851
+ setMode: (mode) => Effect$1.gen(function* () {
852
+ (yield* requireCtx).provide("mode", mode);
853
+ }),
854
+ provide: (key, value) => Effect$1.gen(function* () {
855
+ const ctx = yield* requireCtx;
856
+ if (key === "hitLimit") {
857
+ if (typeof value === "number" || value === void 0) ctx.provide("hitLimit", value);
858
+ else ctx.provide("hitLimit", void 0);
859
+ } else if (key === "mutantActivation") {
860
+ if (value === "runtime" || value === "static") ctx.provide("mutantActivation", value);
861
+ } else if (typeof value === "string") ctx.provide("activeMutant", value);
862
+ })
863
+ };
864
+ const mutantRunCell = Cell.layer({
865
+ read: (command) => Effect$1.gen(function* () {
866
+ const harness = yield* VitestHarness;
867
+ yield* harness.setMode("mutant");
868
+ yield* harness.provide("hitLimit", command.hitLimit);
869
+ yield* harness.provide("mutantActivation", command.mutantActivation);
870
+ yield* harness.provide("activeMutant", command.activeMutant.id);
871
+ const { rawTests, hasExternalError, externalErrorText } = yield* collectRaw({
872
+ testIds: (() => {
873
+ if (command.testFilter !== void 0) return [...command.testFilter];
874
+ })(),
875
+ relatedFiles: [command.sandboxFileName]
876
+ });
877
+ const hitCount = yield* readHitCount.pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
878
+ runnerName: "vitest",
879
+ phase: "mutantRun",
880
+ cause: errorToString(cause)
881
+ })), Effect$1.option, Effect$1.map(Option.getOrUndefined));
882
+ const reportAllKillers = (() => {
883
+ if (typeof input.options.disableBail === "boolean") return input.options.disableBail;
884
+ return false;
885
+ })();
886
+ if (hitCount === void 0) return {
887
+ rawTests,
888
+ projectRoot: input.sandboxDirectory,
889
+ hasExternalError,
890
+ externalErrorText,
891
+ hitLimit: command.hitLimit,
892
+ reportAllKillers
893
+ };
894
+ return {
895
+ rawTests,
896
+ projectRoot: input.sandboxDirectory,
897
+ hasExternalError,
898
+ externalErrorText,
899
+ hitCount,
900
+ hitLimit: command.hitLimit,
901
+ reportAllKillers
902
+ };
903
+ }),
904
+ decode: (raw) => {
905
+ const base = {
906
+ rawTests: raw.rawTests,
907
+ projectRoot: raw.projectRoot,
908
+ hasExternalError: raw.hasExternalError,
909
+ externalErrorText: raw.externalErrorText,
910
+ reportAllKillers: raw.reportAllKillers
911
+ };
912
+ if (raw.hitCount !== void 0) {
913
+ if (raw.hitLimit !== void 0) return Result.succeed(new VitestMutantRunCommand({
914
+ ...base,
915
+ hitCount: raw.hitCount,
916
+ hitLimit: raw.hitLimit
917
+ }));
918
+ return Result.succeed(new VitestMutantRunCommand({
919
+ ...base,
920
+ hitCount: raw.hitCount
921
+ }));
922
+ }
923
+ if (raw.hitLimit !== void 0) return Result.succeed(new VitestMutantRunCommand({
924
+ ...base,
925
+ hitLimit: raw.hitLimit
926
+ }));
927
+ return Result.succeed(new VitestMutantRunCommand(base));
928
+ },
929
+ decide: interpretVitestRun,
930
+ encode: (outcome) => Result.match(outcome, {
931
+ onFailure: (e) => ({
932
+ status: "error",
933
+ errorMessage: e.message
934
+ }),
935
+ onSuccess: (out) => {
936
+ const nrOfTests = () => {
937
+ try {
938
+ const raw = JSON.parse(out.testsJson);
939
+ if (Array.isArray(raw)) return raw.filter(isIdRecord).length;
940
+ return 0;
941
+ } catch {
942
+ return 0;
943
+ }
944
+ };
945
+ return Match.value(out).pipe(Match.tag("Error", (error) => ({
946
+ status: "error",
947
+ errorMessage: error.errorMessage ?? "unknown"
948
+ })), Match.tag("Timeout", (timeout) => (() => {
949
+ if (timeout.reason === void 0) return { status: "timeout" };
950
+ return {
951
+ status: "timeout",
952
+ reason: timeout.reason
953
+ };
954
+ })()), Match.tag("Killed", (killed) => ({
955
+ status: "killed",
956
+ failureMessage: killed.failureMessage ?? "",
957
+ killedBy: (() => {
958
+ if (killed.killerIds !== void 0) return [...killed.killerIds];
959
+ return [];
960
+ })(),
961
+ nrOfTests: nrOfTests()
962
+ })), Match.tag("Survived", () => ({
963
+ status: "survived",
964
+ nrOfTests: nrOfTests()
965
+ })), Match.exhaustive);
966
+ }
967
+ }),
968
+ write: (output, _raw) => Effect$1.succeed(output)
969
+ });
970
+ const dryRun = (options) => Effect$1.gen(function* () {
971
+ yield* (yield* VitestHarness).setMode("dry-run");
972
+ const hasTestFiles = testFilesProvided(options);
919
973
  const filter = (() => {
920
974
  if (hasTestFiles) return {
921
- testFiles: [...command.testFiles ?? []],
975
+ testFiles: [...options.testFiles ?? []],
922
976
  relatedFiles: (() => {
923
- if (command.files !== void 0) return [...command.files];
977
+ if (options.files !== void 0) return [...options.files];
924
978
  })()
925
979
  };
926
980
  return { relatedFiles: (() => {
927
- if (command.files !== void 0) return [...command.files];
981
+ if (options.files !== void 0) return [...options.files];
928
982
  })() };
929
983
  })();
930
984
  const { rawTests, hasExternalError, externalErrorText } = yield* collectRaw(filter);
931
- return {
985
+ const decision = decideVitestDryRun(new VitestDryRunCommand({
932
986
  rawTests,
933
987
  projectRoot: input.sandboxDirectory,
934
988
  hasExternalError,
935
989
  externalErrorText
936
- };
937
- })), Cell.decode((raw) => Result.succeed(new VitestDryRunCommand$1({
938
- rawTests: raw.rawTests,
939
- projectRoot: raw.projectRoot,
940
- hasExternalError: raw.hasExternalError,
941
- externalErrorText: raw.externalErrorText
942
- }))), Cell.decide(vitestDryRunWorkflow), Cell.encode((outcome) => Result.match(outcome, {
943
- onFailure: (e) => ({
990
+ }));
991
+ const result = Match.value(decision).pipe(Match.tag("Error", (error) => ({
944
992
  status: "error",
945
- errorMessage: e.message
946
- }),
947
- onSuccess: (out) => {
948
- const raw = JSON.parse(out.testsJson);
993
+ errorMessage: error.errorMessage
994
+ })), Match.tag("Complete", (complete) => {
995
+ const raw = JSON.parse(complete.testsJson);
949
996
  let tests;
950
997
  if (Array.isArray(raw)) tests = raw.filter(isTestResultLike);
951
998
  else tests = [];
952
- if (out.status === "Error") return {
953
- status: "error",
954
- errorMessage: out.errorMessage ?? "unknown"
955
- };
956
999
  return {
957
1000
  status: "complete",
958
1001
  tests
959
1002
  };
960
- }
961
- })), Cell.write((output) => Effect$1.gen(function* () {
962
- if (output.status === "complete") {
1003
+ }), Match.exhaustive);
1004
+ if (result.status === "complete") {
963
1005
  const mutantCoverage = yield* readMutantCoverage.pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
964
1006
  runnerName: "vitest",
965
1007
  phase: "dryRun",
966
1008
  cause: errorToString(cause)
967
1009
  })));
968
1010
  if (mutantCoverage !== void 0) return {
969
- ...output,
1011
+ ...result,
970
1012
  mutantCoverage
971
1013
  };
972
1014
  }
973
- return output;
974
- })));
975
- const mutantRunDescription = pipe(Cell.read((command) => Effect$1.gen(function* () {
976
- const ctx = yield* requireCtx;
977
- ctx.provide("mode", "mutant");
978
- ctx.provide("hitLimit", command.hitLimit);
979
- ctx.provide("mutantActivation", command.mutantActivation);
980
- ctx.provide("activeMutant", command.activeMutant.id);
981
- const { rawTests, hasExternalError, externalErrorText } = yield* collectRaw({
982
- testIds: (() => {
983
- if (command.testFilter !== void 0) return [...command.testFilter];
984
- })(),
985
- relatedFiles: [command.sandboxFileName]
986
- });
987
- const hitCount = yield* readHitCount.pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
988
- runnerName: "vitest",
989
- phase: "mutantRun",
990
- cause: errorToString(cause)
991
- })), Effect$1.option, Effect$1.map(Option.getOrUndefined));
992
- const reportAllKillers = (() => {
993
- if (typeof input.options.disableBail === "boolean") return input.options.disableBail;
994
- return false;
995
- })();
996
- if (hitCount === void 0) return {
997
- rawTests,
998
- projectRoot: input.sandboxDirectory,
999
- hasExternalError,
1000
- externalErrorText,
1001
- hitLimit: command.hitLimit,
1002
- reportAllKillers
1003
- };
1004
- return {
1005
- rawTests,
1006
- projectRoot: input.sandboxDirectory,
1007
- hasExternalError,
1008
- externalErrorText,
1009
- hitCount,
1010
- hitLimit: command.hitLimit,
1011
- reportAllKillers
1012
- };
1013
- })), Cell.decode((raw) => {
1014
- const base = {
1015
- rawTests: raw.rawTests,
1016
- projectRoot: raw.projectRoot,
1017
- hasExternalError: raw.hasExternalError,
1018
- externalErrorText: raw.externalErrorText,
1019
- reportAllKillers: raw.reportAllKillers
1020
- };
1021
- if (raw.hitCount !== void 0) {
1022
- if (raw.hitLimit !== void 0) return Result.succeed(new VitestMutantRunCommand({
1023
- ...base,
1024
- hitCount: raw.hitCount,
1025
- hitLimit: raw.hitLimit
1026
- }));
1027
- return Result.succeed(new VitestMutantRunCommand({
1028
- ...base,
1029
- hitCount: raw.hitCount
1030
- }));
1031
- }
1032
- if (raw.hitLimit !== void 0) return Result.succeed(new VitestMutantRunCommand({
1033
- ...base,
1034
- hitLimit: raw.hitLimit
1035
- }));
1036
- return Result.succeed(new VitestMutantRunCommand(base));
1037
- }), Cell.decide(vitestMutantRunWorkflow), Cell.encode((outcome) => Result.match(outcome, {
1038
- onFailure: (e) => ({
1039
- status: "error",
1040
- errorMessage: e.message
1041
- }),
1042
- onSuccess: (out) => {
1043
- let parsed;
1044
- try {
1045
- const raw = JSON.parse(out.testsJson);
1046
- if (Array.isArray(raw)) parsed = raw.filter(isIdRecord);
1047
- else parsed = [];
1048
- } catch {
1049
- parsed = [];
1050
- }
1051
- const nrOfTests = parsed.length;
1052
- if (out.status === "Error") return {
1053
- status: "error",
1054
- errorMessage: out.errorMessage ?? "unknown"
1055
- };
1056
- if (out.status === "Timeout") {
1057
- if (out.reason === void 0) return { status: "timeout" };
1058
- return {
1059
- status: "timeout",
1060
- reason: out.reason
1061
- };
1062
- }
1063
- if (out.status === "Killed") return {
1064
- status: "killed",
1065
- failureMessage: out.failureMessage ?? "",
1066
- killedBy: (() => {
1067
- if (out.killerIds !== void 0) return [...out.killerIds];
1068
- return [];
1069
- })(),
1070
- nrOfTests
1071
- };
1072
- return {
1073
- status: "survived",
1074
- nrOfTests
1075
- };
1076
- }
1077
- })), Cell.write((output) => Effect$1.succeed(output)));
1078
- const dryRun = (options) => Cell.apply(dryRunDescription, options).pipe(Effect$1.mapError((cause) => (() => {
1015
+ return result;
1016
+ }).pipe(Effect$1.provideService(VitestHarness, harnessImpl), Effect$1.mapError((cause) => (() => {
1079
1017
  if (cause instanceof TestRunnerFailed) return cause;
1080
1018
  return new TestRunnerFailed({
1081
1019
  runnerName: "vitest",
@@ -1083,7 +1021,7 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
1083
1021
  cause: errorToString(cause)
1084
1022
  });
1085
1023
  })()));
1086
- const mutantRun = (options) => Cell.apply(mutantRunDescription, options).pipe(Effect$1.mapError((cause) => (() => {
1024
+ const mutantRun = (options) => Cell.run(mutantRunCell, options).pipe(Effect$1.provideService(VitestHarness, harnessImpl), Effect$1.mapError((cause) => (() => {
1087
1025
  if (cause instanceof TestRunnerFailed) return cause;
1088
1026
  return new TestRunnerFailed({
1089
1027
  runnerName: "vitest",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@systemfsoftware/stryker-js-vitest-runner",
3
- "version": "2.0.2",
3
+ "version": "3.0.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/systemfsoftware/systemfsoftware.git",
@@ -31,8 +31,8 @@
31
31
  "coverageAnalysis": "perTest"
32
32
  },
33
33
  "dependencies": {
34
- "@systemfsoftware/effect-cell-types": "^5.0.2",
35
- "@systemfsoftware/stryker-js": "^0.1.1"
34
+ "@systemfsoftware/stryker-js": "^1.0.0",
35
+ "@systemfsoftware/effect-cell-types": "^6.0.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "effect": "^4.0.0-rc.112",
@@ -50,7 +50,7 @@
50
50
  "tsdown": "^0.22.14",
51
51
  "typescript": "^7",
52
52
  "vitest": "^4",
53
- "@systemfsoftware/all": "^1.0.2",
53
+ "@systemfsoftware/all": "^1.1.2",
54
54
  "@systemfsoftware/effect-gherkin-spec": "^4.0.0",
55
55
  "@systemfsoftware/oxlint-config": "^0.1.0",
56
56
  "@systemfsoftware/tsconfig": "^1.3.3",