@systemfsoftware/stryker-js 5.0.0 → 6.1.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.
@@ -1,37 +1,42 @@
1
+ import { A as formatTraceparent, C as TestRunnerFailed, D as WorkerEntryUrl, E as TraceContextReference, M as parseTraceparent, N as toMutantRunResult, O as WorkerPluginKind, P as INSTRUMENTER_CONSTANTS, T as TraceContextMiddleware, b as TRACEPARENT_HEADER, f as PropagatedTrace, j as isCustomTestRunner, w as TestRunnerRpcs, x as TRACESTATE_HEADER, y as StrykerOptionsSchema } from "./dist-CWbipfGB.mjs";
1
2
  import { t as mergeConfig } from "./merge-config-BrrNQWje.mjs";
2
- import * as Effect from "effect/Effect";
3
+ import * as Effect$1 from "effect/Effect";
3
4
  import * as FileSystem from "effect/FileSystem";
4
5
  import * as Path from "effect/Path";
5
- import { StrykerOptionsSchema, TestRunnerFailed, TestRunnerRpcs, WorkerEntryUrl, WorkerPluginKind, toMutantRunResult } from "@systemfsoftware/stryker-js-plugin-interface";
6
+ import * as Predicate from "effect/Predicate";
7
+ import * as S from "effect/Schema";
8
+ import * as Match from "effect/Match";
9
+ import * as Option from "effect/Option";
10
+ import * as Context from "effect/Context";
11
+ import * as RpcMiddleware from "effect/unstable/rpc/RpcMiddleware";
12
+ import { Schema } from "effect";
6
13
  import * as Clock from "effect/Clock";
7
14
  import * as Config from "effect/Config";
8
- import * as Context from "effect/Context";
9
15
  import * as Layer from "effect/Layer";
10
- import * as Match from "effect/Match";
11
- import * as Option from "effect/Option";
12
16
  import * as Result from "effect/Result";
13
- import * as S from "effect/Schema";
14
17
  import * as Stream from "effect/Stream";
15
- import { INSTRUMENTER_CONSTANTS } from "@systemfsoftware/stryker-js-instrumenter/mutants";
16
18
  import * as Array$1 from "effect/Array";
17
19
  import * as Cause from "effect/Cause";
18
20
  import "effect/Exit";
19
- import * as Predicate from "effect/Predicate";
20
21
  import * as Duration from "effect/Duration";
21
- import { Schema } from "effect";
22
22
  import * as HashMap from "effect/HashMap";
23
23
  import * as HashSet from "effect/HashSet";
24
- import { Minimatch } from "minimatch";
25
- import { encodeWorkerOptions, layerTraceContextClient } from "@systemfsoftware/stryker-js-plugin-runtime";
24
+ import * as api from "@opentelemetry/api";
25
+ import * as Tracer from "effect/Tracer";
26
+ import * as Headers from "effect/unstable/http/Headers";
27
+ import { NodeFileSystem, NodePath, NodeSocket, NodeStdio } from "@effect/platform-node";
28
+ import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
29
+ import "effect/unstable/rpc/RpcServer";
30
+ import * as NodeSdk from "@effect/opentelemetry/NodeSdk";
31
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
32
+ import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
26
33
  import * as Ref from "effect/Ref";
27
34
  import * as ChildProcess from "effect/unstable/process/ChildProcess";
28
35
  import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
29
- import { NodeFileSystem, NodePath, NodeSocket, NodeStdio } from "@effect/platform-node";
30
36
  import * as NodeChildProcessSpawner from "@effect/platform-node-shared/NodeChildProcessSpawner";
31
37
  import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto";
32
38
  import * as Crypto from "effect/Crypto";
33
39
  import * as RpcClient from "effect/unstable/rpc/RpcClient";
34
- import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
35
40
  import * as Schedule from "effect/Schedule";
36
41
  //#region src/Run.schema.ts
37
42
  const TypeId = "~stryker/mutation-run/StageError";
@@ -83,6 +88,42 @@ var PrepareError = class extends S.TaggedError()("PrepareError", {
83
88
  reason: S.String
84
89
  }) {};
85
90
  //#endregion
91
+ //#region src/glob-match.ts
92
+ const GLOB_META = /[*?[{]/;
93
+ const isGlob = (value) => GLOB_META.test(value);
94
+ const escapeRegex = (value) => value.replace(/[\\^$.|()+]/g, "\\$&");
95
+ const globSegmentToRegex = (segment) => Match.value(segment.length === 0).pipe(Match.when(true, () => ""), Match.orElse(() => {
96
+ const char = segment[0] ?? "";
97
+ const rest = segment.slice(1);
98
+ return Match.value(char).pipe(Match.when("*", () => Match.value(rest.startsWith("*")).pipe(Match.when(true, () => {
99
+ const afterStars = rest.slice(1);
100
+ return Match.value(afterStars.startsWith("/")).pipe(Match.when(true, () => `(?:(?:[^/]+/)*)?${globSegmentToRegex(afterStars.slice(1))}`), Match.orElse(() => `.*${globSegmentToRegex(afterStars)}`));
101
+ }), Match.orElse(() => `[^/]*${globSegmentToRegex(rest)}`))), Match.when("?", () => `[^/]${globSegmentToRegex(rest)}`), Match.when("{", () => {
102
+ const close = segment.indexOf("}");
103
+ return Match.value(close < 0).pipe(Match.when(true, () => `${escapeRegex(char)}${globSegmentToRegex(rest)}`), Match.orElse(() => {
104
+ const inner = segment.slice(1, close);
105
+ const after = segment.slice(close + 1);
106
+ return `(?:${inner.split(",").map(globSegmentToRegex).join("|")})${globSegmentToRegex(after)}`;
107
+ }));
108
+ }), Match.when("[", () => {
109
+ const close = segment.indexOf("]", 1);
110
+ return Match.value(close < 0).pipe(Match.when(true, () => `${escapeRegex(char)}${globSegmentToRegex(rest)}`), Match.orElse(() => `${segment.slice(0, close + 1)}${globSegmentToRegex(segment.slice(close + 1))}`));
111
+ }), Match.orElse(() => `${escapeRegex(char)}${globSegmentToRegex(rest)}`));
112
+ }));
113
+ const globToRegExp = (pattern, caseInsensitive) => new RegExp(`^${globSegmentToRegex(pattern)}$`, Match.value(caseInsensitive).pipe(Match.when(true, () => "i"), Match.orElse(() => "")));
114
+ const matchesGlob = (path, pattern, caseInsensitive = false) => globToRegExp(pattern, caseInsensitive).test(path);
115
+ const compileIgnoreRule = (pattern) => {
116
+ const negate = pattern.startsWith("!");
117
+ const glob = Match.value(negate).pipe(Match.when(true, () => pattern.slice(1)), Match.orElse(() => pattern));
118
+ const re = globToRegExp(glob, true);
119
+ const prefix = new RegExp(re.source.replace(/\$$/, ""), re.flags);
120
+ return {
121
+ negate,
122
+ matches: (candidate) => re.test(candidate),
123
+ matchesPrefix: (candidate) => prefix.test(candidate)
124
+ };
125
+ };
126
+ //#endregion
86
127
  //#region src/Config.schema.ts
87
128
  const ConfigDocumentSchema = S.Record(S.String, S.Unknown);
88
129
  const ImportedModuleSchema = S.Struct({ default: S.optional(S.Unknown) });
@@ -122,6 +163,27 @@ var MergeCommand = class extends S.TaggedClass()("MergeCommand", {
122
163
  overrides: S.Record(S.String, S.Unknown)
123
164
  }) {};
124
165
  var MergeResult = class extends S.TaggedClass()("MergeResult", { merged: S.Record(S.String, S.Unknown) }) {};
166
+ const ExtendsStepDocumentSchema = S.Struct({
167
+ path: S.String,
168
+ options: ConfigDocumentSchema
169
+ });
170
+ const ExtendsStepStateSchema = S.Struct({
171
+ visited: S.Array(S.String),
172
+ documents: S.Array(ExtendsStepDocumentSchema)
173
+ });
174
+ var ExtendsStepDone = class extends S.TaggedClass()("done", { options: ConfigDocumentSchema }) {};
175
+ var ExtendsStepRead = class extends S.TaggedClass()("read", {
176
+ path: S.String,
177
+ state: ExtendsStepStateSchema
178
+ }) {};
179
+ var ExtendsStepResolve = class extends S.TaggedClass()("resolve", {
180
+ specifier: S.String,
181
+ state: ExtendsStepStateSchema
182
+ }) {};
183
+ var ExtendsStepRefused = class extends S.TaggedClass()("refused", {
184
+ reason: S.Literals(["cycle", "non-string-extends"]),
185
+ file: S.String
186
+ }) {};
125
187
  const survivorsPriorReport = S.optionalKey(S.String.pipe(S.annotate({ description: "The path of the prior mutation report a --survivors run admits against and re-tests the survivors of. Defaults to \"reports/mutation-report.json\" when unset. Deliberately has no default: a default would be injected into every resolved options object and written into every report, poisoning the KTD7 marker that identifies a report produced by a survivors run." })));
126
188
  const extendsPropertySchema = S.optionalKey(S.String.pipe(S.annotate({ description: "Path to another stryker config file whose options merge underneath this one. Resolved relative to this file. A child scalar or array replaces the inherited value; a child object merges one level deep; a child key set to null deletes the inherited key. Inheritance chains are not rewritten, so an inherited relative path value still resolves against the working directory of the run that reads it." })));
127
189
  const forkOptionsSchema = S.StructWithRest(S.Struct({
@@ -148,11 +210,108 @@ var StrykerError = class extends Schema.TaggedError()("StrykerError", {
148
210
  cause: Schema.optional(Schema.Unknown)
149
211
  }) {};
150
212
  //#endregion
213
+ //#region ../stryker-js-plugin-runtime/dist/index.mjs
214
+ const CURRENT_VERSION = "00";
215
+ const serializedTraceState = (traceState) => Option.filter(Option.map(Option.fromUndefinedOr(traceState), (state) => state.serialize()), (serialized) => serialized.length > 0);
216
+ const traceStateField = (traceState) => Option.match(serializedTraceState(traceState), {
217
+ onNone: () => ({}),
218
+ onSome: (serialized) => ({ traceState: serialized })
219
+ });
220
+ const tracePartsOf = (context) => Option.map(Option.liftPredicate(context, (candidate) => api.trace.isSpanContextValid(candidate)), (valid) => ({
221
+ version: CURRENT_VERSION,
222
+ traceId: valid.traceId,
223
+ spanId: valid.spanId,
224
+ traceFlags: valid.traceFlags,
225
+ ...traceStateField(valid.traceState)
226
+ }));
227
+ const partsOfSpan = (span) => Option.flatMap(Option.map(Option.fromUndefinedOr(span), (present) => present.spanContext()), tracePartsOf);
228
+ const remotePartsFromHeaders = (headers) => Option.map(Option.flatMap(Headers.get(headers, TRACEPARENT_HEADER), parseTraceparent), (parts) => ({
229
+ ...parts,
230
+ traceState: Option.getOrUndefined(Headers.get(headers, TRACESTATE_HEADER))
231
+ }));
232
+ const traceHeaders = (parts) => {
233
+ const traceparent = Headers.set(Headers.empty, TRACEPARENT_HEADER, formatTraceparent(parts));
234
+ if (parts.traceState === void 0) return traceparent;
235
+ return Headers.set(traceparent, TRACESTATE_HEADER, parts.traceState);
236
+ };
237
+ const inject = (request, parts) => ({
238
+ ...request,
239
+ headers: Headers.merge(request.headers, traceHeaders(parts))
240
+ });
241
+ const hostParts = Effect$1.map(Effect$1.context(), (context) => Option.orElse(Context.get(context, TraceContextReference), () => partsOfSpan(api.trace.getSpan(api.context.active()))));
242
+ const clientMiddleware = (options) => hostParts.pipe(Effect$1.flatMap((parts) => Option.match(parts, {
243
+ onNone: () => options.next(options.request),
244
+ onSome: (present) => options.next(inject(options.request, present))
245
+ })));
246
+ const layerTraceContextClient = RpcMiddleware.layerClient(TraceContextMiddleware, clientMiddleware);
247
+ const SAMPLED_FLAG = 1;
248
+ const traceStateOption = (traceState) => Option.match(Option.fromUndefinedOr(traceState), {
249
+ onNone: () => ({}),
250
+ onSome: (state) => ({ traceState: state })
251
+ });
252
+ const sampledFlagOf = (sampled) => {
253
+ if (sampled) return SAMPLED_FLAG;
254
+ return 0;
255
+ };
256
+ const externalSpanOf = (parts) => Tracer.externalSpan({
257
+ traceId: parts.traceId,
258
+ spanId: parts.spanId,
259
+ sampled: (parts.traceFlags & SAMPLED_FLAG) === SAMPLED_FLAG,
260
+ ...traceStateOption(parts.traceState)
261
+ });
262
+ const partsOfEffectSpan = (span) => ({
263
+ version: CURRENT_VERSION,
264
+ traceId: span.traceId,
265
+ spanId: span.spanId,
266
+ traceFlags: sampledFlagOf(span.sampled)
267
+ });
268
+ const serverMiddleware = (effect, options) => {
269
+ const remote = remotePartsFromHeaders(options.headers);
270
+ const attributes = { "rpc.method": options.rpc._tag };
271
+ return Option.match(Option.map(remote, externalSpanOf), {
272
+ onNone: () => Effect$1.useSpan(`rpc.${options.rpc._tag}`, { attributes }, () => effect),
273
+ onSome: (parent) => Effect$1.useSpan(`rpc.${options.rpc._tag}`, {
274
+ attributes,
275
+ parent
276
+ }, () => effect)
277
+ }).pipe(Effect$1.provideService(PropagatedTrace, remote));
278
+ };
279
+ Layer.succeed(TraceContextMiddleware, serverMiddleware);
280
+ let wire;
281
+ const workerOptionsWire = () => wire ??= S.fromJsonString(S.toCodecJson(StrykerOptionsSchema));
282
+ const encodeWorkerOptions = (options) => S.encodeEffect(workerOptionsWire())(options).pipe(Effect$1.orDie);
283
+ const decodeWorkerOptions = (raw) => S.decodeUnknownEffect(workerOptionsWire())(raw);
284
+ Effect$1.gen(function* () {
285
+ const workerDir = yield* Config.string("STRYKER_WORKER_DIR");
286
+ const fs = yield* FileSystem.FileSystem;
287
+ const path = yield* Path.Path;
288
+ const raw = yield* fs.readFileString(path.join(workerDir, "options.json"));
289
+ return yield* decodeWorkerOptions(raw);
290
+ });
291
+ const WORKER_SERVICE_NAME = "stryker-js-plugin-worker";
292
+ const DEFAULT_ENDPOINT = "http://127.0.0.1:4318";
293
+ const TRACES_SUFFIX = "/v1/traces";
294
+ const tracesUrl = (endpoint) => {
295
+ const trimmed = endpoint.replace(/\/+$/u, "");
296
+ if (trimmed.endsWith(TRACES_SUFFIX)) return trimmed;
297
+ return `${trimmed}${TRACES_SUFFIX}`;
298
+ };
299
+ const otlpLayer = (serviceName, endpoint) => NodeSdk.layer(() => ({
300
+ resource: { serviceName },
301
+ spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter({ url: tracesUrl(endpoint) }))
302
+ }));
303
+ Layer.unwrap(Effect$1.gen(function* () {
304
+ if (!(yield* Config.boolean("OTEL_ENABLED").pipe(Config.withDefault(false)))) return Layer.empty;
305
+ const serviceName = yield* Config.string("OTEL_SERVICE_NAME").pipe(Config.withDefault(WORKER_SERVICE_NAME));
306
+ const endpoint = yield* Config.string("OTEL_EXPORTER_OTLP_ENDPOINT").pipe(Config.withDefault(DEFAULT_ENDPOINT));
307
+ return otlpLayer(serviceName, endpoint);
308
+ }));
309
+ //#endregion
151
310
  //#region src/VmRunner.ts
152
311
  var VmRunner = class extends Context.Service()("@systemfsoftware/stryker-js/VmRunner") {};
153
312
  const vmRunnerName = "vm";
154
313
  const ALL_TESTS_NAME = "All tests";
155
- const isVmRunner = (name) => name.toLowerCase() === "vm";
314
+ const isVmRunner = (name) => typeof name === "string" && name.toLowerCase() === "vm";
156
315
  const vmRunnerCapabilities = { reloadEnvironment: true };
157
316
  const FALLBACK_FILE_NAME = "stryker-vm-tests.js";
158
317
  const errorText = (error) => Match.value(error).pipe(Match.when(Match.instanceOf(Error), (failure) => failure.message), Match.orElse((value) => String(value)));
@@ -161,15 +320,15 @@ const compileFailure = (file, cause) => TestRunnerFailed.make({
161
320
  phase: "init",
162
321
  cause: `Could not compile "${file}" for the in-memory runner: ${errorText(cause)}`
163
322
  });
164
- const compileTests = (platform, fs, testFiles) => Effect.gen(function* () {
165
- const sources = yield* Effect.forEach(testFiles, (file) => fs.readFileString(file).pipe(Effect.mapError((cause) => compileFailure(file, cause)), Effect.flatMap((source) => Effect.try({
323
+ const compileTests = (platform, fs, testFiles) => Effect$1.gen(function* () {
324
+ const sources = yield* Effect$1.forEach(testFiles, (file) => fs.readFileString(file).pipe(Effect$1.mapError((cause) => compileFailure(file, cause)), Effect$1.flatMap((source) => Effect$1.try({
166
325
  try: () => platform.module.stripTypeScriptTypes(source, { mode: "transform" }),
167
326
  catch: (cause) => compileFailure(file, cause)
168
327
  }))));
169
328
  const fileName = Option.getOrElse(Option.fromUndefinedOr(testFiles.at(0)), () => FALLBACK_FILE_NAME);
170
329
  return {
171
330
  fileName,
172
- script: yield* Effect.try({
331
+ script: yield* Effect$1.try({
173
332
  try: () => new platform.vm.Script(sources.join("\n;\n"), { filename: fileName }),
174
333
  catch: (cause) => compileFailure(fileName, cause)
175
334
  })
@@ -209,7 +368,7 @@ const resultFromRun = (failureMessage, timeSpentMs) => Match.value(failureMessag
209
368
  timeSpentMs
210
369
  }]
211
370
  })));
212
- const runInFreshContext = (platform, compiled, activeMutantId) => Effect.sync(() => {
371
+ const runInFreshContext = (platform, compiled, activeMutantId) => Effect$1.sync(() => {
213
372
  const context = platform.vm.createContext(sandboxFor(platform, compiled.fileName, activeMutantId));
214
373
  try {
215
374
  compiled.script.runInContext(context);
@@ -218,30 +377,30 @@ const runInFreshContext = (platform, compiled, activeMutantId) => Effect.sync(()
218
377
  return errorText(cause);
219
378
  }
220
379
  });
221
- const runOnce = (platform, compiled, activeMutantId) => Effect.gen(function* () {
380
+ const runOnce = (platform, compiled, activeMutantId) => Effect$1.gen(function* () {
222
381
  const startedAt = yield* Clock.currentTimeMillis;
223
382
  const failure = yield* runInFreshContext(platform, compiled, activeMutantId);
224
383
  const elapsedMs = (yield* Clock.currentTimeMillis) - startedAt;
225
384
  return resultFromRun(failure, elapsedMs);
226
385
  });
227
- const vmTestRunner = (config) => Effect.gen(function* () {
386
+ const vmTestRunner = (config) => Effect$1.gen(function* () {
228
387
  const platform = yield* VmRunner;
229
388
  const fs = yield* FileSystem.FileSystem;
230
389
  const compiled = yield* Ref.make(Option.none());
231
- const compiledTests = (testFiles) => Effect.gen(function* () {
390
+ const compiledTests = (testFiles) => Effect$1.gen(function* () {
232
391
  const cached = yield* Ref.get(compiled);
233
392
  if (Option.isSome(cached)) return cached.value;
234
393
  const tests = yield* compileTests(platform, fs, testFiles);
235
394
  yield* Ref.set(compiled, Option.some(tests));
236
395
  return tests;
237
396
  });
238
- const run = (testFiles, activeMutantId) => compiledTests(testFiles).pipe(Effect.flatMap((tests) => runOnce(platform, tests, activeMutantId)));
397
+ const run = (testFiles, activeMutantId) => compiledTests(testFiles).pipe(Effect$1.flatMap((tests) => runOnce(platform, tests, activeMutantId)));
239
398
  const testFilesOf = (override) => Match.value(config.testFiles).pipe(Match.when((files) => files.length > 0, (files) => files), Match.orElse(() => override ?? []));
240
399
  return {
241
- capabilities: Effect.succeed(vmRunnerCapabilities),
242
- init: Effect.void,
400
+ capabilities: Effect$1.succeed(vmRunnerCapabilities),
401
+ init: Effect$1.void,
243
402
  dryRun: (options) => run(testFilesOf(options.testFiles), void 0),
244
- mutantRun: (options) => run(config.testFiles, options.activeMutant.id).pipe(Effect.map((result) => toMutantRunResult(result, true)), Effect.catchTag("TestRunnerFailed", (failure) => Effect.succeed(toMutantRunResult({
403
+ mutantRun: (options) => run(config.testFiles, options.activeMutant.id).pipe(Effect$1.map((result) => toMutantRunResult(result, true)), Effect$1.catchTag("TestRunnerFailed", (failure) => Effect$1.succeed(toMutantRunResult({
245
404
  status: "error",
246
405
  errorMessage: failure.cause
247
406
  }, true))))
@@ -289,7 +448,7 @@ var WorkerBootTimeoutError = class extends Schema.TaggedError()("WorkerBootTimeo
289
448
  //#endregion
290
449
  //#region src/Worker.ts
291
450
  var IdGenerator = class extends Context.Service()("@systemfsoftware/stryker-js/Worker/IdGenerator") {};
292
- const makeIdGenerator = Effect.gen(function* () {
451
+ const makeIdGenerator = Effect$1.gen(function* () {
293
452
  const ref = yield* Ref.make(0);
294
453
  return { next: Ref.getAndUpdate(ref, (n) => n + 1) };
295
454
  });
@@ -329,10 +488,10 @@ const splitConcurrency = (total, checkerCount) => {
329
488
  checkers: 0
330
489
  };
331
490
  };
332
- const announcePercentage = (resolved) => Match.value(resolved.isPercentage).pipe(Match.when(true, () => Effect.logDebug(`Computed concurrency ${resolved.total} from "${resolved.option}" based on ${resolved.availableParallelism} available parallelism.`)), Match.orElse(() => Effect.void));
333
- const announceProcesses = (split) => Match.value(split.checkers > 0).pipe(Match.when(true, () => Effect.logInfo(`Creating ${split.checkers} checker process(es) and ${split.testRunners} test runner process(es).`)), Match.orElse(() => Effect.logInfo(`Creating ${split.testRunners} test runner process(es).`)));
334
- const makeConcurrency = (options) => Effect.gen(function* () {
335
- const availableParallelism = yield* Effect.sync(getAvailableParallelism);
491
+ const announcePercentage = (resolved) => Match.value(resolved.isPercentage).pipe(Match.when(true, () => Effect$1.logDebug(`Computed concurrency ${resolved.total} from "${resolved.option}" based on ${resolved.availableParallelism} available parallelism.`)), Match.orElse(() => Effect$1.void));
492
+ const announceProcesses = (split) => Match.value(split.checkers > 0).pipe(Match.when(true, () => Effect$1.logInfo(`Creating ${split.checkers} checker process(es) and ${split.testRunners} test runner process(es).`)), Match.orElse(() => Effect$1.logInfo(`Creating ${split.testRunners} test runner process(es).`)));
493
+ const makeConcurrency = (options) => Effect$1.gen(function* () {
494
+ const availableParallelism = yield* Effect$1.sync(getAvailableParallelism);
336
495
  const { total, isPercentage } = computeTotalConcurrencyDetails(options.concurrency, availableParallelism);
337
496
  yield* announcePercentage({
338
497
  option: options.concurrency,
@@ -361,7 +520,7 @@ const classifyWorkerExit = (pid, exitCode) => Match.value(exitCode).pipe(Match.w
361
520
  //#region src/WorkerLauncher.ts
362
521
  const connectRetry = Schedule.max([Schedule.spaced(50), Schedule.recurs(100)]);
363
522
  var WorkerLauncher = class extends Context.Service()("@systemfsoftware/stryker-js/WorkerLauncher") {};
364
- const makeWorkerClient = (params) => Effect.gen(function* () {
523
+ const makeWorkerClient = (params) => Effect$1.gen(function* () {
365
524
  const worker = yield* (yield* WorkerLauncher).spawn({
366
525
  entrypoint: params.entrypoint,
367
526
  workingDirectory: params.workingDirectory,
@@ -370,25 +529,24 @@ const makeWorkerClient = (params) => Effect.gen(function* () {
370
529
  tempDirPrefix: params.tempDirPrefix,
371
530
  env: params.env
372
531
  });
373
- const protocol = yield* Layer.build(worker.clientLayer).pipe(Effect.retry(connectRetry), Effect.raceFirst(worker.exited), Effect.catchTag("SocketError", () => Effect.fail(WorkerBootTimeoutError.make({ pid: worker.pid }))));
374
- return yield* RpcClient.make(params.rpcs).pipe(Effect.provideContext(protocol), Effect.provide(layerTraceContextClient));
532
+ const protocol = yield* Layer.build(worker.clientLayer).pipe(Effect$1.retry(connectRetry), Effect$1.raceFirst(worker.exited), Effect$1.catchTag("SocketError", () => Effect$1.fail(WorkerBootTimeoutError.make({ pid: worker.pid }))));
533
+ return yield* RpcClient.make(params.rpcs).pipe(Effect$1.provideContext(protocol), Effect$1.provide(layerTraceContextClient));
375
534
  });
376
535
  //#endregion
377
536
  //#region src/platform/node.ts
378
- const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect.catchTag("PlatformError", (cause) => Effect.logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(Effect.annotateLogs("cause", cause))));
379
- const restrictSocketToOwnerOrWarn = (fs, socketPath) => Match.value(process.platform).pipe(Match.when("win32", () => Effect.void), Match.orElse(() => restrictToOwnerOrWarn(fs, socketPath)));
537
+ const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.catchTag("PlatformError", (cause) => Effect$1.logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(Effect$1.annotateLogs("cause", cause))));
380
538
  /**
381
539
  * The Node worker launcher: spawn a worker child with this runtime's
382
540
  * executable, host the RPC server's address as a `net` `path` endpoint (a
383
541
  * socket file in the worker directory on POSIX, a same-user named pipe on
384
542
  * Windows), and connect the NDJSON protocol client over `NodeSocket`.
385
543
  */
386
- const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect.gen(function* () {
544
+ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
387
545
  const crypto = yield* Crypto.Crypto;
388
546
  const fs = yield* FileSystem.FileSystem;
389
547
  const path = yield* Path.Path;
390
548
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
391
- return { spawn: (params) => Effect.gen(function* () {
549
+ return { spawn: (params) => Effect$1.gen(function* () {
392
550
  const workerDir = yield* fs.makeTempDirectoryScoped({ prefix: params.tempDirPrefix });
393
551
  const workerId = yield* crypto.randomUUIDv4;
394
552
  const socketPath = Match.value(process.platform).pipe(Match.when("win32", () => `\\\\.\\pipe\\stryker-worker-${workerId}`), Match.orElse(() => path.join(workerDir, "worker.sock")));
@@ -405,15 +563,15 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect.gen(function
405
563
  ...params.env
406
564
  },
407
565
  stderr: "inherit"
408
- }).pipe(Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
409
- const clientLayer = RpcClient.layerProtocolSocket({ retryTransientErrors: true }).pipe(Layer.provide(NodeSocket.layerNet({ path: socketPath })), Layer.provide(RpcSerialization.layerNdjson), Layer.tap(() => restrictSocketToOwnerOrWarn(fs, socketPath)));
410
- const exited = handle.exitCode.pipe(Effect.orDie, Effect.flatMap((exitCode) => Effect.fail(classifyWorkerExit(Number(handle.pid), exitCode))));
566
+ }).pipe(Effect$1.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
567
+ const clientLayer = RpcClient.layerProtocolSocket({ retryTransientErrors: true }).pipe(Layer.provide(NodeSocket.layerNet({ path: socketPath })), Layer.provide(RpcSerialization.layerNdjson));
568
+ const exited = handle.exitCode.pipe(Effect$1.orDie, Effect$1.flatMap((exitCode) => Effect$1.fail(classifyWorkerExit(Number(handle.pid), exitCode))));
411
569
  return {
412
570
  pid: Number(handle.pid),
413
571
  clientLayer,
414
572
  exited
415
573
  };
416
- }).pipe(Effect.catchIf(S.is(ChildProcessCrashedError), (error) => Effect.fail(error), () => Effect.fail(ChildProcessCrashedError.make({
574
+ }).pipe(Effect$1.catchIf(S.is(ChildProcessCrashedError), (error) => Effect$1.fail(error), () => Effect$1.fail(ChildProcessCrashedError.make({
417
575
  pid: 0,
418
576
  exit: {
419
577
  _tag: "Code",
@@ -435,7 +593,7 @@ const nodePlatformLayer = Layer.mergeAll(nodeWorkerLauncherLayer.pipe(Layer.prov
435
593
  * `Effect.promise` so a platform without `node:vm` fails as a defect — the
436
594
  * runner has no fallback to fall back to.
437
595
  */
438
- const nodeVmPlatformLayer = Layer.effect(VmRunner, Effect.sync(() => ({
596
+ const nodeVmPlatformLayer = Layer.effect(VmRunner, Effect$1.sync(() => ({
439
597
  module: process.getBuiltinModule("node:module"),
440
598
  vm: process.getBuiltinModule("node:vm")
441
599
  })));
@@ -476,14 +634,15 @@ const toRunnerFailure = (runnerName, phase) => (error) => Match.value(error).pip
476
634
  * `Pool.invalidate` and the crash-retry combinator can only act on a failure they
477
635
  * can see.
478
636
  */
479
- const makeChildProcessTestRunner = (params) => Effect.gen(function* () {
480
- const runnerName = params.options.testRunner;
637
+ const makeChildProcessTestRunner = (params) => Effect$1.gen(function* () {
638
+ const runnerName = Match.value(params.options.testRunner).pipe(Match.when(isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
639
+ const execArgv = Match.value(params.options.testRunner).pipe(Match.when(isCustomTestRunner, (runner) => Match.value(runner.nodeArgs).pipe(Match.when(Match.undefined, () => params.options.testRunnerNodeArgs), Match.orElse((args) => args))), Match.orElse(() => params.options.testRunnerNodeArgs));
481
640
  const optionsJson = yield* encodeWorkerOptions(params.options);
482
641
  const client = yield* makeWorkerClient({
483
642
  rpcs: TestRunnerRpcs,
484
643
  entrypoint: params.workerEntrypoint,
485
644
  workingDirectory: params.sandboxWorkingDirectory,
486
- execArgv: [...params.options.testRunnerNodeArgs],
645
+ execArgv: [...execArgv],
487
646
  optionsJson,
488
647
  tempDirPrefix: "stryker-test-runner-",
489
648
  env: {
@@ -491,12 +650,12 @@ const makeChildProcessTestRunner = (params) => Effect.gen(function* () {
491
650
  VITEST: "1",
492
651
  STRYKER_SANDBOX_DIR: params.sandboxWorkingDirectory
493
652
  }
494
- }).pipe(Effect.mapError(toRunnerBootFailure(runnerName)));
653
+ }).pipe(Effect$1.mapError(toRunnerBootFailure(runnerName)));
495
654
  return {
496
- capabilities: client.capabilities().pipe(Effect.mapError(toRunnerFailure(runnerName, "capabilities"))),
497
- init: Effect.void,
498
- dryRun: (options) => client.dryRun({ options }).pipe(Effect.mapError(toRunnerFailure(runnerName, "dryRun"))),
499
- mutantRun: (options) => client.mutantRun({ options }).pipe(Effect.mapError(toRunnerFailure(runnerName, "mutantRun")))
655
+ capabilities: client.capabilities().pipe(Effect$1.mapError(toRunnerFailure(runnerName, "capabilities"))),
656
+ init: Effect$1.void,
657
+ dryRun: (options) => client.dryRun({ options }).pipe(Effect$1.mapError(toRunnerFailure(runnerName, "dryRun"))),
658
+ mutantRun: (options) => client.mutantRun({ options }).pipe(Effect$1.mapError(toRunnerFailure(runnerName, "mutantRun")))
500
659
  };
501
660
  });
502
661
  /**
@@ -509,16 +668,16 @@ const makeChildProcessTestRunner = (params) => Effect.gen(function* () {
509
668
  const withTimeout = (inner) => ({
510
669
  ...inner,
511
670
  dryRun: (options) => {
512
- const policy = Effect.timeoutOrElse({
671
+ const policy = Effect$1.timeoutOrElse({
513
672
  duration: Duration.millis(options.timeout),
514
- orElse: () => Effect.succeed({ status: "timeout" })
673
+ orElse: () => Effect$1.succeed({ status: "timeout" })
515
674
  });
516
675
  return inner.dryRun(options).pipe(policy);
517
676
  },
518
677
  mutantRun: (options) => {
519
- const policy = Effect.timeoutOrElse({
678
+ const policy = Effect$1.timeoutOrElse({
520
679
  duration: Duration.millis(options.timeout),
521
- orElse: () => Effect.succeed({ status: "timeout" })
680
+ orElse: () => Effect$1.succeed({ status: "timeout" })
522
681
  });
523
682
  return inner.mutantRun(options).pipe(policy);
524
683
  }
@@ -534,7 +693,7 @@ const withTimeout = (inner) => ({
534
693
  * keeps the chain that led there.
535
694
  */
536
695
  const withRetry = (inner) => {
537
- const attempt = (run, onExhausted) => run.pipe(Effect.tapError((error) => Match.value(error).pipe(Match.when(S.is(OutOfMemoryError), (outOfMemory) => Effect.logInfo(`Test runner process [${outOfMemory.pid}] ran out of memory. That usually means the tests leak memory. Stryker restarts the process and carries on, but the run is slower for it.`)), Match.orElse(() => Effect.void))), Effect.retry({ times: 2 }), Effect.catchCause((cause) => Effect.succeed(onExhausted(`Test runner crashed. Tried 2 times to restart it without any luck. ${Cause.pretty(cause)}`))));
696
+ const attempt = (run, onExhausted) => run.pipe(Effect$1.tapError((error) => Match.value(error).pipe(Match.when(S.is(OutOfMemoryError), (outOfMemory) => Effect$1.logInfo(`Test runner process [${outOfMemory.pid}] ran out of memory. That usually means the tests leak memory. Stryker restarts the process and carries on, but the run is slower for it.`)), Match.orElse(() => Effect$1.void))), Effect$1.retry({ times: 2 }), Effect$1.catchCause((cause) => Effect$1.succeed(onExhausted(`Test runner crashed. Tried 2 times to restart it without any luck. ${Cause.pretty(cause)}`))));
538
697
  return {
539
698
  ...inner,
540
699
  dryRun: (options) => attempt(inner.dryRun(options), (errorMessage) => ({
@@ -556,14 +715,14 @@ const withRetry = (inner) => {
556
715
  * `Pool.invalidate`, and a runner that restarts itself behind the pool's back
557
716
  * would create two owners of one process.
558
717
  */
559
- const withMaxReuse = (options, retire) => (inner) => Effect.gen(function* () {
718
+ const withMaxReuse = (options, retire) => (inner) => Effect$1.gen(function* () {
560
719
  const restartAfter = options.maxTestRunnerReuse;
561
720
  if (restartAfter <= 0) return inner;
562
721
  const runs = yield* Ref.make(0);
563
722
  return {
564
723
  ...inner,
565
724
  mutantRun: (runOptions) => {
566
- const policy = (self) => Effect.gen(function* () {
725
+ const policy = (self) => Effect$1.gen(function* () {
567
726
  if ((yield* Ref.updateAndGet(runs, (n) => n + 1)) > restartAfter) {
568
727
  yield* retire;
569
728
  yield* Ref.set(runs, 1);
@@ -590,15 +749,15 @@ const environmentPlan = (request) => ({
590
749
  * mutated, so a caller that reuses its own options does not read a value it
591
750
  * never wrote.
592
751
  */
593
- const withEnvironmentReload = (retire) => (inner) => Effect.gen(function* () {
752
+ const withEnvironmentReload = (retire) => (inner) => Effect$1.gen(function* () {
594
753
  const state = yield* Ref.make("pristine");
595
754
  return {
596
755
  ...inner,
597
756
  dryRun: (options) => {
598
- const policy = (self) => Ref.set(state, "loaded").pipe(Effect.andThen(self));
757
+ const policy = (self) => Ref.set(state, "loaded").pipe(Effect$1.andThen(self));
599
758
  return policy(inner.dryRun(options));
600
759
  },
601
- mutantRun: (options) => Effect.gen(function* () {
760
+ mutantRun: (options) => Effect$1.gen(function* () {
602
761
  const current = yield* Ref.get(state);
603
762
  const canReload = (yield* inner.capabilities).reloadEnvironment;
604
763
  const plan = environmentPlan({
@@ -607,7 +766,7 @@ const withEnvironmentReload = (retire) => (inner) => Effect.gen(function* () {
607
766
  canReload
608
767
  });
609
768
  if (plan.retire) yield* retire;
610
- const policy = (self) => Effect.gen(function* () {
769
+ const policy = (self) => Effect$1.gen(function* () {
611
770
  const result = yield* self;
612
771
  yield* Ref.set(state, plan.nextState);
613
772
  return result;
@@ -619,10 +778,8 @@ const withEnvironmentReload = (retire) => (inner) => Effect.gen(function* () {
619
778
  })
620
779
  };
621
780
  });
622
- /** "command" — the name this runner answers to in the options. */
623
- const commandRunnerName = "command";
624
781
  /** Whether a configured runner name selects this runner. */
625
- const isCommandRunner = (name) => name.toLowerCase() === commandRunnerName;
782
+ const isCommandRunner = (name) => typeof name === "string" && name.toLowerCase() === "command";
626
783
  /** Each call is a fresh process, so the environment is always reloadable. */
627
784
  const commandRunnerCapabilities = { reloadEnvironment: true };
628
785
  /** One test result standing for the whole command, decided by its exit code. */
@@ -661,7 +818,7 @@ const spawnResult = (outcome, elapsed) => Match.value(outcome).pipe(Match.tag("F
661
818
  * `activeMutantId` is threaded through the environment rather than the command
662
819
  * line, which is how the instrumented code finds the mutant to activate.
663
820
  */
664
- const runCommand = (config, activeMutantId) => Effect.gen(function* () {
821
+ const runCommand = (config, activeMutantId) => Effect$1.gen(function* () {
665
822
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
666
823
  const startedAt = yield* Clock.currentTimeMillis;
667
824
  const command = ChildProcess.make(config.options.commandRunner.command, {
@@ -669,20 +826,20 @@ const runCommand = (config, activeMutantId) => Effect.gen(function* () {
669
826
  cwd: config.workingDir,
670
827
  ...mutantActivation(activeMutantId)
671
828
  });
672
- const outcome = yield* Effect.scoped(Effect.gen(function* () {
829
+ const outcome = yield* Effect$1.scoped(Effect$1.gen(function* () {
673
830
  const handle = yield* spawner.spawn(command);
674
831
  return {
675
832
  output: yield* Stream.mkString(Stream.decodeText(handle.all)),
676
833
  exitCode: yield* handle.exitCode
677
834
  };
678
- })).pipe(Effect.exit);
835
+ })).pipe(Effect$1.exit);
679
836
  const elapsed = (yield* Clock.currentTimeMillis) - startedAt;
680
837
  return spawnResult(outcome, elapsed);
681
838
  });
682
839
  /** Run the tests with no mutant active, to establish the baseline. */
683
840
  const commandRunnerDryRun = (config) => runCommand(config, void 0);
684
841
  /** Run the tests with one mutant active. */
685
- const commandRunnerMutantRun = (config, { activeMutant }) => runCommand(config, activeMutant.id).pipe(Effect.map((result) => toMutantRunResult(result, true)));
842
+ const commandRunnerMutantRun = (config, { activeMutant }) => runCommand(config, activeMutant.id).pipe(Effect$1.map((result) => toMutantRunResult(result, true)));
686
843
  /**
687
844
  * The command runner, wrapped in the two adjustments that apply to it.
688
845
  *
@@ -700,17 +857,17 @@ const commandRunner = (context, spawner) => {
700
857
  workingDir: context.sandboxWorkingDirectory,
701
858
  options: context.options
702
859
  };
703
- const provided = Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner);
860
+ const provided = Effect$1.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner);
704
861
  const base = {
705
- capabilities: Effect.succeed(commandRunnerCapabilities),
706
- init: Effect.void,
862
+ capabilities: Effect$1.succeed(commandRunnerCapabilities),
863
+ init: Effect$1.void,
707
864
  dryRun: () => commandRunnerDryRun(config).pipe(provided),
708
865
  mutantRun: (options) => commandRunnerMutantRun(config, options).pipe(provided)
709
866
  };
710
867
  return withRetry(withTimeout(base));
711
868
  };
712
- const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option.some(ChildProcessSpawner.ChildProcessSpawner.pipe(Effect.map((spawner) => commandRunner(context, spawner))))), Match.when(isVmRunner, () => Option.some(vmTestRunner({ testFiles: context.testFiles }).pipe(Effect.provide(nodeVmPlatformLayer)))), Match.orElse(() => Option.none()));
713
- const buildTestRunner = (context, childProcessRunner) => Effect.gen(function* () {
869
+ const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option.some(ChildProcessSpawner.ChildProcessSpawner.pipe(Effect$1.map((spawner) => commandRunner(context, spawner))))), Match.when(isVmRunner, () => Option.some(vmTestRunner({ testFiles: context.testFiles }).pipe(Effect$1.provide(nodeVmPlatformLayer)))), Match.orElse(() => Option.none()));
870
+ const buildTestRunner = (context, childProcessRunner) => Effect$1.gen(function* () {
714
871
  const inProcess = inProcessRunner(context);
715
872
  if (Option.isSome(inProcess)) return yield* inProcess.value;
716
873
  const base = yield* childProcessRunner;
@@ -830,7 +987,7 @@ function describeErrors(error) {
830
987
  return errorMessageOrFallback(completedErrorMessages(state), error.message);
831
988
  }
832
989
  function importModule(moduleName) {
833
- return Effect.tryPromise({
990
+ return Effect$1.tryPromise({
834
991
  try: () => import(moduleName),
835
992
  catch: (cause) => StrykerError.make({
836
993
  message: `Failed to import module "${moduleName}"`,
@@ -842,10 +999,6 @@ const initialExtendsStepState = {
842
999
  visited: [],
843
1000
  documents: []
844
1001
  };
845
- const DoneTag = { _tag: "done" };
846
- const ReadTag = { _tag: "read" };
847
- const ResolveTag = { _tag: "resolve" };
848
- const RefusedTag = { _tag: "refused" };
849
1002
  const asUnknownArray = (value) => {
850
1003
  if (Array.isArray(value)) return value;
851
1004
  return [];
@@ -888,11 +1041,10 @@ const stripExtends = (document) => {
888
1041
  };
889
1042
  const mergeChainDocuments = (documents) => documents.reduceRight((merged, entry) => mergeConfigs(merged, stripExtends(entry.options)), {});
890
1043
  const decideExtendsStep = (state, document, file, pathService) => {
891
- if (state.visited.includes(file)) return {
892
- ...RefusedTag,
1044
+ if (state.visited.includes(file)) return ExtendsStepRefused.make({
893
1045
  reason: "cycle",
894
1046
  file
895
- };
1047
+ });
896
1048
  const nextState = {
897
1049
  visited: [...state.visited, file],
898
1050
  documents: [...state.documents, {
@@ -900,34 +1052,25 @@ const decideExtendsStep = (state, document, file, pathService) => {
900
1052
  options: document
901
1053
  }]
902
1054
  };
903
- return Match.value(document["extends"]).pipe(Match.when(void 0, () => ({
904
- ...DoneTag,
905
- options: mergeChainDocuments(nextState.documents)
906
- })), Match.when(null, () => ({
907
- ...DoneTag,
908
- options: mergeChainDocuments(nextState.documents)
909
- })), Match.when(Match.string, (extendValue) => Match.value(isModuleSpecifier(extendValue)).pipe(Match.when(true, () => ({
910
- ...ResolveTag,
1055
+ return Match.value(document["extends"]).pipe(Match.when(void 0, () => ExtendsStepDone.make({ options: mergeChainDocuments(nextState.documents) })), Match.when(null, () => ExtendsStepDone.make({ options: mergeChainDocuments(nextState.documents) })), Match.when(Match.string, (extendValue) => Match.value(isModuleSpecifier(extendValue)).pipe(Match.when(true, () => ExtendsStepResolve.make({
911
1056
  specifier: extendValue,
912
1057
  state: nextState
913
- })), Match.when(false, () => ({
914
- ...ReadTag,
1058
+ })), Match.when(false, () => ExtendsStepRead.make({
915
1059
  path: pathService.resolve(pathService.dirname(file), extendValue),
916
1060
  state: nextState
917
- })), Match.exhaustive)), Match.orElse(() => ({
918
- ...RefusedTag,
1061
+ })), Match.exhaustive)), Match.orElse(() => ExtendsStepRefused.make({
919
1062
  reason: "non-string-extends",
920
1063
  file
921
1064
  })));
922
1065
  };
923
- const decodeConfigDocument = (configFile, document) => S.decodeUnknownEffect(ConfigDocumentSchema)(document).pipe(Effect.mapError((cause) => ConfigFileInvalidError.make({
1066
+ const decodeConfigDocument = (configFile, document) => S.decodeUnknownEffect(ConfigDocumentSchema)(document).pipe(Effect$1.mapError((cause) => ConfigFileInvalidError.make({
924
1067
  file: configFile,
925
1068
  cause
926
1069
  })));
927
- const requireDefaultExport = (configFile, defaultExport) => Match.value(defaultExport).pipe(Match.when(void 0, () => Effect.fail(ConfigFileInvalidError.make({
1070
+ const requireDefaultExport = (configFile, defaultExport) => Match.value(defaultExport).pipe(Match.when(void 0, () => Effect$1.fail(ConfigFileInvalidError.make({
928
1071
  file: configFile,
929
1072
  cause: "Config file must have a default export!"
930
- }))), Match.when(isNonNullObject, (value) => Effect.succeed(value)), Match.orElse(() => Effect.fail(ConfigFileInvalidError.make({
1073
+ }))), Match.when(isNonNullObject, (value) => Effect$1.succeed(value)), Match.orElse(() => Effect$1.fail(ConfigFileInvalidError.make({
931
1074
  file: configFile,
932
1075
  cause: "Default export of config file must be an object!"
933
1076
  }))));
@@ -942,13 +1085,13 @@ const factoryFailureCause = (cause) => Match.value(cause).pipe(Match.when(Match.
942
1085
  * config is being read for; the promise is awaited here because a promise is a
943
1086
  * non-null object and would otherwise reach the document decoder as one.
944
1087
  */
945
- const settleConfigDefault = (configFile, defaultExport, configEnv) => Effect.tryPromise({
1088
+ const settleConfigDefault = (configFile, defaultExport, configEnv) => Effect$1.tryPromise({
946
1089
  try: () => Promise.resolve(defaultExport).then((exported) => Match.value(exported).pipe(Match.when(isConfigFactory, (factory) => factory(configEnv)), Match.orElse((value) => value))),
947
1090
  catch: (cause) => ConfigFileInvalidError.make({
948
1091
  file: configFile,
949
1092
  cause: factoryFailureCause(cause)
950
1093
  })
951
- }).pipe(Effect.flatMap((settled) => requireDefaultExport(configFile, settled)));
1094
+ }).pipe(Effect$1.flatMap((settled) => requireDefaultExport(configFile, settled)));
952
1095
  const ERASABLE_SYNTAX_HELP = "Config modules may use only erasable TypeScript syntax: no enums, no namespaces with runtime code, no parameter properties, and no decorators.";
953
1096
  const carriesCode = (cause) => cause instanceof Error && "code" in cause;
954
1097
  const errorCodeOf = (cause) => {
@@ -961,50 +1104,50 @@ const errorMessageOf = (cause) => {
961
1104
  };
962
1105
  const importFailureDetail = (failure) => errorMessageOf(failure.cause) ?? failure.message;
963
1106
  const configImportCause = (configFile, failure) => Match.value(errorCodeOf(failure.cause)).pipe(Match.when("ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX", () => new Error(`The config file "${configFile}" uses TypeScript syntax Node cannot execute. ${ERASABLE_SYNTAX_HELP}`, { cause: failure.cause })), Match.when("ERR_UNKNOWN_FILE_EXTENSION", () => new Error(`The config file "${configFile}" has an extension Node cannot load. Stryker reads config modules with ${SUPPORTED_CONFIG_FILE_EXTENSION_GUIDE}.`, { cause: failure.cause })), Match.when("ERR_MODULE_NOT_FOUND", () => new Error(`The config file "${configFile}" imports a module Node cannot find. The specifier is most likely not installed — install it as a dependency of the project, or remove the import. Node reported: ${importFailureDetail(failure)}`, { cause: failure.cause })), Match.when("ERR_PACKAGE_PATH_NOT_EXPORTED", () => new Error(`The config file "${configFile}" imports a path a package does not export. The package is installed but its "exports" map leaves this specifier out — import a path the package publishes. Node reported: ${importFailureDetail(failure)}`, { cause: failure.cause })), Match.orElse(() => failure));
964
- const configModuleUrl = (configFile, pathService) => Match.value(configFile.startsWith("file:")).pipe(Match.when(true, () => Effect.try({
1107
+ const configModuleUrl = (configFile, pathService) => Match.value(configFile.startsWith("file:")).pipe(Match.when(true, () => Effect$1.try({
965
1108
  try: () => new URL(configFile),
966
1109
  catch: (cause) => ConfigFileUnreadableError.make({
967
1110
  file: configFile,
968
1111
  cause
969
1112
  })
970
- })), Match.orElse(() => pathService.toFileUrl(pathService.resolve(configFile)).pipe(Effect.mapError((cause) => ConfigFileUnreadableError.make({
1113
+ })), Match.orElse(() => pathService.toFileUrl(pathService.resolve(configFile)).pipe(Effect$1.mapError((cause) => ConfigFileUnreadableError.make({
971
1114
  file: configFile,
972
1115
  cause
973
1116
  })))));
974
- const readConfigModule = (configFile, configEnv) => Effect.gen(function* () {
1117
+ const readConfigModule = (configFile, configEnv) => Effect$1.gen(function* () {
975
1118
  const pathService = yield* Path.Path;
976
- const importedModule = yield* importModule((yield* configModuleUrl(configFile, pathService)).href).pipe(Effect.mapError((failure) => ConfigFileUnreadableError.make({
1119
+ const importedModule = yield* importModule((yield* configModuleUrl(configFile, pathService)).href).pipe(Effect$1.mapError((failure) => ConfigFileUnreadableError.make({
977
1120
  file: configFile,
978
1121
  cause: configImportCause(configFile, failure)
979
1122
  })));
980
- const exported = yield* S.decodeUnknownEffect(ImportedModuleSchema)(importedModule).pipe(Effect.mapError((cause) => ConfigFileInvalidError.make({
1123
+ const exported = yield* S.decodeUnknownEffect(ImportedModuleSchema)(importedModule).pipe(Effect$1.mapError((cause) => ConfigFileInvalidError.make({
981
1124
  file: configFile,
982
1125
  cause
983
- })), Effect.map((decoded) => decoded.default));
1126
+ })), Effect$1.map((decoded) => decoded.default));
984
1127
  const document = yield* settleConfigDefault(configFile, exported, configEnv);
985
1128
  return yield* decodeConfigDocument(configFile, document);
986
1129
  });
987
1130
  const configFileExtension = (configFile, pathService) => pathService.extname(configFile).toLowerCase().slice(1);
988
1131
  const isLegacyConfigFile = (configFile, pathService) => LEGACY_CONFIG_FILE_EXTENSIONS.includes(configFileExtension(configFile, pathService));
989
- const readExtendsChild = (configFile, configEnv) => Effect.gen(function* () {
1132
+ const readExtendsChild = (configFile, configEnv) => Effect$1.gen(function* () {
990
1133
  const pathService = yield* Path.Path;
991
- return yield* Match.value(isLegacyConfigFile(configFile, pathService)).pipe(Match.when(true, () => Effect.fail(ConfigFileUnsupportedError.make({
1134
+ return yield* Match.value(isLegacyConfigFile(configFile, pathService)).pipe(Match.when(true, () => Effect$1.fail(ConfigFileUnsupportedError.make({
992
1135
  file: configFile,
993
1136
  hint: extendsChildHint(configFile)
994
1137
  }))), Match.orElse(() => readConfigModule(configFile, configEnv)));
995
1138
  });
996
- const canonicalConfigFile = (file, pathService) => Match.value(file.startsWith("file:")).pipe(Match.when(true, () => Effect.try({
1139
+ const canonicalConfigFile = (file, pathService) => Match.value(file.startsWith("file:")).pipe(Match.when(true, () => Effect$1.try({
997
1140
  try: () => new URL(file),
998
1141
  catch: (cause) => ConfigFileUnreadableError.make({
999
1142
  file,
1000
1143
  cause
1001
1144
  })
1002
- }).pipe(Effect.flatMap((url) => pathService.fromFileUrl(url).pipe(Effect.mapError((cause) => ConfigFileUnreadableError.make({
1145
+ }).pipe(Effect$1.flatMap((url) => pathService.fromFileUrl(url).pipe(Effect$1.mapError((cause) => ConfigFileUnreadableError.make({
1003
1146
  file,
1004
1147
  cause
1005
- })))))), Match.orElse(() => Effect.succeed(pathService.resolve(file))));
1148
+ })))))), Match.orElse(() => Effect$1.succeed(pathService.resolve(file))));
1006
1149
  function resolveExtendsSpecifier(specifier) {
1007
- return Effect.try({
1150
+ return Effect$1.try({
1008
1151
  try: () => import.meta.resolve(specifier),
1009
1152
  catch: (cause) => ConfigFileUnreadableError.make({
1010
1153
  file: specifier,
@@ -1013,14 +1156,14 @@ function resolveExtendsSpecifier(specifier) {
1013
1156
  });
1014
1157
  }
1015
1158
  function resolveExtends(configFile, document, configEnv) {
1016
- return Effect.gen(function* () {
1159
+ return Effect$1.gen(function* () {
1017
1160
  const pathService = yield* Path.Path;
1018
- const loop = (state, file, currentDocument) => Effect.gen(function* () {
1161
+ const loop = (state, file, currentDocument) => Effect$1.gen(function* () {
1019
1162
  const canonicalFile = yield* canonicalConfigFile(file, pathService);
1020
- return yield* Match.value(decideExtendsStep(state, currentDocument, canonicalFile, pathService)).pipe(Match.tag("done", (d) => Effect.succeed(d.options)), Match.tag("read", (d) => readExtendsChild(d.path, configEnv).pipe(Effect.flatMap((nextDocument) => loop(d.state, d.path, nextDocument)))), Match.tag("resolve", (d) => resolveExtendsSpecifier(d.specifier).pipe(Effect.flatMap((resolvedUrl) => readExtendsChild(resolvedUrl, configEnv).pipe(Effect.flatMap((nextDocument) => loop(d.state, resolvedUrl, nextDocument)))))), Match.tag("refused", (d) => {
1163
+ return yield* Match.value(decideExtendsStep(state, currentDocument, canonicalFile, pathService)).pipe(Match.tag("done", (d) => Effect$1.succeed(d.options)), Match.tag("read", (d) => readExtendsChild(d.path, configEnv).pipe(Effect$1.flatMap((nextDocument) => loop(d.state, d.path, nextDocument)))), Match.tag("resolve", (d) => resolveExtendsSpecifier(d.specifier).pipe(Effect$1.flatMap((resolvedUrl) => readExtendsChild(resolvedUrl, configEnv).pipe(Effect$1.flatMap((nextDocument) => loop(d.state, resolvedUrl, nextDocument)))))), Match.tag("refused", (d) => {
1021
1164
  let message = `Invalid config file "${d.file}". "extends" must be a string`;
1022
1165
  if (d.reason === "cycle") message = `Config inheritance cycle detected at "${d.file}"`;
1023
- return Effect.fail(ConfigFileInvalidError.make({
1166
+ return Effect$1.fail(ConfigFileInvalidError.make({
1024
1167
  file: d.file,
1025
1168
  cause: message
1026
1169
  }));
@@ -1045,10 +1188,10 @@ const mutationRangeBoundErrors = (index, match) => {
1045
1188
  const end = matchLineNumber(match, 5);
1046
1189
  return [...startLineErrors(index, mutationRange, start), ...lineOrderErrors(index, mutationRange, start, end)];
1047
1190
  };
1048
- const requireUnmagicalMutationRange = (mutateString, index, match) => Match.value(new Minimatch(mutateString).hasMagic()).pipe(Match.when(true, () => [`Config option "mutate[${index}]" is invalid. Cannot combine a glob expression with a mutation range in "${mutateString}".`]), Match.orElse(() => mutationRangeBoundErrors(index, match)));
1191
+ const requireUnmagicalMutationRange = (mutateString, index, match) => Match.value(isGlob(mutateString)).pipe(Match.when(true, () => [`Config option "mutate[${index}]" is invalid. Cannot combine a glob expression with a mutation range in "${mutateString}".`]), Match.orElse(() => mutationRangeBoundErrors(index, match)));
1049
1192
  const mutationRangeErrors = (mutateString, index) => Match.value(MUTATION_RANGE_REGEX.exec(mutateString)).pipe(Match.when((match) => match !== null, (match) => requireUnmagicalMutationRange(mutateString, index, match)), Match.orElse(() => []));
1050
- const warnOnIgnoredNodeArgs = (nodeArgs) => Match.value(nodeArgs.length > 0).pipe(Match.when(true, () => Effect.logWarning("Using \"testRunnerNodeArgs\" together with the \"command\" test runner is not supported, these arguments will be ignored. You can add your custom arguments by setting the \"commandRunner.command\" option.")), Match.orElse(() => Effect.void));
1051
- const warnOnCommandRunnerNodeArgs = (options) => Match.value(isCommandRunner(options.testRunner)).pipe(Match.when(true, () => warnOnIgnoredNodeArgs(options.testRunnerNodeArgs)), Match.orElse(() => Effect.void));
1193
+ const warnOnIgnoredNodeArgs = (nodeArgs) => Match.value(nodeArgs.length > 0).pipe(Match.when(true, () => Effect$1.logWarning("Using \"testRunnerNodeArgs\" together with the \"command\" test runner is not supported, these arguments will be ignored. You can add your custom arguments by setting the \"commandRunner.command\" option.")), Match.orElse(() => Effect$1.void));
1194
+ const warnOnCommandRunnerNodeArgs = (options) => Match.value(isCommandRunner(options.testRunner)).pipe(Match.when(true, () => warnOnIgnoredNodeArgs(options.testRunnerNodeArgs)), Match.orElse(() => Effect$1.void));
1052
1195
  const customValidationErrors = (options) => [
1053
1196
  ...thresholdErrors(options),
1054
1197
  ...ignoreStaticErrors(options),
@@ -1056,23 +1199,23 @@ const customValidationErrors = (options) => [
1056
1199
  ];
1057
1200
  function customValidation(options) {
1058
1201
  const additionalErrors = customValidationErrors(options);
1059
- return warnOnCommandRunnerNodeArgs(options).pipe(Effect.flatMap(() => logConfigErrors(additionalErrors)), Effect.flatMap(() => throwErrorIfNeeded(additionalErrors)));
1202
+ return warnOnCommandRunnerNodeArgs(options).pipe(Effect$1.flatMap(() => logConfigErrors(additionalErrors)), Effect$1.flatMap(() => throwErrorIfNeeded(additionalErrors)));
1060
1203
  }
1061
1204
  function schemaValidate(options) {
1062
1205
  const decoded = decodeOptions(options);
1063
1206
  if (Result.isFailure(decoded)) return failWithConfigErrors(describeErrors(decoded.failure));
1064
1207
  Object.assign(options, decoded.success);
1065
- return Effect.succeed(decoded.success);
1208
+ return Effect$1.succeed(decoded.success);
1066
1209
  }
1067
1210
  const configErrorHeadline = (errors) => Match.value(errors.length === 1).pipe(Match.when(true, () => "Please correct this configuration error and try again."), Match.orElse(() => "Please correct these configuration errors and try again."));
1068
1211
  const configErrorMessage = (errors) => `${configErrorHeadline(errors)} ${errors.join(" ")}`;
1069
- const logConfigErrors = (errors) => Effect.gen(function* () {
1070
- for (const error of errors) yield* Effect.logError(error);
1212
+ const logConfigErrors = (errors) => Effect$1.gen(function* () {
1213
+ for (const error of errors) yield* Effect$1.logError(error);
1071
1214
  });
1072
- const failWithConfigErrors = (errors) => logConfigErrors(errors).pipe(Effect.flatMap(() => Effect.fail(ConfigError.make({ message: configErrorMessage(errors) }))));
1215
+ const failWithConfigErrors = (errors) => logConfigErrors(errors).pipe(Effect$1.flatMap(() => Effect$1.fail(ConfigError.make({ message: configErrorMessage(errors) }))));
1073
1216
  function throwErrorIfNeeded(errors) {
1074
- if (errors.length === 0) return Effect.void;
1075
- return Effect.fail(ConfigError.make({ message: configErrorMessage(errors) }));
1217
+ if (errors.length === 0) return Effect$1.void;
1218
+ return Effect$1.fail(ConfigError.make({ message: configErrorMessage(errors) }));
1076
1219
  }
1077
1220
  const OPTIONS_ADDED_BY_STRYKER = [
1078
1221
  "set",
@@ -1084,10 +1227,10 @@ const excessOptionNames = (options, schema) => {
1084
1227
  const schemaKeys = schemaPropertyNames(schema);
1085
1228
  return Object.keys(options).filter((key) => key.endsWith("_comment") === false).filter((key) => OPTIONS_ADDED_BY_STRYKER.includes(key) === false).filter((key) => schemaKeys.includes(key) === false);
1086
1229
  };
1087
- const warnAboutUnknownOptions = (options, excessNames) => Effect.gen(function* () {
1088
- for (const excessPropertyName of excessNames) yield* Effect.logWarning(`Unknown stryker config option "${excessPropertyName}".`);
1089
- const pluginsJson = yield* S.encodeEffect(S.fromJsonString(S.Array(S.String)))([...options.plugins]).pipe(Effect.orDie);
1090
- yield* Effect.logWarning(`Possible causes:
1230
+ const warnAboutUnknownOptions = (options, excessNames) => Effect$1.gen(function* () {
1231
+ for (const excessPropertyName of excessNames) yield* Effect$1.logWarning(`Unknown stryker config option "${excessPropertyName}".`);
1232
+ const pluginsJson = yield* S.encodeEffect(S.fromJsonString(S.Array(S.String)))([...options.plugins]).pipe(Effect$1.orDie);
1233
+ yield* Effect$1.logWarning(`Possible causes:
1091
1234
  * Is it a typo on your end?
1092
1235
  * Did you only write this property as a comment? If so, please postfix it with "_comment".
1093
1236
  * You might be missing a plugin that is supposed to use it. Stryker loaded plugins from: ${pluginsJson}
@@ -1096,39 +1239,39 @@ const warnAboutUnknownOptions = (options, excessNames) => Effect.gen(function* (
1096
1239
  });
1097
1240
  const unknownOptionWarning = (options, schema) => {
1098
1241
  const excessNames = excessOptionNames(options, schema);
1099
- return Match.value(excessNames.length > 0).pipe(Match.when(true, () => warnAboutUnknownOptions(options, excessNames)), Match.orElse(() => Effect.void));
1242
+ return Match.value(excessNames.length > 0).pipe(Match.when(true, () => warnAboutUnknownOptions(options, excessNames)), Match.orElse(() => Effect$1.void));
1100
1243
  };
1101
1244
  function markExcessOptions(options, schema) {
1102
- return Effect.gen(function* () {
1245
+ return Effect$1.gen(function* () {
1103
1246
  if (isWarningEnabled("unknownOptions", options.warnings)) yield* unknownOptionWarning(options, schema);
1104
1247
  });
1105
1248
  }
1106
- const logUnserializableWarnings = (unserializables) => Effect.gen(function* () {
1107
- for (const unserializable of unserializables) yield* Effect.logWarning(`Config option "${unserializable.path.join(".")}" is not (fully) serializable. ${unserializable.reason}. Any test runner or checker worker processes might not receive this value as intended.`);
1108
- yield* Effect.logWarning(`(disable ${optionsPath("warnings", "unserializableOptions")} to ignore this warning)`);
1249
+ const logUnserializableWarnings = (unserializables) => Effect$1.gen(function* () {
1250
+ for (const unserializable of unserializables) yield* Effect$1.logWarning(`Config option "${unserializable.path.join(".")}" is not (fully) serializable. ${unserializable.reason}. Any test runner or checker worker processes might not receive this value as intended.`);
1251
+ yield* Effect$1.logWarning(`(disable ${optionsPath("warnings", "unserializableOptions")} to ignore this warning)`);
1109
1252
  });
1110
- const warnAboutUnserializableOptions = (options) => Match.value(findUnserializables(options)).pipe(Match.when(void 0, () => Effect.void), Match.orElse((unserializables) => logUnserializableWarnings(unserializables)));
1253
+ const warnAboutUnserializableOptions = (options) => Match.value(findUnserializables(options)).pipe(Match.when(void 0, () => Effect$1.void), Match.orElse((unserializables) => logUnserializableWarnings(unserializables)));
1111
1254
  function markUnserializableOptions(options) {
1112
- return Effect.gen(function* () {
1255
+ return Effect$1.gen(function* () {
1113
1256
  if (isWarningEnabled("unserializableOptions", options.warnings)) yield* warnAboutUnserializableOptions(options);
1114
1257
  });
1115
1258
  }
1116
1259
  function markOptions(options, schema) {
1117
- return Effect.gen(function* () {
1260
+ return Effect$1.gen(function* () {
1118
1261
  yield* markExcessOptions(options, schema);
1119
1262
  yield* markUnserializableOptions(options);
1120
1263
  });
1121
1264
  }
1122
1265
  function validateOptions(options, schema) {
1123
- return Effect.gen(function* () {
1266
+ return Effect$1.gen(function* () {
1124
1267
  const typed = yield* schemaValidate(options);
1125
1268
  yield* customValidation(typed);
1126
1269
  yield* markOptions(typed, schema);
1127
1270
  return typed;
1128
1271
  });
1129
1272
  }
1130
- const createDefaultOptions = S.decodeEffect(StrykerOptionsSchema)({}).pipe(Effect.orDie);
1131
- Effect.map(createDefaultOptions, (opts) => deepFreeze(opts));
1273
+ const createDefaultOptions = S.decodeEffect(StrykerOptionsSchema)({}).pipe(Effect$1.orDie);
1274
+ Effect$1.map(createDefaultOptions, (opts) => deepFreeze(opts));
1132
1275
  `
1133
1276
  Example of how a config file should look:
1134
1277
  /**
@@ -1142,29 +1285,29 @@ A config file is a TypeScript or ESM JavaScript module: stryker.conf.ts, stryker
1142
1285
 
1143
1286
  See https://stryker-mutator.io/docs/stryker-js/config-file for more information.`.trim();
1144
1287
  function exists(fileName) {
1145
- return Effect.gen(function* () {
1146
- return yield* (yield* FileSystem.FileSystem).access(fileName).pipe(Effect.as(true), Effect.catchTag("PlatformError", (error) => Match.value(error.reason).pipe(Match.tag("NotFound", () => Effect.succeed(false)), Match.orElse(() => Effect.fail(ConfigFileUnreadableError.make({
1288
+ return Effect$1.gen(function* () {
1289
+ return yield* (yield* FileSystem.FileSystem).access(fileName).pipe(Effect$1.as(true), Effect$1.catchTag("PlatformError", (error) => Match.value(error.reason).pipe(Match.tag("NotFound", () => Effect$1.succeed(false)), Match.orElse(() => Effect$1.fail(ConfigFileUnreadableError.make({
1147
1290
  file: fileName,
1148
1291
  cause: error
1149
- }))))), Effect.mapError((error) => ConfigFileUnreadableError.make({
1292
+ }))))), Effect$1.mapError((error) => ConfigFileUnreadableError.make({
1150
1293
  file: fileName,
1151
1294
  cause: error
1152
1295
  })));
1153
1296
  });
1154
1297
  }
1155
- const requireExistingConfigFile = (configFileName) => exists(configFileName).pipe(Effect.flatMap((doesExist) => Match.value(doesExist).pipe(Match.when(true, () => Effect.succeed(configFileName)), Match.orElse(() => Effect.fail(ConfigFileNotFoundError.make({ file: configFileName }))))));
1298
+ const requireExistingConfigFile = (configFileName) => exists(configFileName).pipe(Effect$1.flatMap((doesExist) => Match.value(doesExist).pipe(Match.when(true, () => Effect$1.succeed(configFileName)), Match.orElse(() => Effect$1.fail(ConfigFileNotFoundError.make({ file: configFileName }))))));
1156
1299
  const firstExistingConfigFile = (fileNames) => Option.match(Option.fromUndefinedOr(fileNames[0]), {
1157
- onNone: () => Effect.succeedNone,
1158
- onSome: (head) => exists(head).pipe(Effect.flatMap((doesExist) => {
1159
- if (doesExist) return Effect.succeedSome(head);
1300
+ onNone: () => Effect$1.succeedNone,
1301
+ onSome: (head) => exists(head).pipe(Effect$1.flatMap((doesExist) => {
1302
+ if (doesExist) return Effect$1.succeedSome(head);
1160
1303
  return firstExistingConfigFile(fileNames.slice(1));
1161
1304
  }))
1162
1305
  });
1163
- const configFileFor = (configFileName) => Effect.gen(function* () {
1306
+ const configFileFor = (configFileName) => Effect$1.gen(function* () {
1164
1307
  const pathService = yield* Path.Path;
1165
1308
  const supported = SUPPORTED_CONFIG_FILE_EXTENSIONS.includes(configFileExtension(configFileName, pathService));
1166
1309
  const legacy = isLegacyConfigFile(configFileName, pathService);
1167
- return yield* Match.value(supported).pipe(Match.when(true, () => requireExistingConfigFile(configFileName)), Match.orElse(() => Effect.fail(ConfigFileUnsupportedError.make({
1310
+ return yield* Match.value(supported).pipe(Match.when(true, () => requireExistingConfigFile(configFileName)), Match.orElse(() => Effect$1.fail(ConfigFileUnsupportedError.make({
1168
1311
  file: configFileName,
1169
1312
  hint: Match.value(legacy).pipe(Match.when(true, () => legacyConfigHint(configFileName)), Match.orElse(() => unsupportedConfigHint(configFileName)))
1170
1313
  }))));
@@ -1174,43 +1317,43 @@ const legacyConfigError = (file) => ConfigFileUnsupportedError.make({
1174
1317
  file,
1175
1318
  hint: legacyConfigHint(file)
1176
1319
  });
1177
- const legacyConfigWarning = (file, supportedFile) => Effect.logWarning(shadowedLegacyWarning(file, supportedFile));
1178
- const refuseLegacyOnlyProject = () => firstLegacyConfigFile().pipe(Effect.flatMap((legacyFile) => Option.match(legacyFile, {
1179
- onNone: () => Effect.succeedNone,
1180
- onSome: (file) => Effect.fail(legacyConfigError(file))
1320
+ const legacyConfigWarning = (file, supportedFile) => Effect$1.logWarning(shadowedLegacyWarning(file, supportedFile));
1321
+ const refuseLegacyOnlyProject = () => firstLegacyConfigFile().pipe(Effect$1.flatMap((legacyFile) => Option.match(legacyFile, {
1322
+ onNone: () => Effect$1.succeedNone,
1323
+ onSome: (file) => Effect$1.fail(legacyConfigError(file))
1181
1324
  })));
1182
- const warnShadowedLegacyConfig = (supportedFile) => firstLegacyConfigFile().pipe(Effect.flatMap((legacyFile) => Option.match(legacyFile, {
1183
- onNone: () => Effect.succeed(supportedFile),
1184
- onSome: (file) => Effect.as(legacyConfigWarning(file, supportedFile), supportedFile)
1325
+ const warnShadowedLegacyConfig = (supportedFile) => firstLegacyConfigFile().pipe(Effect$1.flatMap((legacyFile) => Option.match(legacyFile, {
1326
+ onNone: () => Effect$1.succeed(supportedFile),
1327
+ onSome: (file) => Effect$1.as(legacyConfigWarning(file, supportedFile), supportedFile)
1185
1328
  })));
1186
- const discoverConfigFile = () => firstExistingConfigFile([...SUPPORTED_CONFIG_FILE_NAMES]).pipe(Effect.flatMap((found) => Option.match(found, {
1187
- onNone: () => refuseLegacyOnlyProject().pipe(Effect.map((legacy) => Option.getOrUndefined(legacy))),
1329
+ const discoverConfigFile = () => firstExistingConfigFile([...SUPPORTED_CONFIG_FILE_NAMES]).pipe(Effect$1.flatMap((found) => Option.match(found, {
1330
+ onNone: () => refuseLegacyOnlyProject().pipe(Effect$1.map((legacy) => Option.getOrUndefined(legacy))),
1188
1331
  onSome: (supportedFile) => warnShadowedLegacyConfig(supportedFile)
1189
1332
  })));
1190
1333
  function findConfigFile(configFileName) {
1191
1334
  return Match.value(configFileName).pipe(Match.when(Match.string, (fileName) => configFileFor(fileName)), Match.orElse(() => discoverConfigFile()));
1192
1335
  }
1193
- const resolveChildExtends = (configFile, child, configEnv) => Match.value("extends" in child).pipe(Match.when(true, () => resolveExtends(configFile, child, configEnv)), Match.orElse(() => Effect.succeed(child)));
1194
- const isCiEnvironment = Config.string("CI").pipe(Effect.map((value) => Match.value(value.trim().toLowerCase()).pipe(Match.when("", () => false), Match.when("0", () => false), Match.when("false", () => false), Match.orElse(() => true))), Effect.orElseSucceed(() => false));
1336
+ const resolveChildExtends = (configFile, child, configEnv) => Match.value("extends" in child).pipe(Match.when(true, () => resolveExtends(configFile, child, configEnv)), Match.orElse(() => Effect$1.succeed(child)));
1337
+ const isCiEnvironment = Config.string("CI").pipe(Effect$1.map((value) => Match.value(value.trim().toLowerCase()).pipe(Match.when("", () => false), Match.when("0", () => false), Match.when("false", () => false), Match.orElse(() => true))), Effect$1.orElseSucceed(() => false));
1195
1338
  function loadOptionsFromConfigFile(cliOptions, configEnv) {
1196
- return findConfigFile(cliOptions["configFile"]).pipe(Effect.flatMap((configFile) => Match.value(configFile).pipe(Match.when(void 0, () => Effect.succeed({})), Match.orElse((found) => readConfigModule(found, configEnv).pipe(Effect.flatMap((child) => resolveChildExtends(found, child, configEnv)))))));
1339
+ return findConfigFile(cliOptions["configFile"]).pipe(Effect$1.flatMap((configFile) => Match.value(configFile).pipe(Match.when(void 0, () => Effect$1.succeed({})), Match.orElse((found) => readConfigModule(found, configEnv).pipe(Effect$1.flatMap((child) => resolveChildExtends(found, child, configEnv)))))));
1197
1340
  }
1198
1341
  function readConfig(cliOptions, invocation) {
1199
- return Effect.gen(function* () {
1342
+ return Effect$1.gen(function* () {
1200
1343
  const configEnv = {
1201
1344
  command: invocation.command,
1202
1345
  mode: invocation.mode,
1203
1346
  isDryRun: cliOptions["dryRunOnly"] === true,
1204
1347
  isCi: yield* isCiEnvironment
1205
1348
  };
1206
- const cliRecord = yield* S.decodeUnknownEffect(ConfigDocumentSchema)(cliOptions).pipe(Effect.orDie);
1349
+ const cliRecord = yield* S.decodeUnknownEffect(ConfigDocumentSchema)(cliOptions).pipe(Effect$1.orDie);
1207
1350
  const fileRecord = yield* loadOptionsFromConfigFile(cliRecord, configEnv);
1208
1351
  const fileOptions = yield* Result.match(S.decodeUnknownResult(ConfigDocumentSchema)(fileRecord), {
1209
- onFailure: (cause) => Effect.fail(ConfigFileInvalidError.make({
1352
+ onFailure: (cause) => Effect$1.fail(ConfigFileInvalidError.make({
1210
1353
  file: "config",
1211
1354
  cause
1212
1355
  })),
1213
- onSuccess: (options) => Effect.succeed(options)
1356
+ onSuccess: (options) => Effect$1.succeed(options)
1214
1357
  });
1215
1358
  const merged = mergeConfig(fileOptions, cliRecord);
1216
1359
  const decoded = S.decodeUnknownResult(StrykerOptionsSchema)(merged);
@@ -1313,7 +1456,7 @@ const buildPluginLoadPlan = (entries) => {
1313
1456
  shadowings: shadowingState.shadowings
1314
1457
  };
1315
1458
  };
1316
- const failPluginLoad = (descriptor, error) => Effect.logWarning(`Error during loading "${descriptor}" plugin`).pipe(Effect.andThen(() => Effect.fail(PluginLoadFailedError.make({
1459
+ const failPluginLoad = (descriptor, error) => Effect$1.logWarning(`Error during loading "${descriptor}" plugin`).pipe(Effect$1.andThen(() => Effect$1.fail(PluginLoadFailedError.make({
1317
1460
  descriptor,
1318
1461
  cause: error
1319
1462
  }))));
@@ -1330,37 +1473,37 @@ const hasContribution = (contributions) => [
1330
1473
  contributions.ignorers,
1331
1474
  contributions.schemaContribution
1332
1475
  ].some((contribution) => contribution !== void 0);
1333
- const warnUndescribedPluginModule = (descriptor) => Effect.logWarning(`Module "${descriptor}" did not contribute a StrykerJS plugin. It didn't export a "strykerPlugins", "strykerIgnorers", or "strykerValidationSchema".`).pipe(Effect.as(void 0));
1476
+ const warnUndescribedPluginModule = (descriptor) => Effect$1.logWarning(`Module "${descriptor}" did not contribute a StrykerJS plugin. It didn't export a "strykerPlugins", "strykerIgnorers", or "strykerValidationSchema".`).pipe(Effect$1.as(void 0));
1334
1477
  const describeLoadedPlugin = (descriptor, module) => Result.match(pluginContributionsOf(module), {
1335
1478
  onFailure: (cause) => failPluginLoad(descriptor, cause),
1336
- onSuccess: (contributions) => Match.value(hasContribution(contributions)).pipe(Match.when(true, () => Effect.succeed(contributions)), Match.orElse(() => warnUndescribedPluginModule(descriptor)))
1479
+ onSuccess: (contributions) => Match.value(hasContribution(contributions)).pipe(Match.when(true, () => Effect$1.succeed(contributions)), Match.orElse(() => warnUndescribedPluginModule(descriptor)))
1337
1480
  });
1338
1481
  function loadPlugin(descriptor, entrypoint) {
1339
- return Effect.gen(function* () {
1340
- yield* Effect.logDebug(`Loading plugin ${descriptor}`);
1341
- const maybeModule = yield* importModule(entrypoint).pipe(Effect.catch((error) => failPluginLoad(descriptor, error)));
1482
+ return Effect$1.gen(function* () {
1483
+ yield* Effect$1.logDebug(`Loading plugin ${descriptor}`);
1484
+ const maybeModule = yield* importModule(entrypoint).pipe(Effect$1.catch((error) => failPluginLoad(descriptor, error)));
1342
1485
  const module = Option.getOrUndefined(Option.fromUndefinedOr(maybeModule));
1343
1486
  if (module === void 0) return;
1344
1487
  return yield* describeLoadedPlugin(descriptor, module);
1345
1488
  });
1346
1489
  }
1347
1490
  function loadPlugins(pluginDescriptors) {
1348
- return Effect.gen(function* () {
1491
+ return Effect$1.gen(function* () {
1349
1492
  const path = yield* Path.Path;
1350
- const entrypoints = yield* Effect.forEach(Array$1.fromIterable(HashSet.fromIterable(pluginDescriptors)), (specifier) => path.fromFileUrl(new URL(specifier)).pipe(Effect.map((entrypoint) => ({
1493
+ const entrypoints = yield* Effect$1.forEach(Array$1.fromIterable(HashSet.fromIterable(pluginDescriptors)), (specifier) => path.fromFileUrl(new URL(specifier)).pipe(Effect$1.map((entrypoint) => ({
1351
1494
  specifier,
1352
1495
  entrypoint
1353
- })), Effect.mapError((cause) => PluginLoadFailedError.make({
1496
+ })), Effect$1.mapError((cause) => PluginLoadFailedError.make({
1354
1497
  descriptor: specifier,
1355
1498
  cause
1356
1499
  }))), { concurrency: "unbounded" });
1357
- const loaded = yield* Effect.forEach(entrypoints, (resolved) => loadPlugin(resolved.specifier, resolved.entrypoint).pipe(Effect.map((plugin) => {
1500
+ const loaded = yield* Effect$1.forEach(entrypoints, (resolved) => loadPlugin(resolved.specifier, resolved.entrypoint).pipe(Effect$1.map((plugin) => {
1358
1501
  if (plugin === void 0) return;
1359
1502
  return {
1360
1503
  ...plugin,
1361
- moduleName: resolved.entrypoint
1504
+ moduleName: resolved.specifier
1362
1505
  };
1363
- })), { concurrency: "unbounded" }).pipe(Effect.map((arr) => arr.filter(Predicate.isNotNullish)));
1506
+ })), { concurrency: "unbounded" }).pipe(Effect$1.map((arr) => arr.filter(Predicate.isNotNullish)));
1364
1507
  const ignorers = loaded.flatMap((entry) => entry.ignorers ?? NO_IGNORERS);
1365
1508
  const entries = loaded.map((entry) => ({
1366
1509
  moduleName: entry.moduleName,
@@ -1368,7 +1511,7 @@ function loadPlugins(pluginDescriptors) {
1368
1511
  schemaContribution: entry.schemaContribution
1369
1512
  }));
1370
1513
  const plan_ = buildPluginLoadPlan(entries);
1371
- for (const shadowing of plan_.shadowings) yield* Effect.logWarning(`Plugin "${shadowing.name}" of kind "${shadowing.kind}" at index ${shadowing.winnerIndex} shadows plugin at index ${shadowing.shadowedIndex}.`);
1514
+ for (const shadowing of plan_.shadowings) yield* Effect$1.logWarning(`Plugin "${shadowing.name}" of kind "${shadowing.kind}" at index ${shadowing.winnerIndex} shadows plugin at index ${shadowing.shadowedIndex}.`);
1372
1515
  return {
1373
1516
  schemaContributions: plan_.schemaContributions,
1374
1517
  pluginsByKind: plan_.pluginsByKind,
@@ -1378,14 +1521,21 @@ function loadPlugins(pluginDescriptors) {
1378
1521
  };
1379
1522
  });
1380
1523
  }
1524
+ const pluginUrlsFromOptions = (options) => [
1525
+ ...options.plugins,
1526
+ ...options.appendPlugins,
1527
+ ...options.ignorers,
1528
+ ...Match.value(options.testRunner).pipe(Match.when(isCustomTestRunner, (runner) => [runner.plugin]), Match.orElse(() => [])),
1529
+ ...options.checkers.map((checker) => checker.plugin)
1530
+ ];
1381
1531
  function hasValidationSchemaContribution(module) {
1382
1532
  return Schema.is(SchemaValidationContributionSchema)(module);
1383
1533
  }
1384
1534
  const findByKindAndName = (items, kind, name) => Option.fromUndefinedOr(items.find((item) => item.kind === kind && item.name.toLowerCase() === name.toLowerCase()));
1385
- const findContribution = (descriptors, kind, name) => Effect.fromOption(Option.filter(findByKindAndName(descriptors, kind, name), (descriptor) => descriptor.kind === kind), () => PluginNotFoundError.make({ descriptor: `${kind}:${name} (available: ${descriptors.map((d) => d.name).join(", ")})` }));
1535
+ const findContribution = (descriptors, kind, name) => Effect$1.fromOption(Option.filter(findByKindAndName(descriptors, kind, name), (descriptor) => descriptor.kind === kind), () => PluginNotFoundError.make({ descriptor: `${kind}:${name} (available: ${descriptors.map((d) => d.name).join(", ")})` }));
1386
1536
  function findPlugin(pluginsByKind, kind, name) {
1387
1537
  return Option.match(HashMap.get(pluginsByKind, kind), {
1388
- onNone: () => Effect.fail(PluginNotFoundError.make({ descriptor: `${kind}:${name} (no ${kind} plugins were loaded)` })),
1538
+ onNone: () => Effect$1.fail(PluginNotFoundError.make({ descriptor: `${kind}:${name} (no ${kind} plugins were loaded)` })),
1389
1539
  onSome: (descriptors) => findContribution(descriptors, kind, name)
1390
1540
  });
1391
1541
  }
@@ -1394,8 +1544,8 @@ function create(pluginsByKind, kind, name) {
1394
1544
  }
1395
1545
  function createAll(pluginsByKind, kind) {
1396
1546
  const descriptors = HashMap.get(pluginsByKind, kind);
1397
- if (Option.isNone(descriptors)) return Effect.succeed([]);
1398
- return Effect.succeed(descriptors.value.filter((d) => d.kind === kind));
1547
+ if (Option.isNone(descriptors)) return Effect$1.succeed([]);
1548
+ return Effect$1.succeed(descriptors.value.filter((d) => d.kind === kind));
1399
1549
  }
1400
1550
  //#endregion
1401
1551
  //#region src/plugin-worker-entry.ts
@@ -1404,10 +1554,32 @@ const missingWorkerEntry = (stage, kind, name) => (failure) => StageError.make({
1404
1554
  reason: `the ${kind} plugin "${name}" is not among the loaded plugins`,
1405
1555
  cause: failure
1406
1556
  });
1407
- const requiredSource = (params) => Effect.fromOption(findByKindAndName(params.loaded.pluginSources, params.kind, params.name), () => PluginNotFoundError.make({ descriptor: `${params.kind}:${params.name}` }));
1408
- const resolvePluginWorkerEntry = (params) => requiredSource(params).pipe(Effect.map((source) => ({
1557
+ const requiredSource = (params) => Effect$1.fromOption(findByKindAndName(params.loaded.pluginSources, params.kind, params.name), () => PluginNotFoundError.make({ descriptor: `${params.kind}:${params.name}` }));
1558
+ const resolvePluginWorkerEntry = (params) => requiredSource(params).pipe(Effect$1.map((source) => ({
1409
1559
  kind: params.kind,
1410
1560
  entrypoint: source.workerEntry
1411
1561
  })));
1562
+ const resolveConfiguredWorkerSpawn = (params) => {
1563
+ const byName = (name) => requiredSource({
1564
+ loaded: params.loaded,
1565
+ kind: params.kind,
1566
+ name
1567
+ }).pipe(Effect$1.map((source) => ({
1568
+ name,
1569
+ spawn: {
1570
+ kind: params.kind,
1571
+ entrypoint: source.workerEntry
1572
+ }
1573
+ })));
1574
+ if (typeof params.configured === "string") return byName(params.configured);
1575
+ const pluginUrl = params.configured.plugin;
1576
+ return Effect$1.fromOption(Option.map(Option.fromUndefinedOr(params.loaded.pluginSources.find((source) => source.kind === params.kind && source.modulePath === pluginUrl)), (source) => ({
1577
+ name: source.name,
1578
+ spawn: {
1579
+ kind: params.kind,
1580
+ entrypoint: source.workerEntry
1581
+ }
1582
+ })), () => PluginNotFoundError.make({ descriptor: `${params.kind}:${pluginUrl}` }));
1583
+ };
1412
1584
  //#endregion
1413
- export { PrepareError as $, OutOfMemoryError as A, ConfigDocumentSchema as B, connectRetry as C, layer as D, classifyWorkerExit as E, vmRunnerName as F, ConfigFileUnsupportedError as G, ConfigFileInvalidError as H, vmTestRunner as I, MergeResult as J, ImportedModuleSchema as K, StrykerError as L, VmRunner as M, isVmRunner as N, makeConcurrency as O, vmRunnerCapabilities as P, survivorsPriorReport as Q, ALWAYS_IGNORE as R, WorkerLauncher as S, IdGenerator as T, ConfigFileNotFoundError as U, ConfigError as V, ConfigFileUnreadableError as W, extendsPropertySchema as X, ReadConfigCommand as Y, forkOptionsSchema as Z, validateOptions as _, loadPlugins as a, makeChildProcessTestRunner as b, decideExtendsStep as c, importModule as d, StageError as et, initialExtendsStepState as f, resolveExtends as g, readConfig as h, createAll as i, WorkerBootTimeoutError as j, ChildProcessCrashedError as k, describeErrors as l, mergeConfigs as m, resolvePluginWorkerEntry as n, PluginLoadFailedError as o, loadConfigCell as p, MergeCommand as q, create as r, PluginNotFoundError as s, missingWorkerEntry as t, forkCoreSchema as u, buildTestRunner as v, makeWorkerClient as w, nodePlatformLayer as x, isCommandRunner as y, MUTATION_RANGE_REGEX as z };
1585
+ export { ExtendsStepRefused as $, makeConcurrency as A, partsOfEffectSpan as B, nodePlatformLayer as C, IdGenerator as D, makeWorkerClient as E, isVmRunner as F, ConfigError as G, ALWAYS_IGNORE as H, vmRunnerCapabilities as I, ConfigFileUnreadableError as J, ConfigFileInvalidError as K, vmRunnerName as L, OutOfMemoryError as M, WorkerBootTimeoutError as N, classifyWorkerExit as O, VmRunner as P, ExtendsStepRead as Q, vmTestRunner as R, makeChildProcessTestRunner as S, connectRetry as T, MUTATION_RANGE_REGEX as U, StrykerError as V, ConfigDocumentSchema as W, ExtendsStepDocumentSchema as X, ConfigFileUnsupportedError as Y, ExtendsStepDone as Z, readConfig as _, createAll as a, ReadConfigCommand as at, buildTestRunner as b, PluginLoadFailedError as c, survivorsPriorReport as ct, describeErrors as d, PrepareError as dt, ExtendsStepResolve as et, forkCoreSchema as f, StageError as ft, mergeConfigs as g, loadConfigCell as h, create as i, MergeResult as it, ChildProcessCrashedError as j, layer as k, PluginNotFoundError as l, compileIgnoreRule as lt, initialExtendsStepState as m, resolveConfiguredWorkerSpawn as n, ImportedModuleSchema as nt, loadPlugins as o, extendsPropertySchema as ot, importModule as p, ConfigFileNotFoundError as q, resolvePluginWorkerEntry as r, MergeCommand as rt, pluginUrlsFromOptions as s, forkOptionsSchema as st, missingWorkerEntry as t, ExtendsStepStateSchema as tt, decideExtendsStep as u, matchesGlob as ut, resolveExtends as v, WorkerLauncher as w, isCommandRunner as x, validateOptions as y, encodeWorkerOptions as z };