@systemfsoftware/stryker-js 11.0.0 → 12.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.
- package/CHANGELOG.md +51 -0
- package/README.md +49 -27
- package/dist/{dist-ClUhPgb6.mjs → Run.schema-BaK_pxuK.mjs} +2969 -2715
- package/dist/{Run.schema-CUpTIyrj.d.mts → Run.schema-BnUKGQjA.d.mts} +4 -2
- package/dist/{RunEnvironment.service-zgwzyXpO.d.mts → RunEnvironment.service-BaTBH0mI.d.mts} +52 -44
- package/dist/config.d.mts +15 -3
- package/dist/config.mjs +7 -2
- package/dist/events.d.mts +1 -1
- package/dist/events.mjs +1 -1
- package/dist/{index-CMCCQdTd.d.mts → index-CKd1sAni.d.mts} +930 -918
- package/dist/index.d.mts +36 -27
- package/dist/index.mjs +8 -5
- package/dist/main.mjs +25238 -53532
- package/dist/merge-config-ByZJPeQZ.mjs +32 -0
- package/dist/promises.d.mts +2 -2
- package/dist/promises.mjs +1 -1
- package/dist/{run-stages.cell-CPpkn7og.mjs → run-stages.cell-RwTUyNX9.mjs} +753 -663
- package/dist/stryker-config.schema-VVxHqsAv.d.mts +18 -0
- package/package.json +16 -20
- package/dist/Run.schema-B_qdjbe9.mjs +0 -226
- package/dist/dist-DKhCurgc.mjs +0 -1524
- package/dist/stryker-config.schema-CCnDtVuW.mjs +0 -82
- package/dist/stryker-config.schema-lr7GMjpY.d.mts +0 -35
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
3
|
-
import {
|
|
4
|
-
import { Cell, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
1
|
+
import { A as Plugin_exports, D as VerdictReached, E as SkippedReported, F as ErrorText_exports, I as Format_exports, L as Instrument_exports, M as Reporter_exports, N as TestRunner_exports, O as Checker_exports, P as Trace_exports$1, R as Mutant_exports, _ as PluginsReported, b as RunFailed$1, c as Heartbeat, f as OutputMode, i as FormatRegistryResolved, j as Report_exports, k as Options_exports, l as HelpRendered, m as PlanKnown, n as StageError, p as PhaseEntered, t as PrepareError, u as ModeSignal, w as RunStarted, x as RunMutantTested, y as RunEvent } from "./Run.schema-BaK_pxuK.mjs";
|
|
2
|
+
import { t as mergeConfig } from "./merge-config-ByZJPeQZ.mjs";
|
|
3
|
+
import { Blueprint, Cell, Handle, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
5
4
|
import * as Boolean$1 from "effect/Boolean";
|
|
6
5
|
import * as Match from "effect/Match";
|
|
7
6
|
import * as Option$1 from "effect/Option";
|
|
@@ -9,22 +8,21 @@ import * as Predicate$1 from "effect/Predicate";
|
|
|
9
8
|
import * as Result from "effect/Result";
|
|
10
9
|
import * as S from "effect/Schema";
|
|
11
10
|
import * as Effect$1 from "effect/Effect";
|
|
12
|
-
import { absurd, dual } from "effect/Function";
|
|
11
|
+
import { absurd, dual, pipe } from "effect/Function";
|
|
13
12
|
import * as Arr from "effect/Array";
|
|
14
13
|
import * as SchemaGetter$1 from "effect/SchemaGetter";
|
|
15
|
-
import { Prototype } from "effect/Pipeable";
|
|
16
14
|
import * as Context from "effect/Context";
|
|
17
|
-
import { Boolean, Option, Predicate, Schema, SchemaGetter } from "effect";
|
|
15
|
+
import { Boolean, Option, Predicate, Schema, SchemaGetter, SchemaTransformation } from "effect";
|
|
16
|
+
import * as Exit from "effect/Exit";
|
|
18
17
|
import * as RpcMiddleware from "effect/unstable/rpc/RpcMiddleware";
|
|
19
|
-
import * as Metric from "effect/Metric";
|
|
20
18
|
import * as Cause from "effect/Cause";
|
|
19
|
+
import * as Metric from "effect/Metric";
|
|
21
20
|
import * as SchemaTransformation$1 from "effect/SchemaTransformation";
|
|
22
21
|
import * as Record from "effect/Record";
|
|
23
22
|
import * as Path from "effect/Path";
|
|
24
23
|
import * as Config from "effect/Config";
|
|
25
24
|
import * as FileSystem from "effect/FileSystem";
|
|
26
25
|
import * as Clock from "effect/Clock";
|
|
27
|
-
import * as Exit from "effect/Exit";
|
|
28
26
|
import * as Stream from "effect/Stream";
|
|
29
27
|
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
30
28
|
import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
|
|
@@ -61,15 +59,15 @@ import { RpcClientError } from "effect/unstable/rpc/RpcClientError";
|
|
|
61
59
|
import * as Socket from "effect/unstable/socket/Socket";
|
|
62
60
|
import * as NodeFileSystem$1 from "@effect/platform-node-shared/NodeFileSystem";
|
|
63
61
|
import * as NodePath$1 from "@effect/platform-node-shared/NodePath";
|
|
64
|
-
import * as Equivalence from "effect/Equivalence";
|
|
65
62
|
import { badArgument } from "effect/PlatformError";
|
|
66
|
-
import
|
|
63
|
+
import * as Equivalence from "effect/Equivalence";
|
|
67
64
|
import * as Console from "effect/Console";
|
|
68
65
|
import * as Formatter from "effect/Formatter";
|
|
69
66
|
import * as Runtime from "effect/Runtime";
|
|
70
67
|
import * as Order from "effect/Order";
|
|
71
68
|
import * as CliError from "effect/unstable/cli/CliError";
|
|
72
69
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
70
|
+
import "effect/Deferred";
|
|
73
71
|
import * as Pool from "effect/Pool";
|
|
74
72
|
import * as Semaphore from "effect/Semaphore";
|
|
75
73
|
//#region src/admit-checker-answer.workflow.ts
|
|
@@ -180,14 +178,15 @@ var WorkerBootTimeoutError = class extends Schema.TaggedError()("WorkerBootTimeo
|
|
|
180
178
|
};
|
|
181
179
|
//#endregion
|
|
182
180
|
//#region src/Checker/Checker.handle.ts
|
|
183
|
-
const TypeId$
|
|
181
|
+
const TypeId$10 = Symbol.for("~systemfsoftware/stryker-js/Checker");
|
|
184
182
|
const checkerDuration = Metric.timer("stryker.checker.duration", { description: "Checker worker RPC duration in milliseconds" });
|
|
185
183
|
const checkerMutantsChecked = Metric.counter("stryker.checker.mutants.checked", { description: "Total number of mutants a checker worker answered for" });
|
|
186
184
|
const checkerRpcFailures = Metric.counter("stryker.checker.rpc_failures", {
|
|
187
185
|
description: "Checker worker RPC calls that did not complete, excluding interruptions",
|
|
188
186
|
incremental: true
|
|
189
187
|
});
|
|
190
|
-
const
|
|
188
|
+
const CheckerHandle = Handle.make()(TypeId$10);
|
|
189
|
+
const isCheckerHandle = CheckerHandle.is;
|
|
191
190
|
const connectionCrashed = (cause) => ChildProcessCrashedError.make({
|
|
192
191
|
pid: 0,
|
|
193
192
|
exit: {
|
|
@@ -200,24 +199,17 @@ const recordCheckerCall = (spanName, checkerName, mutants, call) => call.pipe(Ef
|
|
|
200
199
|
"stryker.checker.name": checkerName,
|
|
201
200
|
"stryker.mutants.count": mutants.length
|
|
202
201
|
} }), Effect$1.timed, Effect$1.onExit((exit) => Match.value(exit).pipe(Match.tag("Success", () => Metric.update(checkerMutantsChecked, mutants.length)), Match.tag("Failure", (failure) => failure.cause.pipe(Cause.hasInterruptsOnly, Match.value, Match.when(true, () => Effect$1.void), Match.orElse(() => Metric.update(checkerRpcFailures, 1)))), Match.exhaustive)), Effect$1.tap(([duration]) => Metric.update(checkerDuration, duration)), Effect$1.map(([, result]) => result), Effect$1.mapError((error) => Match.value(error).pipe(Match.tag("CheckerFailed", (failed) => failed), Match.orElse((e) => connectionCrashed(e.message)))));
|
|
203
|
-
const checkOf = (self, checkerName, mutants) => recordCheckerCall("stryker.checker.check", checkerName, mutants, self
|
|
202
|
+
const checkOf = (self, checkerName, mutants) => recordCheckerCall("stryker.checker.check", checkerName, mutants, CheckerHandle.slot(self).check({
|
|
204
203
|
checkerName,
|
|
205
204
|
mutants: [...mutants]
|
|
206
205
|
}));
|
|
207
|
-
const groupOf$1 = (self, checkerName, mutants) => recordCheckerCall("stryker.checker.group", checkerName, mutants, self
|
|
206
|
+
const groupOf$1 = (self, checkerName, mutants) => recordCheckerCall("stryker.checker.group", checkerName, mutants, CheckerHandle.slot(self).group({
|
|
208
207
|
checkerName,
|
|
209
208
|
mutants: [...mutants]
|
|
210
209
|
}));
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
[ClientTypeId]: client,
|
|
215
|
-
...Prototype,
|
|
216
|
-
check: (checkerName, mutants) => checkOf(self, checkerName, mutants),
|
|
217
|
-
group: (checkerName, mutants) => groupOf$1(self, checkerName, mutants)
|
|
218
|
-
};
|
|
219
|
-
return self;
|
|
220
|
-
};
|
|
210
|
+
const check = dual((args) => isCheckerHandle(args[0]), (self, checkerName, mutants) => checkOf(self, checkerName, mutants));
|
|
211
|
+
const group = dual((args) => isCheckerHandle(args[0]), (self, checkerName, mutants) => groupOf$1(self, checkerName, mutants));
|
|
212
|
+
const makeCheckerHandle = (client) => CheckerHandle.make({}, client);
|
|
221
213
|
//#endregion
|
|
222
214
|
//#region src/Checker/Checker.schema.ts
|
|
223
215
|
var UndescribableMutant = class extends S.TaggedError()("UndescribableMutant", {
|
|
@@ -245,7 +237,7 @@ const CheckerMutantFromMutant = S.decodeTo(CheckerMutant, SchemaTransformation$1
|
|
|
245
237
|
})
|
|
246
238
|
}))(Mutant_exports.Mutant);
|
|
247
239
|
//#endregion
|
|
248
|
-
//#region src/Checker/Checker.
|
|
240
|
+
//#region src/Checker/Checker.parts.ts
|
|
249
241
|
const plansById = (plans) => new Map(plans.map((plan) => [plan.mutant.id, plan]));
|
|
250
242
|
const missingPlanIds = (plans, present) => plans.map((plan) => plan.mutant.id).filter((id) => !present.has(id));
|
|
251
243
|
const answeredPlanIds = (paired) => new Set(paired.map(([plan]) => plan.mutant.id));
|
|
@@ -313,8 +305,8 @@ const pairGroups = (checkerName, plans, idGroups) => Match.value(partitionGroups
|
|
|
313
305
|
unrequestedIds: [...partition.unrequested],
|
|
314
306
|
requestedIds: plans.map((plan) => plan.mutant.id)
|
|
315
307
|
}))), Match.orElse((partition) => admitGroupedPlans(checkerName, plans, partition)));
|
|
316
|
-
const writeDecidedAnswers = (
|
|
317
|
-
const writeDecidedGroups = (
|
|
308
|
+
const writeDecidedAnswers = (input) => Effect$1.fromResult(pairCheckResults(input.checkerName, input.plans, Object.fromEntries(input.answers.map((answer) => [answer.id, answer.result]))));
|
|
309
|
+
const writeDecidedGroups = (input) => Effect$1.fromResult(pairGroups(input.checkerName, input.plans, input.idGroups));
|
|
318
310
|
const wireRecordOf = (mutant) => Result.mapError(S.decodeResult(CheckerMutantFromMutant)(mutant), (error) => UndescribableMutant.make({
|
|
319
311
|
id: mutant.id,
|
|
320
312
|
fileName: mutant.fileName,
|
|
@@ -356,7 +348,7 @@ const skippedIdsOf = (undescribable) => `${undescribable.slice(0, SKIPPED_IDS_IN
|
|
|
356
348
|
onSome: (count) => `, +${count - SKIPPED_IDS_IN_WARNING} more`
|
|
357
349
|
})}`;
|
|
358
350
|
const refusalReasonsOf = (undescribable) => [...new Set(undescribable.map((mutant) => mutant.reason))].join("; ");
|
|
359
|
-
const logSkippedMutants = (
|
|
351
|
+
const logSkippedMutants = (input) => Match.value(input.undescribable.length).pipe(Match.when(0, () => Effect$1.void), Match.orElse(() => Effect$1.logWarning(`Checker "${input.checkerName}" skipped ${input.undescribable.length} mutant(s) it cannot be told about: ${refusalReasonsOf(input.undescribable)} (${skippedIdsOf(input.undescribable)})`)));
|
|
360
352
|
const recordSkipped = (skipped) => Boolean$1.match(skipped > 0, {
|
|
361
353
|
onTrue: () => Metric.update(UndescribableMutant.skipped, skipped),
|
|
362
354
|
onFalse: () => Effect$1.void
|
|
@@ -365,9 +357,14 @@ const partitionedFor = (input) => Option$1.match(Option$1.fromUndefinedOr(input.
|
|
|
365
357
|
onSome: (known) => selectedFromLookup(input.plans, known),
|
|
366
358
|
onNone: () => partitionMutantsForWire(input.plans)
|
|
367
359
|
});
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/Checker/Checker.cell.ts
|
|
368
362
|
const readCheckCommand = (input) => Effect$1.gen(function* () {
|
|
369
363
|
const partitioned = partitionedFor(input);
|
|
370
|
-
yield* logSkippedMutants(
|
|
364
|
+
yield* logSkippedMutants({
|
|
365
|
+
checkerName: input.checkerName,
|
|
366
|
+
undescribable: partitioned.undescribable
|
|
367
|
+
});
|
|
371
368
|
yield* recordSkipped(partitioned.undescribable.length);
|
|
372
369
|
yield* Effect$1.annotateCurrentSpan({ "stryker.checker.skipped_mutants_count": partitioned.undescribable.length });
|
|
373
370
|
const answers = yield* input.checker.check(input.checkerName, partitioned.wire);
|
|
@@ -407,7 +404,11 @@ const commandFailed = (issue, input) => Checker_exports.CheckerFailed.make({
|
|
|
407
404
|
mutantIds: input.plans.map((plan) => plan.mutant.id)
|
|
408
405
|
});
|
|
409
406
|
const checkCell = Sandwich.named("stryker.checker.check_plans")(readCheckCommand).decide(admitCheckerAnswer).write({
|
|
410
|
-
CheckResultDecision: ({ pairs }, raw) => writeDecidedAnswers(
|
|
407
|
+
CheckResultDecision: ({ pairs }, raw) => writeDecidedAnswers({
|
|
408
|
+
plans: raw.plans,
|
|
409
|
+
checkerName: raw.checkerName,
|
|
410
|
+
answers: pairs
|
|
411
|
+
}),
|
|
411
412
|
CheckGroupDecision: (_decision, raw) => Effect$1.fail(CheckerSkippedRequested.make({
|
|
412
413
|
checkerName: raw.checkerName,
|
|
413
414
|
phase: "check",
|
|
@@ -417,8 +418,12 @@ const checkCell = Sandwich.named("stryker.checker.check_plans")(readCheckCommand
|
|
|
417
418
|
CheckerSkippedRequested: (breach) => Effect$1.fail(CheckerSkippedRequested.make(breach)),
|
|
418
419
|
CommandRejected: ({ issue }, raw) => Effect$1.fail(commandFailed(issue, raw))
|
|
419
420
|
});
|
|
420
|
-
const
|
|
421
|
-
CheckGroupDecision: ({ groups }, raw) => writeDecidedGroups(
|
|
421
|
+
const groupCell = Sandwich.named("stryker.checker.group_plans")(readGroupCommand).decide(admitCheckerAnswer).write({
|
|
422
|
+
CheckGroupDecision: ({ groups }, raw) => writeDecidedGroups({
|
|
423
|
+
plans: raw.plans,
|
|
424
|
+
checkerName: raw.checkerName,
|
|
425
|
+
idGroups: groups
|
|
426
|
+
}),
|
|
422
427
|
CheckResultDecision: (_decision, raw) => Effect$1.fail(CheckerSkippedRequested.make({
|
|
423
428
|
checkerName: raw.checkerName,
|
|
424
429
|
phase: "group",
|
|
@@ -427,16 +432,20 @@ const checkGroupedCell = Sandwich.named("stryker.checker.group_plans")(readGroup
|
|
|
427
432
|
CheckerAnsweredUnrequested: (breach) => Effect$1.fail(CheckerAnsweredUnrequested.make(breach)),
|
|
428
433
|
CheckerSkippedRequested: (breach) => Effect$1.fail(CheckerSkippedRequested.make(breach)),
|
|
429
434
|
CommandRejected: ({ issue }, raw) => Effect$1.fail(commandFailed(issue, raw))
|
|
430
|
-
})
|
|
435
|
+
});
|
|
436
|
+
const checkGroupedCell = groupCell.pipe(Cell.flatMap((groups) => Cell.mapInput(Cell.collect(checkCell, (perGroup) => perGroup.flat()), (input) => groups.map((group) => ({
|
|
431
437
|
...input,
|
|
432
438
|
plans: group
|
|
433
439
|
})))));
|
|
434
|
-
const
|
|
440
|
+
const checkRequestOf = (checker, checkerName, plans) => ({
|
|
435
441
|
checker,
|
|
436
442
|
checkerName,
|
|
437
443
|
plans,
|
|
438
444
|
lookup: lookupOf(partitionMutantsForWire(plans))
|
|
439
|
-
})
|
|
445
|
+
});
|
|
446
|
+
const groupPlans = dual(3, (checker, checkerName, plans) => groupCell.run(checkRequestOf(checker, checkerName, plans)));
|
|
447
|
+
const checkPlans = dual(3, (checker, checkerName, plans) => checkCell.run(checkRequestOf(checker, checkerName, plans)));
|
|
448
|
+
const checkGroupedPlans = dual(3, (checker, checkerName, plans) => checkGroupedCell.run(checkRequestOf(checker, checkerName, plans)));
|
|
440
449
|
//#endregion
|
|
441
450
|
//#region src/Config.schema.ts
|
|
442
451
|
const ConfigDocumentSchema = S.Record(S.String, S.Unknown);
|
|
@@ -479,6 +488,22 @@ const forkOptionsSchema = S.StructWithRest(S.Struct({
|
|
|
479
488
|
extends: extendsPropertySchema
|
|
480
489
|
}), [S.Record(S.String, S.Unknown)]);
|
|
481
490
|
//#endregion
|
|
491
|
+
//#region src/config/default-options.ts
|
|
492
|
+
const isNonNullObject$1 = (value) => typeof value === "object" && value !== null;
|
|
493
|
+
const isRecordValue = (value) => isNonNullObject$1(value) && Array.isArray(value) === false;
|
|
494
|
+
const isArrayValue$1 = (value) => Array.isArray(value);
|
|
495
|
+
const freezeArrayValue = (value) => Object.freeze(value.map((element) => deepFreeze(element)));
|
|
496
|
+
const freezeMapEntry = ([entryKey, entryValue]) => [deepFreeze(entryKey), deepFreeze(entryValue)];
|
|
497
|
+
const freezeMapValue = (value) => Object.freeze(new Map([...value.entries()].map(freezeMapEntry)));
|
|
498
|
+
const freezeSetValue = (value) => Object.freeze(new Set([...value.values()].map((element) => deepFreeze(element))));
|
|
499
|
+
const freezeRegExpValue = (value) => Object.freeze(value);
|
|
500
|
+
const freezeRecordValue = (value) => Object.freeze(Record.map(value, (propertyValue) => deepFreeze(propertyValue)));
|
|
501
|
+
function deepFreeze(target) {
|
|
502
|
+
return Match.value(target).pipe(Match.when(isArrayValue$1, freezeArrayValue), Match.when((value) => value instanceof Map, freezeMapValue), Match.when((value) => value instanceof RegExp, freezeRegExpValue), Match.when((value) => value instanceof Set, freezeSetValue), Match.when(isRecordValue, freezeRecordValue), Match.orElse(() => target));
|
|
503
|
+
}
|
|
504
|
+
const createDefaultOptions = S.decodeEffect(Options_exports.StrykerOptionsSchema)({}).pipe(Effect$1.orDie);
|
|
505
|
+
const defaultOptions = Effect$1.map(createDefaultOptions, (options) => deepFreeze(options));
|
|
506
|
+
//#endregion
|
|
482
507
|
//#region src/ConfigError.schema.ts
|
|
483
508
|
var ConfigFileNotFoundError = class extends S.TaggedError()("ConfigFileNotFoundError", { file: S.String }) {
|
|
484
509
|
exitClass = "ConfigError";
|
|
@@ -697,13 +722,16 @@ const interpretDryRunResult = Workflow.make({
|
|
|
697
722
|
});
|
|
698
723
|
//#endregion
|
|
699
724
|
//#region src/pooled-test-runner.handle.ts
|
|
700
|
-
const TypeId$
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
725
|
+
const TypeId$9 = Symbol.for("~systemfsoftware/stryker-js/PooledTestRunner");
|
|
726
|
+
const PooledTestRunner = Handle.make()(TypeId$9);
|
|
727
|
+
PooledTestRunner.is;
|
|
728
|
+
const make$3 = (runner) => PooledTestRunner.make({
|
|
729
|
+
capabilities: runner.capabilities,
|
|
730
|
+
init: runner.init,
|
|
731
|
+
dryRun: runner.dryRun,
|
|
732
|
+
mutantRun: runner.mutantRun
|
|
733
|
+
});
|
|
734
|
+
const withTimeout = (inner) => make$3({
|
|
707
735
|
...inner,
|
|
708
736
|
dryRun: (options) => inner.dryRun(options).pipe(Effect$1.timeoutOrElse({
|
|
709
737
|
duration: Duration.millis(options.timeout),
|
|
@@ -725,7 +753,7 @@ const maxRetries = 2;
|
|
|
725
753
|
const exhaustedMessage = (cause) => `Test runner crashed. Tried ${maxRetries} times to restart it without any luck. ${Cause.pretty(cause)}`;
|
|
726
754
|
const withRetry = (inner) => {
|
|
727
755
|
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: maxRetries }), Effect$1.catchCause((cause) => Effect$1.succeed(onExhausted(exhaustedMessage(cause)))));
|
|
728
|
-
return {
|
|
756
|
+
return make$3({
|
|
729
757
|
...inner,
|
|
730
758
|
dryRun: (options) => attempt(inner.dryRun(options), (errorMessage) => ({
|
|
731
759
|
status: "error",
|
|
@@ -735,11 +763,11 @@ const withRetry = (inner) => {
|
|
|
735
763
|
status: "error",
|
|
736
764
|
errorMessage
|
|
737
765
|
}))
|
|
738
|
-
};
|
|
766
|
+
});
|
|
739
767
|
};
|
|
740
768
|
const withMaxReuse = dual(2, (options, retire) => (inner) => Match.value(options.maxTestRunnerReuse).pipe(Match.when((restartAfter) => restartAfter <= 0, () => Effect$1.succeed(inner)), Match.orElse((restartAfter) => Effect$1.gen(function* () {
|
|
741
769
|
const runs = yield* Ref.make(0);
|
|
742
|
-
return {
|
|
770
|
+
return make$3({
|
|
743
771
|
...inner,
|
|
744
772
|
mutantRun: (runOptions) => {
|
|
745
773
|
const policy = (self) => Effect$1.gen(function* () {
|
|
@@ -752,7 +780,7 @@ const withMaxReuse = dual(2, (options, retire) => (inner) => Match.value(options
|
|
|
752
780
|
});
|
|
753
781
|
return policy(inner.mutantRun(runOptions));
|
|
754
782
|
}
|
|
755
|
-
};
|
|
783
|
+
});
|
|
756
784
|
}))));
|
|
757
785
|
const nextEnvironmentState = (requested) => Boolean$1.match(requested, {
|
|
758
786
|
onTrue: () => "loaded-static-mutant",
|
|
@@ -768,7 +796,7 @@ const reloadPlanOf = (requested, current, canReload) => ({
|
|
|
768
796
|
});
|
|
769
797
|
const withEnvironmentReload = dual(2, (inner, retire) => Effect$1.gen(function* () {
|
|
770
798
|
const state = yield* Ref.make("pristine");
|
|
771
|
-
return {
|
|
799
|
+
return make$3({
|
|
772
800
|
...inner,
|
|
773
801
|
dryRun: (options) => {
|
|
774
802
|
const policy = (self) => Ref.set(state, "loaded").pipe(Effect$1.andThen(self));
|
|
@@ -792,8 +820,11 @@ const withEnvironmentReload = dual(2, (inner, retire) => Effect$1.gen(function*
|
|
|
792
820
|
reloadEnvironment: plan.reloadEnvironment
|
|
793
821
|
}));
|
|
794
822
|
})
|
|
795
|
-
};
|
|
823
|
+
});
|
|
796
824
|
}));
|
|
825
|
+
//#endregion
|
|
826
|
+
//#region src/command-runner.blueprint.ts
|
|
827
|
+
const TypeId$8 = Symbol.for("~systemfsoftware/stryker-js/CommandRunner");
|
|
797
828
|
const ALL_TESTS_NAME = "All tests";
|
|
798
829
|
const isCommandRunner = (name) => typeof name === "string" && name.toLowerCase() === "command";
|
|
799
830
|
const commandRunnerCapabilities = { reloadEnvironment: true };
|
|
@@ -845,11 +876,7 @@ const commandRunnerMutantRun = (config, mutantPick) => runCommand(config, mutant
|
|
|
845
876
|
onFailure: (failure) => Effect$1.fail(failure),
|
|
846
877
|
onSuccess: (decision) => Effect$1.succeed(decision.asResult)
|
|
847
878
|
})));
|
|
848
|
-
const
|
|
849
|
-
const config = {
|
|
850
|
-
workingDir: context.sandboxWorkingDirectory,
|
|
851
|
-
options: context.options
|
|
852
|
-
};
|
|
879
|
+
const pooledRunnerOf = (config, spawner) => {
|
|
853
880
|
const provided = Effect$1.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner);
|
|
854
881
|
return make$3({
|
|
855
882
|
capabilities: Effect$1.succeed(commandRunnerCapabilities),
|
|
@@ -857,6 +884,23 @@ const commandRunner = dual(2, (context, spawner) => {
|
|
|
857
884
|
dryRun: () => commandRunnerDryRun(config).pipe(provided),
|
|
858
885
|
mutantRun: (options) => commandRunnerMutantRun(config, options).pipe(provided)
|
|
859
886
|
});
|
|
887
|
+
};
|
|
888
|
+
const CommandRunners = Blueprint.make()(TypeId$8).steps({
|
|
889
|
+
steps: {},
|
|
890
|
+
targets: { runner: (spec) => (spawner) => pooledRunnerOf({
|
|
891
|
+
workingDir: spec.workingDir,
|
|
892
|
+
options: spec.options
|
|
893
|
+
}, spawner) }
|
|
894
|
+
});
|
|
895
|
+
const commandRunner = dual(2, (context, spawner) => CommandRunners.of({
|
|
896
|
+
workingDir: context.sandboxWorkingDirectory,
|
|
897
|
+
options: context.options
|
|
898
|
+
}).runner(spawner));
|
|
899
|
+
S.Struct({
|
|
900
|
+
command: S.Literals(["run", "merge-reports"]),
|
|
901
|
+
isDryRun: S.Boolean,
|
|
902
|
+
mode: S.Literals(["human", "machine"]),
|
|
903
|
+
isCi: S.Boolean
|
|
860
904
|
});
|
|
861
905
|
//#endregion
|
|
862
906
|
//#region src/config/warning-enabled.workflow.ts
|
|
@@ -996,7 +1040,7 @@ const resolveConfig = Workflow.make({
|
|
|
996
1040
|
const ExitDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/ExitDecision");
|
|
997
1041
|
var ClassifyExitCommand = class extends S.TaggedClass()("ClassifyExitCommand", {
|
|
998
1042
|
pending: S.Array(Plugin_exports.ExitClass),
|
|
999
|
-
score:
|
|
1043
|
+
score: Report_exports.MutationScore,
|
|
1000
1044
|
breakingThreshold: S.NullOr(S.Finite)
|
|
1001
1045
|
}) {
|
|
1002
1046
|
static [Workflow.InstrumentationBrand] = {};
|
|
@@ -1031,9 +1075,12 @@ const PRECEDENCE = [
|
|
|
1031
1075
|
];
|
|
1032
1076
|
const precedenceOf = (pending) => Arr.findFirst(PRECEDENCE, (candidate) => pending.includes(candidate));
|
|
1033
1077
|
const decisionOf$1 = (exitClass) => Match.value(exitClass).pipe(Match.when("VerdictFail", () => ExitVerdictFailed.make({})), Match.when("ConfigError", () => ExitConfigErrored.make({})), Match.when("RuntimeError", () => ExitRuntimeErrored.make({})), Match.when("InternalError", () => ExitInternalErrored.make({})), Match.exhaustive);
|
|
1034
|
-
const verdictExitClass = (score, breakingThreshold) =>
|
|
1035
|
-
|
|
1036
|
-
|
|
1078
|
+
const verdictExitClass = (score, breakingThreshold) => Match.valueTags(score, {
|
|
1079
|
+
Unscored: () => null,
|
|
1080
|
+
Scored: ({ percentage }) => Option$1.match(Option$1.fromNullishOr(breakingThreshold), {
|
|
1081
|
+
onNone: () => null,
|
|
1082
|
+
onSome: (threshold) => Match.value(percentage < threshold).pipe(Match.when(true, () => "VerdictFail"), Match.when(false, () => null), Match.exhaustive)
|
|
1083
|
+
})
|
|
1037
1084
|
});
|
|
1038
1085
|
const decide$9 = (command) => Option$1.match(Option$1.fromNullishOr(verdictExitClass(command.score, command.breakingThreshold)), {
|
|
1039
1086
|
onNone: () => Option$1.match(precedenceOf(command.pending), {
|
|
@@ -1203,7 +1250,14 @@ var Trace_exports = /* @__PURE__ */ __exportAll$1({
|
|
|
1203
1250
|
layerTraceContextServer: () => layerTraceContextServer,
|
|
1204
1251
|
withLinkedSpan: () => withLinkedSpan
|
|
1205
1252
|
});
|
|
1206
|
-
const
|
|
1253
|
+
const isEscapedKey = (key) => JSON.stringify(key) !== `"${key}"`;
|
|
1254
|
+
const omitEscapedKeys = (key, value) => isEscapedKey(key) ? void 0 : value;
|
|
1255
|
+
const withoutEscapedKeys = (options) => Option$1.getOrThrow(S.decodeUnknownOption(Options_exports.StrykerOptionsSchema)(JSON.parse(JSON.stringify(options, omitEscapedKeys))));
|
|
1256
|
+
const OptionsLawDomain = S.declare((value) => S.is(Options_exports.StrykerOptionsSchema)(value), { toCodecArbitrary: () => S.link()(Options_exports.StrykerOptionsSchema, {
|
|
1257
|
+
decode: SchemaGetter.transform(withoutEscapedKeys),
|
|
1258
|
+
encode: SchemaGetter.passthrough()
|
|
1259
|
+
}) });
|
|
1260
|
+
const WorkerOptionsWire = S.fromJsonString(Options_exports.StrykerOptionsSchema.pipe(S.decodeTo(OptionsLawDomain, SchemaTransformation.passthrough())));
|
|
1207
1261
|
var WorkerOptions = class WorkerOptions extends Context.Service()("@systemfsoftware/stryker-js-plugin-runtime/worker-options.service/WorkerOptions") {
|
|
1208
1262
|
static layer = Layer.effect(WorkerOptions, Effect$1.gen(function* () {
|
|
1209
1263
|
const workerDir = yield* Config.String("STRYKER_WORKER_DIR");
|
|
@@ -1219,17 +1273,29 @@ const restrictSocket = (address) => Match.value(address).pipe(Match.tag("UnixPat
|
|
|
1219
1273
|
onTrue: () => Effect$1.void,
|
|
1220
1274
|
onFalse: () => Effect$1.flatMap(FileSystem.FileSystem, (fs) => fs.chmod(path, 384))
|
|
1221
1275
|
})), Match.orElse(() => Effect$1.void));
|
|
1222
|
-
const
|
|
1276
|
+
const TypeId$7 = Symbol.for("~systemfsoftware/stryker-js-plugin-runtime/WorkerServer");
|
|
1277
|
+
const workerServerLayerOf = (params) => Layer.unwrap(Effect$1.gen(function* () {
|
|
1223
1278
|
const socket = yield* SocketServer.SocketServer;
|
|
1224
1279
|
yield* restrictSocket(socket.address);
|
|
1225
1280
|
return RpcServer.layer(params.rpcs).pipe(Layer.provide(params.handlers), Layer.provide(params.schemaServices), Layer.provide(RpcServer.layerProtocolSocketServer), Layer.provide(RpcSerialization.layerNdjson), Layer.provide(traceContextServer));
|
|
1226
1281
|
}));
|
|
1282
|
+
Blueprint.make()(TypeId$7).steps({
|
|
1283
|
+
steps: {},
|
|
1284
|
+
targets: { layer: workerServerLayerOf }
|
|
1285
|
+
}).is;
|
|
1286
|
+
const workerServerLayer = workerServerLayerOf;
|
|
1227
1287
|
const TRACES_SUFFIX = "/v1/traces";
|
|
1228
1288
|
const tracesUrlOf = (endpoint) => Option$1.match(Option$1.liftPredicate(endpoint.replace(/\/+$/u, ""), (trimmed) => trimmed.endsWith(TRACES_SUFFIX)), {
|
|
1229
1289
|
onSome: (trimmed) => trimmed,
|
|
1230
1290
|
onNone: () => `${endpoint.replace(/\/+$/u, "")}${TRACES_SUFFIX}`
|
|
1231
1291
|
});
|
|
1232
|
-
const canonicalTracesUrl = S.String.pipe(S.check(S.isPattern(/\/v1\/traces$/u
|
|
1292
|
+
const canonicalTracesUrl = S.String.pipe(S.check(S.isPattern(/\/v1\/traces$/u, { arbitraryConstraint: {
|
|
1293
|
+
patterns: [{
|
|
1294
|
+
source: "\\/v1\\/traces$",
|
|
1295
|
+
flags: "u"
|
|
1296
|
+
}],
|
|
1297
|
+
minLength: 12
|
|
1298
|
+
} })));
|
|
1233
1299
|
const TracesUrl = S.String.pipe(S.decodeTo(canonicalTracesUrl, {
|
|
1234
1300
|
decode: SchemaGetter$1.transform(tracesUrlOf),
|
|
1235
1301
|
encode: SchemaGetter$1.passthrough()
|
|
@@ -1261,23 +1327,22 @@ var Worker_exports = /* @__PURE__ */ __exportAll$1({
|
|
|
1261
1327
|
});
|
|
1262
1328
|
//#endregion
|
|
1263
1329
|
//#region src/spawned-socket-worker.handle.ts
|
|
1264
|
-
const TypeId$
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
[ClientLayerTypeId]: worker.clientLayer,
|
|
1330
|
+
const TypeId$6 = Symbol.for("~systemfsoftware/stryker-js/SpawnedSocketWorker");
|
|
1331
|
+
const SpawnedSocketWorker = Handle.make()(TypeId$6);
|
|
1332
|
+
SpawnedSocketWorker.is;
|
|
1333
|
+
const make$2 = (worker) => SpawnedSocketWorker.make({
|
|
1269
1334
|
pid: worker.pid,
|
|
1270
|
-
exited: worker.exited
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
const clientLayer = (self) => self[ClientLayerTypeId];
|
|
1335
|
+
exited: worker.exited
|
|
1336
|
+
}, { clientLayer: worker.clientLayer });
|
|
1337
|
+
const clientLayer = (self) => SpawnedSocketWorker.slot(self).clientLayer;
|
|
1274
1338
|
//#endregion
|
|
1275
1339
|
//#region src/WorkerLauncher.service.ts
|
|
1276
1340
|
var WorkerLauncher = class extends Context.Service()("@systemfsoftware/stryker-js/WorkerLauncher.service/WorkerLauncher") {};
|
|
1277
1341
|
//#endregion
|
|
1278
|
-
//#region src/worker-client.
|
|
1342
|
+
//#region src/worker-client.blueprint.ts
|
|
1343
|
+
const TypeId$5 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
|
|
1279
1344
|
const connectRetry = Schedule.max([Schedule.spaced(50), Schedule.recurs(100)]);
|
|
1280
|
-
const
|
|
1345
|
+
const scopedOf$1 = (params) => Effect$1.gen(function* () {
|
|
1281
1346
|
const launcher = yield* WorkerLauncher;
|
|
1282
1347
|
const optionsJson = yield* S.encodeEffect(Worker_exports.WorkerOptionsWire)(params.options).pipe(Effect$1.orDie);
|
|
1283
1348
|
const worker = yield* launcher.spawn({
|
|
@@ -1292,6 +1357,11 @@ const makeWorkerClient = (params) => Effect$1.gen(function* () {
|
|
|
1292
1357
|
const traceContext = yield* Layer.build(Trace_exports.layerTraceContextClient);
|
|
1293
1358
|
return yield* RpcClient.make(params.rpcs).pipe(Effect$1.provideContext(Context.merge(protocol, traceContext)));
|
|
1294
1359
|
});
|
|
1360
|
+
const WorkerClients = () => Blueprint.make()(TypeId$5).steps({
|
|
1361
|
+
steps: {},
|
|
1362
|
+
targets: { scoped: scopedOf$1 }
|
|
1363
|
+
});
|
|
1364
|
+
const makeWorkerClient = (params) => WorkerClients().of(params).scoped;
|
|
1295
1365
|
const ReporterStageTypeId = Symbol.for("@systemfsoftware/stryker-js/ReporterStage");
|
|
1296
1366
|
const carriesAttachments = (stage) => "attachments" in stage;
|
|
1297
1367
|
const makeReporterStage = (attachments) => {
|
|
@@ -1639,7 +1709,10 @@ var VerdictEnvelope = class VerdictEnvelope extends S.Class("VerdictEnvelope")({
|
|
|
1639
1709
|
runId,
|
|
1640
1710
|
mode,
|
|
1641
1711
|
signal,
|
|
1642
|
-
score:
|
|
1712
|
+
score: Report_exports.MutationScore.match(metrics.mutationScore, {
|
|
1713
|
+
Scored: ({ percentage }) => percentage,
|
|
1714
|
+
Unscored: () => null
|
|
1715
|
+
}),
|
|
1643
1716
|
thresholds: {
|
|
1644
1717
|
high: report.thresholds.high,
|
|
1645
1718
|
low: report.thresholds.low,
|
|
@@ -1677,7 +1750,7 @@ var RunEvents = class extends Context.Service()("@systemfsoftware/stryker-js/run
|
|
|
1677
1750
|
var RunIdentity = class extends Context.Service()("@systemfsoftware/stryker-js/run-events.service/RunIdentity") {};
|
|
1678
1751
|
//#endregion
|
|
1679
1752
|
//#region package.json
|
|
1680
|
-
var version = "
|
|
1753
|
+
var version = "12.1.0";
|
|
1681
1754
|
//#endregion
|
|
1682
1755
|
//#region src/stryker-package.schema.ts
|
|
1683
1756
|
var StrykerPackage = class extends S.Class("StrykerPackage")({
|
|
@@ -1969,22 +2042,28 @@ const mutationTestReport = (deps, input) => (results) => Effect$1.gen(function*
|
|
|
1969
2042
|
identities
|
|
1970
2043
|
};
|
|
1971
2044
|
});
|
|
1972
|
-
const determineExitCode = (input) => (metrics) =>
|
|
1973
|
-
const { mutationScore } = metrics.metrics;
|
|
2045
|
+
const determineExitCode = (input) => (metrics) => {
|
|
1974
2046
|
const breaking = input.options.thresholds.break;
|
|
1975
|
-
const
|
|
1976
|
-
|
|
2047
|
+
const score = metrics.metrics.mutationScore;
|
|
2048
|
+
const failure = Option$1.fromNullishOr(Result.match(classifyExit(ClassifyExitCommand.make({
|
|
1977
2049
|
pending: [],
|
|
1978
|
-
score
|
|
2050
|
+
score,
|
|
1979
2051
|
breakingThreshold: breaking
|
|
1980
2052
|
})), {
|
|
1981
2053
|
onFailure: (refused) => refused,
|
|
1982
2054
|
onSuccess: (decision) => Match.value(decision).pipe(Match.tag("ExitVerdictFailed", () => "VerdictFail"), Match.orElse(() => null))
|
|
1983
|
-
}))
|
|
1984
|
-
|
|
1985
|
-
|
|
2055
|
+
}));
|
|
2056
|
+
return Report_exports.MutationScore.match(score, {
|
|
2057
|
+
Scored: ({ percentage }) => Option$1.match(failure, {
|
|
2058
|
+
onNone: () => Effect$1.as(logScoredPass(breaking, percentage), null),
|
|
2059
|
+
onSome: (exitClass) => Effect$1.as(logBroken(breaking, percentage), exitClass)
|
|
2060
|
+
}),
|
|
2061
|
+
Unscored: () => Effect$1.as(logUnscored(breaking), Option$1.getOrNull(failure))
|
|
1986
2062
|
});
|
|
1987
|
-
}
|
|
2063
|
+
};
|
|
2064
|
+
const logScoredPass = (breaking, percentage) => Match.value(breaking).pipe(Match.when(null, () => Effect$1.logDebug("No breaking threshold configured. Won't fail the build no matter how low your mutation score is. Set `thresholds.break` to change this behavior.")), Match.orElse((threshold) => Effect$1.logInfo(`Final mutation score of ${percentage.toFixed(2)} is greater than or equal to break threshold ${String(threshold)}`)));
|
|
2065
|
+
const logUnscored = (breaking) => Match.value(breaking).pipe(Match.when(null, () => Effect$1.void), Match.orElse((threshold) => Effect$1.logInfo(`No valid mutant was tested, so there is no mutation score to hold against break threshold ${String(threshold)}`)));
|
|
2066
|
+
const logBroken = (breaking, percentage) => Effect$1.andThen(Effect$1.logError(`Final mutation score ${percentage.toFixed(2)} under breaking threshold ${String(breaking)}, setting exit code to 1 (failure).`), Effect$1.logInfo("(improve mutation score or set `thresholds.break = null` to prevent this error in the future)"));
|
|
1988
2067
|
const emitVerdict = (deps, input) => (report) => Effect$1.gen(function* () {
|
|
1989
2068
|
const envelope = VerdictEnvelope.build(report, input.resolvedMode.mode, input.resolvedMode.signal, input.runId, input.basePath, deps.path);
|
|
1990
2069
|
yield* Queue.offer(deps.events, VerdictReached.make({
|
|
@@ -2016,7 +2095,7 @@ const reportAll = (deps, input) => Effect$1.gen(function* () {
|
|
|
2016
2095
|
const verdict = yield* determineExitCode(input)(metrics);
|
|
2017
2096
|
const finalVerdict = Result.match(classifyExit(ClassifyExitCommand.make({
|
|
2018
2097
|
pending: [verdict, terminalDrain].filter((candidate) => candidate !== null),
|
|
2019
|
-
score:
|
|
2098
|
+
score: Report_exports.MutationScore.cases.Unscored.make({}),
|
|
2020
2099
|
breakingThreshold: null
|
|
2021
2100
|
})), {
|
|
2022
2101
|
onFailure: (refused) => refused,
|
|
@@ -2108,7 +2187,8 @@ var ClearTextReportCommand = class extends S.TaggedClass()("ClearTextReportComma
|
|
|
2108
2187
|
};
|
|
2109
2188
|
var ClearTextReportRendered = class extends S.TaggedClass()("ClearTextReportRendered", {
|
|
2110
2189
|
stdout: S.Array(ReportChunkSchema),
|
|
2111
|
-
diagnostics: S.Array(ReportChunkSchema)
|
|
2190
|
+
diagnostics: S.Array(ReportChunkSchema),
|
|
2191
|
+
stderr: S.Array(ReportChunkSchema)
|
|
2112
2192
|
}) {
|
|
2113
2193
|
[ClearTextReportTypeId] = ClearTextReportTypeId;
|
|
2114
2194
|
};
|
|
@@ -2367,8 +2447,12 @@ const mutantReportSection = (report, metrics, render) => Boolean$1.match(render.
|
|
|
2367
2447
|
},
|
|
2368
2448
|
onFalse: () => EMPTY_SECTIONS
|
|
2369
2449
|
});
|
|
2450
|
+
const hasFullScore = (metrics) => Match.valueTags(metrics.mutationScore, {
|
|
2451
|
+
Scored: ({ percentage }) => percentage === 100,
|
|
2452
|
+
Unscored: () => false
|
|
2453
|
+
});
|
|
2370
2454
|
const partialScoresVisible = (metrics, render) => Boolean$1.match(render.skipFull, {
|
|
2371
|
-
onTrue: () => metrics.childResults.some((child) => child.metrics
|
|
2455
|
+
onTrue: () => metrics.childResults.some((child) => !hasFullScore(child.metrics)),
|
|
2372
2456
|
onFalse: () => true
|
|
2373
2457
|
});
|
|
2374
2458
|
const drawsScoreTable = (metrics, render) => Boolean$1.match(render.reportScoreTable, {
|
|
@@ -2376,14 +2460,14 @@ const drawsScoreTable = (metrics, render) => Boolean$1.match(render.reportScoreT
|
|
|
2376
2460
|
onFalse: () => false
|
|
2377
2461
|
});
|
|
2378
2462
|
const mutationScoreOf = (scoreType, metrics) => Match.value(scoreType).pipe(Match.when("total", () => metrics.mutationScore), Match.when("covered", () => metrics.mutationScoreBasedOnCoveredCode), Match.exhaustive);
|
|
2379
|
-
const scoreText = (scoreType, row) => {
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
})
|
|
2385
|
-
|
|
2386
|
-
|
|
2463
|
+
const scoreText = (scoreType, row) => Match.valueTags(mutationScoreOf(scoreType, row.metrics), {
|
|
2464
|
+
Scored: ({ percentage }) => percentage.toFixed(2),
|
|
2465
|
+
Unscored: () => "n/a"
|
|
2466
|
+
});
|
|
2467
|
+
const thresholdTone = (thresholds, score) => Match.valueTags(score, {
|
|
2468
|
+
Scored: ({ percentage }) => Match.value(percentage).pipe(Match.when((value) => value >= thresholds.high, () => "positive"), Match.when((value) => value >= thresholds.low, () => "warning"), Match.orElse(() => "negative")),
|
|
2469
|
+
Unscored: () => "muted"
|
|
2470
|
+
});
|
|
2387
2471
|
const scoreTone = (thresholds, scoreType, allowColor) => Boolean$1.match(allowColor, {
|
|
2388
2472
|
onTrue: () => (row) => thresholdTone(thresholds, mutationScoreOf(scoreType, row.metrics)),
|
|
2389
2473
|
onFalse: () => () => "plain"
|
|
@@ -2480,7 +2564,7 @@ const createColumns = (metricsResult, render) => [
|
|
|
2480
2564
|
const leafRules = (columns) => columns.flatMap((column) => column.leaves.map((leaf) => [rule("-", slotWidthOf(leaf))]));
|
|
2481
2565
|
const leafHeaders = (columns) => columns.flatMap((column) => column.leaves.map((leaf) => placedLine(leaf.header, leaf.style, leaf.netWidth)));
|
|
2482
2566
|
const fullRowVisible = (render, row) => Boolean$1.match(render.skipFull, {
|
|
2483
|
-
onTrue: () => row.metrics
|
|
2567
|
+
onTrue: () => !hasFullScore(row.metrics),
|
|
2484
2568
|
onFalse: () => true
|
|
2485
2569
|
});
|
|
2486
2570
|
const bodyRow = (columns, row, ancestorCount) => rowOfLines(columns.flatMap((column) => column.leaves.map((leaf) => [placedCell(leaf.cell(row, ancestorCount), leaf.style, leaf.netWidth, leaf.tone(row))])));
|
|
@@ -2525,7 +2609,11 @@ const renderClearTextReport = Workflow.make({
|
|
|
2525
2609
|
const sections = renderClearText(report, metrics, command.render);
|
|
2526
2610
|
return Result.succeed(ClearTextReportRendered.make({
|
|
2527
2611
|
stdout: [...sections.stdout],
|
|
2528
|
-
diagnostics: [...sections.diagnostics]
|
|
2612
|
+
diagnostics: [...sections.diagnostics],
|
|
2613
|
+
stderr: Boolean$1.match(command.render.debug, {
|
|
2614
|
+
onTrue: () => [...sections.diagnostics],
|
|
2615
|
+
onFalse: () => []
|
|
2616
|
+
})
|
|
2529
2617
|
}));
|
|
2530
2618
|
}
|
|
2531
2619
|
})
|
|
@@ -2575,14 +2663,8 @@ const renderOptionsOf = (options) => ({
|
|
|
2575
2663
|
});
|
|
2576
2664
|
const readClearTextReport = (input) => Effect$1.map(Stream.fromAsyncIterable(input.events, failAsClearText).pipe(Stream.filterMap(terminalReportOf), Stream.run(Sink.last())), (terminal) => ({
|
|
2577
2665
|
_tag: "ClearTextReportCommand",
|
|
2578
|
-
reported: Option$1.
|
|
2579
|
-
|
|
2580
|
-
onSome: (ready) => ready.report
|
|
2581
|
-
}),
|
|
2582
|
-
computed: Option$1.match(terminal, {
|
|
2583
|
-
onNone: () => void 0,
|
|
2584
|
-
onSome: (ready) => ready.metrics
|
|
2585
|
-
}),
|
|
2666
|
+
reported: Option$1.getOrUndefined(Option$1.map(terminal, (ready) => ready.report)),
|
|
2667
|
+
computed: Option$1.getOrUndefined(Option$1.map(terminal, (ready) => ready.metrics)),
|
|
2586
2668
|
render: renderOptionsOf(input.options),
|
|
2587
2669
|
rendered: true
|
|
2588
2670
|
}));
|
|
@@ -2619,13 +2701,10 @@ const renderLine = (line) => runsOf(line).map(renderSpan).join("");
|
|
|
2619
2701
|
const renderChunk = (chunk) => chunk.map(renderLine).join("\n");
|
|
2620
2702
|
const writeChunks = (output, channel, chunks) => output.write(channel, chunks.map((chunk) => `${renderChunk(chunk)}\n`)).pipe(Effect$1.mapError(failAsClearText), Effect$1.asVoid);
|
|
2621
2703
|
const clearTextReportCell = Sandwich.named("stryker.report.clearText")(readClearTextReport).decide(renderClearTextReport).write({
|
|
2622
|
-
ClearTextReportRendered: (rendered,
|
|
2704
|
+
ClearTextReportRendered: (rendered, _raw) => Effect$1.gen(function* () {
|
|
2623
2705
|
const output = yield* ReporterOutput;
|
|
2624
2706
|
yield* writeChunks(output, "stdout", rendered.stdout);
|
|
2625
|
-
yield*
|
|
2626
|
-
onTrue: () => writeChunks(output, "stderr", rendered.diagnostics),
|
|
2627
|
-
onFalse: () => Effect$1.void
|
|
2628
|
-
});
|
|
2707
|
+
yield* Effect$1.forEach(rendered.stderr, (chunk) => writeChunks(output, "stderr", [chunk]), { discard: true });
|
|
2629
2708
|
}),
|
|
2630
2709
|
ClearTextReportSuppressed: () => Effect$1.void,
|
|
2631
2710
|
CommandRejected: ({ issue }) => Effect$1.fail(failAsClearText(issue))
|
|
@@ -2642,11 +2721,16 @@ const clearTextReporterFactory = (context) => {
|
|
|
2642
2721
|
const JsonReportTypeId = Symbol.for("@systemfsoftware/stryker-js/JsonReport");
|
|
2643
2722
|
var JsonReportCommand = class extends S.TaggedClass()("JsonReportCommand", {
|
|
2644
2723
|
reported: S.optional(Report_exports.MutationTestResultSchema),
|
|
2645
|
-
rendered: S.Boolean
|
|
2724
|
+
rendered: S.Boolean,
|
|
2725
|
+
debug: S.Boolean,
|
|
2726
|
+
fileName: S.String
|
|
2646
2727
|
}) {
|
|
2647
2728
|
static [Workflow.InstrumentationBrand] = { rendered: "stryker.report.render" };
|
|
2648
2729
|
};
|
|
2649
|
-
var JsonReportRendered = class extends S.TaggedClass()("JsonReportRendered", {
|
|
2730
|
+
var JsonReportRendered = class extends S.TaggedClass()("JsonReportRendered", {
|
|
2731
|
+
report: Report_exports.MutationTestResultSchema,
|
|
2732
|
+
announceFileName: S.Option(S.String)
|
|
2733
|
+
}) {
|
|
2650
2734
|
[JsonReportTypeId] = JsonReportTypeId;
|
|
2651
2735
|
};
|
|
2652
2736
|
var JsonReportSuppressed = class extends S.TaggedClass()("JsonReportSuppressed", {}) {
|
|
@@ -2659,7 +2743,13 @@ const renderJsonReport = Workflow.make({
|
|
|
2659
2743
|
error: S.Never,
|
|
2660
2744
|
decide: (command) => Option$1.match(Option$1.fromUndefinedOr(command.reported), {
|
|
2661
2745
|
onNone: () => Result.succeed(JsonReportSuppressed.make({})),
|
|
2662
|
-
onSome: (report) => Result.succeed(JsonReportRendered.make({
|
|
2746
|
+
onSome: (report) => Result.succeed(JsonReportRendered.make({
|
|
2747
|
+
report,
|
|
2748
|
+
announceFileName: Boolean$1.match(command.debug, {
|
|
2749
|
+
onTrue: () => Option$1.some(command.fileName),
|
|
2750
|
+
onFalse: () => Option$1.none()
|
|
2751
|
+
})
|
|
2752
|
+
}))
|
|
2663
2753
|
})
|
|
2664
2754
|
});
|
|
2665
2755
|
//#endregion
|
|
@@ -2674,13 +2764,11 @@ const readJsonReport = (input) => Effect$1.map(Stream.fromAsyncIterable(input.ev
|
|
|
2674
2764
|
_tag: "JsonReportCommand",
|
|
2675
2765
|
reported: Option$1.getOrUndefined(last),
|
|
2676
2766
|
rendered: true,
|
|
2767
|
+
debug: input.options.logLevel === "debug",
|
|
2768
|
+
fileName: input.options.jsonReporter.fileName,
|
|
2677
2769
|
options: input.options
|
|
2678
2770
|
}));
|
|
2679
2771
|
const jsonBytesOf = (report) => S.encodeEffect(S.fromJsonString(S.Unknown, { space: 0 }))(report).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
2680
|
-
const announceRelativePath = (output, options, path) => Boolean$1.match(options.logLevel === "debug", {
|
|
2681
|
-
onTrue: () => Effect$1.ignore(output.write("stderr", [`Using relative path ${path.normalize(options.jsonReporter.fileName)}\n`])),
|
|
2682
|
-
onFalse: () => Effect$1.void
|
|
2683
|
-
});
|
|
2684
2772
|
const jsonReportCell = Sandwich.named("stryker.report.json")(readJsonReport).decide(renderJsonReport).write({
|
|
2685
2773
|
JsonReportRendered: (rendered, raw) => Effect$1.gen(function* () {
|
|
2686
2774
|
const output = yield* ReporterOutput;
|
|
@@ -2688,7 +2776,7 @@ const jsonReportCell = Sandwich.named("stryker.report.json")(readJsonReport).dec
|
|
|
2688
2776
|
const path = yield* Path.Path;
|
|
2689
2777
|
const json = yield* jsonBytesOf(rendered.report);
|
|
2690
2778
|
const fileName = path.resolve(raw.options.jsonReporter.fileName);
|
|
2691
|
-
yield*
|
|
2779
|
+
yield* Effect$1.forEach(Option$1.toArray(rendered.announceFileName), (name) => Effect$1.ignore(output.write("stderr", [`Using relative path ${path.normalize(name)}\n`])), { discard: true });
|
|
2692
2780
|
yield* fs.makeDirectory(path.dirname(fileName), { recursive: true }).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
2693
2781
|
yield* fs.writeFileString(fileName, json).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
2694
2782
|
const url = yield* path.toFileUrl(fileName).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
@@ -2705,116 +2793,11 @@ const jsonReporterFactory = (context) => {
|
|
|
2705
2793
|
}));
|
|
2706
2794
|
};
|
|
2707
2795
|
//#endregion
|
|
2708
|
-
//#region src/
|
|
2709
|
-
const ProgressReportTypeId = Symbol.for("@systemfsoftware/stryker-js/ProgressReport");
|
|
2710
|
-
const ProgressTimingSchema = S.Struct({
|
|
2711
|
-
net: S.Finite,
|
|
2712
|
-
overhead: S.Finite
|
|
2713
|
-
});
|
|
2714
|
-
const ProgressCapabilitiesSchema = S.Struct({ reloadEnvironment: S.Boolean });
|
|
2715
|
-
const ProgressTallySchema = S.Struct({
|
|
2716
|
-
survived: S.Finite,
|
|
2717
|
-
timedOut: S.Finite,
|
|
2718
|
-
tested: S.Finite,
|
|
2719
|
-
mutants: S.Finite,
|
|
2720
|
-
total: S.Finite,
|
|
2721
|
-
ticks: S.Finite,
|
|
2722
|
-
ticksByMutantId: S.Record(S.String, S.Finite),
|
|
2723
|
-
timing: ProgressTimingSchema,
|
|
2724
|
-
capabilities: ProgressCapabilitiesSchema,
|
|
2725
|
-
startedAt: S.Finite
|
|
2726
|
-
});
|
|
2727
|
-
const ProgressBarStateSchema = S.Struct({
|
|
2728
|
-
format: S.String,
|
|
2729
|
-
total: S.Finite,
|
|
2730
|
-
curr: S.Finite,
|
|
2731
|
-
width: S.Finite,
|
|
2732
|
-
complete: S.String,
|
|
2733
|
-
incomplete: S.String
|
|
2734
|
-
});
|
|
2735
|
-
const ProgressStateSchema = S.Struct({
|
|
2736
|
-
tally: ProgressTallySchema,
|
|
2737
|
-
bar: S.NullOr(ProgressBarStateSchema)
|
|
2738
|
-
});
|
|
2739
|
-
var ProgressReportCommand = class extends S.TaggedClass()("ProgressReportCommand", {
|
|
2740
|
-
kind: S.Literals([
|
|
2741
|
-
"tick",
|
|
2742
|
-
"skip",
|
|
2743
|
-
"finalize"
|
|
2744
|
-
]),
|
|
2745
|
-
state: ProgressStateSchema,
|
|
2746
|
-
now: S.Finite
|
|
2747
|
-
}) {
|
|
2748
|
-
static [Workflow.InstrumentationBrand] = { now: "stryker.report.rendered" };
|
|
2749
|
-
};
|
|
2750
|
-
var ProgressBarTick = class extends S.TaggedClass()("ProgressBarTick", {
|
|
2751
|
-
bar: ProgressBarStateSchema,
|
|
2752
|
-
tally: ProgressTallySchema,
|
|
2753
|
-
now: S.Finite
|
|
2754
|
-
}) {
|
|
2755
|
-
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2756
|
-
};
|
|
2757
|
-
var ProgressLineBreak = class extends S.TaggedClass()("ProgressLineBreak", {}) {
|
|
2758
|
-
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2759
|
-
};
|
|
2760
|
-
var ProgressChunkSuppressed = class extends S.TaggedClass()("ProgressChunkSuppressed", {}) {
|
|
2761
|
-
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2762
|
-
};
|
|
2763
|
-
const ProgressReportDecision = S.Union([
|
|
2764
|
-
ProgressBarTick,
|
|
2765
|
-
ProgressLineBreak,
|
|
2766
|
-
ProgressChunkSuppressed
|
|
2767
|
-
]);
|
|
2768
|
-
const isComplete$1 = (bar) => bar.curr >= bar.total;
|
|
2769
|
-
const renderProgressReport = Workflow.make({
|
|
2770
|
-
command: ProgressReportCommand,
|
|
2771
|
-
decision: ProgressReportDecision,
|
|
2772
|
-
error: S.Never,
|
|
2773
|
-
decide: (command) => Result.succeed(Match.value(command.kind).pipe(Match.when("finalize", () => Option$1.match(Option$1.fromNullishOr(command.state.bar), {
|
|
2774
|
-
onNone: () => ProgressChunkSuppressed.make({}),
|
|
2775
|
-
onSome: (bar) => Boolean$1.match(isComplete$1(bar), {
|
|
2776
|
-
onTrue: () => ProgressChunkSuppressed.make({}),
|
|
2777
|
-
onFalse: () => ProgressLineBreak.make({})
|
|
2778
|
-
})
|
|
2779
|
-
})), Match.when("skip", () => ProgressChunkSuppressed.make({})), Match.when("tick", () => Option$1.match(Option$1.fromNullishOr(command.state.bar), {
|
|
2780
|
-
onNone: () => ProgressChunkSuppressed.make({}),
|
|
2781
|
-
onSome: (bar) => ProgressBarTick.make({
|
|
2782
|
-
bar,
|
|
2783
|
-
tally: command.state.tally,
|
|
2784
|
-
now: command.now
|
|
2785
|
-
})
|
|
2786
|
-
})), Match.exhaustive))
|
|
2787
|
-
});
|
|
2788
|
-
//#endregion
|
|
2789
|
-
//#region src/progress-report.cell.ts
|
|
2790
|
-
const failAsProgress = (cause) => Reporter_exports.ReporterFailed.make({
|
|
2791
|
-
reporterName: "progress",
|
|
2792
|
-
event: "mutationTestReportReady",
|
|
2793
|
-
cause: Option$1.getOrElse(Option$1.map(ErrorText_exports.ErrorText.fromCause(cause), (rendered) => rendered.text), () => "")
|
|
2794
|
-
});
|
|
2796
|
+
//#region src/progress-report.steps.ts
|
|
2795
2797
|
const PROGRESS_BAR_FORMAT = "Mutation testing [:bar] :percent (elapsed: :et, remaining: :etc) :tested/:mutants Mutants tested (:survived survived, :timedOut timed out)";
|
|
2796
2798
|
const PROGRESS_BAR_WIDTH = 50;
|
|
2797
2799
|
const PROGRESS_BAR_COMPLETE = "=";
|
|
2798
2800
|
const PROGRESS_BAR_INCOMPLETE = " ";
|
|
2799
|
-
const emptyTally = (startedAt) => ({
|
|
2800
|
-
survived: 0,
|
|
2801
|
-
timedOut: 0,
|
|
2802
|
-
tested: 0,
|
|
2803
|
-
mutants: 0,
|
|
2804
|
-
total: 0,
|
|
2805
|
-
ticks: 0,
|
|
2806
|
-
ticksByMutantId: {},
|
|
2807
|
-
timing: {
|
|
2808
|
-
net: 0,
|
|
2809
|
-
overhead: 0
|
|
2810
|
-
},
|
|
2811
|
-
capabilities: { reloadEnvironment: false },
|
|
2812
|
-
startedAt
|
|
2813
|
-
});
|
|
2814
|
-
const INITIAL_PROGRESS = {
|
|
2815
|
-
tally: emptyTally(0),
|
|
2816
|
-
bar: null
|
|
2817
|
-
};
|
|
2818
2801
|
const TALLY_COUNTED = {
|
|
2819
2802
|
Killed: {
|
|
2820
2803
|
survived: 0,
|
|
@@ -2917,24 +2900,14 @@ const advance = (state, event, now) => Match.value(event).pipe(Match.tag("dryRun
|
|
|
2917
2900
|
kind: "skip",
|
|
2918
2901
|
state
|
|
2919
2902
|
})));
|
|
2920
|
-
const
|
|
2903
|
+
const progressStep = (input) => Option$1.match(Option$1.fromNullishOr(input.event), {
|
|
2921
2904
|
onNone: () => ({
|
|
2922
|
-
_tag: "ProgressReportCommand",
|
|
2923
2905
|
kind: "finalize",
|
|
2924
|
-
state: input.state
|
|
2925
|
-
now
|
|
2906
|
+
state: input.state
|
|
2926
2907
|
}),
|
|
2927
|
-
onSome: (
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
_tag: "ProgressReportCommand",
|
|
2931
|
-
kind: step.kind,
|
|
2932
|
-
state: step.state,
|
|
2933
|
-
now
|
|
2934
|
-
};
|
|
2935
|
-
}
|
|
2936
|
-
}));
|
|
2937
|
-
const isComplete = (bar) => bar.curr >= bar.total;
|
|
2908
|
+
onSome: (present) => advance(input.state, present, input.now)
|
|
2909
|
+
});
|
|
2910
|
+
const isComplete$1 = (bar) => bar.curr >= bar.total;
|
|
2938
2911
|
const secondsBetween = (now, startedAt) => Math.floor((now - startedAt) / 1e3);
|
|
2939
2912
|
const formatTime = (timeInSeconds) => {
|
|
2940
2913
|
const hours = Math.floor(timeInSeconds / 3600);
|
|
@@ -2972,7 +2945,128 @@ const lineBreakOf = (complete) => Boolean$1.match(complete, {
|
|
|
2972
2945
|
onTrue: () => "\n",
|
|
2973
2946
|
onFalse: () => ""
|
|
2974
2947
|
});
|
|
2975
|
-
const renderTick = (tick) => `\r${formatBar(tick.bar, progressData(tick.tally, tick.now))}${lineBreakOf(isComplete(tick.bar))}`;
|
|
2948
|
+
const renderTick = (tick) => `\r${formatBar(tick.bar, progressData(tick.tally, tick.now))}${lineBreakOf(isComplete$1(tick.bar))}`;
|
|
2949
|
+
//#endregion
|
|
2950
|
+
//#region src/render-progress-report.workflow.ts
|
|
2951
|
+
const ProgressReportTypeId = Symbol.for("@systemfsoftware/stryker-js/ProgressReport");
|
|
2952
|
+
const ProgressTimingSchema = S.Struct({
|
|
2953
|
+
net: S.Finite,
|
|
2954
|
+
overhead: S.Finite
|
|
2955
|
+
});
|
|
2956
|
+
const ProgressCapabilitiesSchema = S.Struct({ reloadEnvironment: S.Boolean });
|
|
2957
|
+
const ProgressTallySchema = S.Struct({
|
|
2958
|
+
survived: S.Finite,
|
|
2959
|
+
timedOut: S.Finite,
|
|
2960
|
+
tested: S.Finite,
|
|
2961
|
+
mutants: S.Finite,
|
|
2962
|
+
total: S.Finite,
|
|
2963
|
+
ticks: S.Finite,
|
|
2964
|
+
ticksByMutantId: S.Record(S.String, S.Finite),
|
|
2965
|
+
timing: ProgressTimingSchema,
|
|
2966
|
+
capabilities: ProgressCapabilitiesSchema,
|
|
2967
|
+
startedAt: S.Finite
|
|
2968
|
+
});
|
|
2969
|
+
const ProgressBarStateSchema = S.Struct({
|
|
2970
|
+
format: S.String,
|
|
2971
|
+
total: S.Finite,
|
|
2972
|
+
curr: S.Finite,
|
|
2973
|
+
width: S.Finite,
|
|
2974
|
+
complete: S.String,
|
|
2975
|
+
incomplete: S.String
|
|
2976
|
+
});
|
|
2977
|
+
const ProgressStateSchema = S.Struct({
|
|
2978
|
+
tally: ProgressTallySchema,
|
|
2979
|
+
bar: S.NullOr(ProgressBarStateSchema)
|
|
2980
|
+
});
|
|
2981
|
+
var ProgressReportCommand = class extends S.TaggedClass()("ProgressReportCommand", {
|
|
2982
|
+
kind: S.Literals([
|
|
2983
|
+
"tick",
|
|
2984
|
+
"skip",
|
|
2985
|
+
"finalize"
|
|
2986
|
+
]),
|
|
2987
|
+
state: ProgressStateSchema,
|
|
2988
|
+
now: S.Finite
|
|
2989
|
+
}) {
|
|
2990
|
+
static [Workflow.InstrumentationBrand] = { now: "stryker.report.rendered" };
|
|
2991
|
+
};
|
|
2992
|
+
var ProgressBarTick = class extends S.TaggedClass()("ProgressBarTick", {
|
|
2993
|
+
bar: ProgressBarStateSchema,
|
|
2994
|
+
tally: ProgressTallySchema,
|
|
2995
|
+
now: S.Finite
|
|
2996
|
+
}) {
|
|
2997
|
+
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2998
|
+
};
|
|
2999
|
+
var ProgressLineBreak = class extends S.TaggedClass()("ProgressLineBreak", {}) {
|
|
3000
|
+
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
3001
|
+
};
|
|
3002
|
+
var ProgressChunkSuppressed = class extends S.TaggedClass()("ProgressChunkSuppressed", {}) {
|
|
3003
|
+
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
3004
|
+
};
|
|
3005
|
+
const ProgressReportDecision = S.Union([
|
|
3006
|
+
ProgressBarTick,
|
|
3007
|
+
ProgressLineBreak,
|
|
3008
|
+
ProgressChunkSuppressed
|
|
3009
|
+
]);
|
|
3010
|
+
const isComplete = (bar) => bar.curr >= bar.total;
|
|
3011
|
+
const renderProgressReport = Workflow.make({
|
|
3012
|
+
command: ProgressReportCommand,
|
|
3013
|
+
decision: ProgressReportDecision,
|
|
3014
|
+
error: S.Never,
|
|
3015
|
+
decide: (command) => Result.succeed(Match.value(command.kind).pipe(Match.when("finalize", () => Option$1.match(Option$1.fromNullishOr(command.state.bar), {
|
|
3016
|
+
onNone: () => ProgressChunkSuppressed.make({}),
|
|
3017
|
+
onSome: (bar) => Boolean$1.match(isComplete(bar), {
|
|
3018
|
+
onTrue: () => ProgressChunkSuppressed.make({}),
|
|
3019
|
+
onFalse: () => ProgressLineBreak.make({})
|
|
3020
|
+
})
|
|
3021
|
+
})), Match.when("skip", () => ProgressChunkSuppressed.make({})), Match.when("tick", () => Option$1.match(Option$1.fromNullishOr(command.state.bar), {
|
|
3022
|
+
onNone: () => ProgressChunkSuppressed.make({}),
|
|
3023
|
+
onSome: (bar) => ProgressBarTick.make({
|
|
3024
|
+
bar,
|
|
3025
|
+
tally: command.state.tally,
|
|
3026
|
+
now: command.now
|
|
3027
|
+
})
|
|
3028
|
+
})), Match.exhaustive))
|
|
3029
|
+
});
|
|
3030
|
+
//#endregion
|
|
3031
|
+
//#region src/progress-report.cell.ts
|
|
3032
|
+
const failAsProgress = (cause) => Reporter_exports.ReporterFailed.make({
|
|
3033
|
+
reporterName: "progress",
|
|
3034
|
+
event: "mutationTestReportReady",
|
|
3035
|
+
cause: Option$1.getOrElse(Option$1.map(ErrorText_exports.ErrorText.fromCause(cause), (rendered) => rendered.text), () => "")
|
|
3036
|
+
});
|
|
3037
|
+
const emptyTally = (startedAt) => ({
|
|
3038
|
+
survived: 0,
|
|
3039
|
+
timedOut: 0,
|
|
3040
|
+
tested: 0,
|
|
3041
|
+
mutants: 0,
|
|
3042
|
+
total: 0,
|
|
3043
|
+
ticks: 0,
|
|
3044
|
+
ticksByMutantId: {},
|
|
3045
|
+
timing: {
|
|
3046
|
+
net: 0,
|
|
3047
|
+
overhead: 0
|
|
3048
|
+
},
|
|
3049
|
+
capabilities: { reloadEnvironment: false },
|
|
3050
|
+
startedAt
|
|
3051
|
+
});
|
|
3052
|
+
const INITIAL_PROGRESS = {
|
|
3053
|
+
tally: emptyTally(0),
|
|
3054
|
+
bar: null
|
|
3055
|
+
};
|
|
3056
|
+
const readProgressStep = (input) => Effect$1.gen(function* () {
|
|
3057
|
+
const now = yield* Clock.currentTimeMillis;
|
|
3058
|
+
const step = progressStep({
|
|
3059
|
+
state: input.state,
|
|
3060
|
+
event: input.event,
|
|
3061
|
+
now
|
|
3062
|
+
});
|
|
3063
|
+
return {
|
|
3064
|
+
_tag: "ProgressReportCommand",
|
|
3065
|
+
kind: step.kind,
|
|
3066
|
+
state: step.state,
|
|
3067
|
+
now
|
|
3068
|
+
};
|
|
3069
|
+
});
|
|
2976
3070
|
const writeChunk = (chunk) => Effect$1.flatMap(ReporterOutput, (output) => Effect$1.ignore(output.write("stdout", [chunk])));
|
|
2977
3071
|
const progressReportCell = Sandwich.named("stryker.report.progress")(readProgressStep).decide(renderProgressReport).write({
|
|
2978
3072
|
ProgressBarTick: (tick, raw) => Effect$1.as(writeChunk(renderTick(tick)), raw.state),
|
|
@@ -3061,7 +3155,7 @@ const phaseEntered = (phase) => Effect$1.gen(function* () {
|
|
|
3061
3155
|
}));
|
|
3062
3156
|
});
|
|
3063
3157
|
//#endregion
|
|
3064
|
-
//#region src/run/load-config.
|
|
3158
|
+
//#region src/run/load-config.parts.ts
|
|
3065
3159
|
const isNonNullObject = (value) => typeof value === "object" && value !== null;
|
|
3066
3160
|
const combine = (prefixes, suffixes, extensions) => prefixes.flatMap((prefix) => suffixes.flatMap((suffix) => extensions.map((extension) => `${prefix}stryker${suffix}.${extension}`)));
|
|
3067
3161
|
const CONFIG_FILE_NAME_PREFIXES = ["", "."];
|
|
@@ -3228,7 +3322,7 @@ const applyConfigFactory = (factory, configEnv) => factory(configEnv);
|
|
|
3228
3322
|
/**
|
|
3229
3323
|
* Settle a config module's default export into the object the document schema decodes.
|
|
3230
3324
|
*
|
|
3231
|
-
* `./config` types `
|
|
3325
|
+
* `./config` types `defineConfig` as accepting the config object, a promise of it,
|
|
3232
3326
|
* or a factory receiving `ConfigEnv`, so the loader accepts all three. The factory
|
|
3233
3327
|
* is invoked here because this is the only place that knows the invocation the
|
|
3234
3328
|
* config is being read for; the promise is awaited here because a promise is a
|
|
@@ -3536,20 +3630,10 @@ const readLoadConfig = (input) => Effect$1.gen(function* () {
|
|
|
3536
3630
|
};
|
|
3537
3631
|
const cliRecord = yield* S.decodeEffect(ConfigDocumentSchema)(input.cliOptions).pipe(Effect$1.orDie);
|
|
3538
3632
|
return yield* loadOptionsFromConfigFile(cliRecord, configEnv).pipe(Effect$1.map((fileOptions) => LoadConfigCommand.make({
|
|
3539
|
-
document:
|
|
3633
|
+
document: mergeConfig(Option$1.getOrElse(fileOptions, () => ({})), cliRecord),
|
|
3540
3634
|
fileFound: Option$1.isSome(fileOptions)
|
|
3541
3635
|
})));
|
|
3542
3636
|
});
|
|
3543
|
-
const loadConfig = Sandwich.named("stryker.config_read")(readLoadConfig).decide(resolveConfig).write({
|
|
3544
|
-
ConfigFromFile: ({ options }) => Effect$1.succeed(options),
|
|
3545
|
-
ConfigFromDefaults: ({ options }) => Effect$1.succeed(options),
|
|
3546
|
-
ConfigOptionsRefused: ({ message }) => Effect$1.fail(ConfigError.make({ message: configErrorMessage(describeMessageOf(message)) })),
|
|
3547
|
-
CommandRejected: ({ issue }) => Effect$1.fail(ConfigError.make({ message: issue }))
|
|
3548
|
-
});
|
|
3549
|
-
const readConfig = dual(2, (cliOptions, invocation) => loadConfig.run({
|
|
3550
|
-
cliOptions,
|
|
3551
|
-
invocation
|
|
3552
|
-
}));
|
|
3553
3637
|
const emitPreparePhaseEntered = phaseEntered("prepare");
|
|
3554
3638
|
const failConfigWith = (message) => Effect$1.fail(ConfigError.make({ message })).pipe(Effect$1.tapCause(() => emitPreparePhaseEntered));
|
|
3555
3639
|
const readRunConfig = (input) => Effect$1.gen(function* () {
|
|
@@ -3566,6 +3650,18 @@ const readRunConfig = (input) => Effect$1.gen(function* () {
|
|
|
3566
3650
|
basePath: env.basePath
|
|
3567
3651
|
});
|
|
3568
3652
|
});
|
|
3653
|
+
//#endregion
|
|
3654
|
+
//#region src/run/load-config.cell.ts
|
|
3655
|
+
const loadConfig = Sandwich.named("stryker.config_read")(readLoadConfig).decide(resolveConfig).write({
|
|
3656
|
+
ConfigFromFile: ({ options }) => Effect$1.succeed(options),
|
|
3657
|
+
ConfigFromDefaults: ({ options }) => Effect$1.succeed(options),
|
|
3658
|
+
ConfigOptionsRefused: ({ message }) => Effect$1.fail(ConfigError.make({ message: configErrorMessage(describeMessageOf(message)) })),
|
|
3659
|
+
CommandRejected: ({ issue }) => Effect$1.fail(ConfigError.make({ message: issue }))
|
|
3660
|
+
});
|
|
3661
|
+
const readConfig = dual(2, (cliOptions, invocation) => loadConfig.run({
|
|
3662
|
+
cliOptions,
|
|
3663
|
+
invocation
|
|
3664
|
+
}));
|
|
3569
3665
|
const loadConfigCell = Sandwich.named("stryker.load_config")(readRunConfig).decide(resolveConfig).write({
|
|
3570
3666
|
ConfigFromFile: ({ options }, raw) => Effect$1.succeed({
|
|
3571
3667
|
options,
|
|
@@ -3620,9 +3716,10 @@ const classifyWorkerExit = Workflow.make({
|
|
|
3620
3716
|
decide: decide$8
|
|
3621
3717
|
});
|
|
3622
3718
|
//#endregion
|
|
3623
|
-
//#region src/worker-protocol.
|
|
3719
|
+
//#region src/worker-protocol.blueprint.ts
|
|
3720
|
+
const TypeId$4 = Symbol.for("~systemfsoftware/stryker-js/WorkerProtocol");
|
|
3624
3721
|
const droppedConnection = RpcClientError.make({ reason: Socket.SocketReadError.make({ cause: /* @__PURE__ */ new Error("worker connection dropped with the request in flight") }) });
|
|
3625
|
-
const
|
|
3722
|
+
const layerOf = (socket) => Layer.effect(RpcClient.Protocol, Effect$1.gen(function* () {
|
|
3626
3723
|
const handlers = MutableHashMap.empty();
|
|
3627
3724
|
const inFlight = MutableHashMap.empty();
|
|
3628
3725
|
const connected = yield* Ref.make(false);
|
|
@@ -3661,10 +3758,15 @@ const layerWorkerProtocol = (socket) => Layer.effect(RpcClient.Protocol, Effect$
|
|
|
3661
3758
|
send: (clientId, request, transferables) => track(clientId, request).pipe(Effect$1.andThen(inner.send(clientId, request, transferables)))
|
|
3662
3759
|
});
|
|
3663
3760
|
}));
|
|
3761
|
+
const WorkerProtocol = Blueprint.make()(TypeId$4).steps({
|
|
3762
|
+
steps: {},
|
|
3763
|
+
targets: { layer: (spec) => layerOf(spec.socket) }
|
|
3764
|
+
});
|
|
3765
|
+
const layerWorkerProtocol = (socket) => WorkerProtocol.of({ socket }).layer;
|
|
3664
3766
|
//#endregion
|
|
3665
3767
|
//#region src/drivers/node.ts
|
|
3666
3768
|
const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.tapError((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))), Effect$1.catchTag("PlatformError", () => Effect$1.void));
|
|
3667
|
-
const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
|
|
3769
|
+
const nodeWorkerLauncherLayer = (childEnv) => Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
|
|
3668
3770
|
const crypto = yield* Crypto.Crypto;
|
|
3669
3771
|
const fs = yield* FileSystem.FileSystem;
|
|
3670
3772
|
const path = yield* Path.Path;
|
|
@@ -3683,6 +3785,7 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(functi
|
|
|
3683
3785
|
env: {
|
|
3684
3786
|
STRYKER_WORKER_DIR: workerDir,
|
|
3685
3787
|
STRYKER_SOCKET: socketPath,
|
|
3788
|
+
...childEnv,
|
|
3686
3789
|
...params.env
|
|
3687
3790
|
},
|
|
3688
3791
|
stderr: "inherit"
|
|
@@ -3722,7 +3825,8 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(functi
|
|
|
3722
3825
|
const nodeFsPathLayer$1 = Layer.mergeAll(NodeFileSystem.layer, NodePath.layer);
|
|
3723
3826
|
const nodeSpawnerLayer = NodeChildProcessSpawner.layer.pipe(Layer.provide(nodeFsPathLayer$1));
|
|
3724
3827
|
const nodeBase = Layer.mergeAll(nodeFsPathLayer$1, nodeSpawnerLayer, NodeStdio.layer);
|
|
3725
|
-
const
|
|
3828
|
+
const makeNodePlatformLayer = (options) => Layer.mergeAll(nodeWorkerLauncherLayer(options.childEnv).pipe(Layer.provide(Layer.merge(nodeBase, NodeCrypto.layer))), nodeBase);
|
|
3829
|
+
const nodePlatformLayer = makeNodePlatformLayer({ childEnv: {} });
|
|
3726
3830
|
//#endregion
|
|
3727
3831
|
//#region src/IncrementalDiff.schema.ts
|
|
3728
3832
|
const PositionSchema$1 = S.Struct({
|
|
@@ -3897,7 +4001,7 @@ const writeHtmlFile = (fileName, html) => Effect$1.gen(function* () {
|
|
|
3897
4001
|
const readRenderCommand = (input) => Effect$1.succeed({
|
|
3898
4002
|
_tag: "RenderHtmlReport",
|
|
3899
4003
|
fileName: input.fileName,
|
|
3900
|
-
inlinedBundle: inlinedBundle
|
|
4004
|
+
inlinedBundle: input.inlinedBundle,
|
|
3901
4005
|
report: input.report
|
|
3902
4006
|
});
|
|
3903
4007
|
const writeHtmlReport = Sandwich.named("html_report.write")(readRenderCommand).decide(renderHtmlReport).write({
|
|
@@ -3916,7 +4020,8 @@ const failAsHtmlReporter = (cause) => Reporter_exports.ReporterFailed.make({
|
|
|
3916
4020
|
});
|
|
3917
4021
|
const drainEvents = (fileName, events) => Stream.runForEach(Stream.fromAsyncIterable(events, failAsHtmlReporter).pipe(Stream.filter(S.is(Reporter_exports.MutationTestReportReady))), (ready) => writeHtmlReport.run({
|
|
3918
4022
|
fileName,
|
|
3919
|
-
report: ready.report
|
|
4023
|
+
report: ready.report,
|
|
4024
|
+
inlinedBundle: inlinedBundle()
|
|
3920
4025
|
}).pipe(Effect$1.mapError(failAsHtmlReporter)));
|
|
3921
4026
|
const makeHtmlReporter = dual(2, (options, _init) => (events) => Layer.build(nodeFsPathLayer).pipe(Effect$1.flatMap((platform) => Effect$1.provideContext(drainEvents(options.htmlReporter.fileName, events), platform)), Effect$1.scoped));
|
|
3922
4027
|
var HtmlReporter_exports = /* @__PURE__ */ __exportAll({ makeHtmlReporter: () => makeHtmlReporter });
|
|
@@ -3927,7 +4032,8 @@ const PERCENTAGE_OPTION = /^(100|[1-9]?[0-9])%$/;
|
|
|
3927
4032
|
var TestRunnersOnly = class extends S.TaggedClass()("TestRunnersOnly", {
|
|
3928
4033
|
testRunners: S.Finite,
|
|
3929
4034
|
total: S.Finite,
|
|
3930
|
-
isPercentage: S.Boolean
|
|
4035
|
+
isPercentage: S.Boolean,
|
|
4036
|
+
announcement: S.Option(S.String)
|
|
3931
4037
|
}) {
|
|
3932
4038
|
[ConcurrencyDecisionTypeId] = ConcurrencyDecisionTypeId;
|
|
3933
4039
|
};
|
|
@@ -3935,7 +4041,8 @@ var TestRunnersAndCheckers = class extends S.TaggedClass()("TestRunnersAndChecke
|
|
|
3935
4041
|
testRunners: S.Finite,
|
|
3936
4042
|
checkers: S.Finite,
|
|
3937
4043
|
total: S.Finite,
|
|
3938
|
-
isPercentage: S.Boolean
|
|
4044
|
+
isPercentage: S.Boolean,
|
|
4045
|
+
announcement: S.Option(S.String)
|
|
3939
4046
|
}) {
|
|
3940
4047
|
[ConcurrencyDecisionTypeId] = ConcurrencyDecisionTypeId;
|
|
3941
4048
|
};
|
|
@@ -3957,31 +4064,37 @@ const defaultedTotal = (availableParallelism) => Boolean$1.match(availableParall
|
|
|
3957
4064
|
const percentageDetails = (text, availableParallelism) => Option$1.match(percentageOf(text), {
|
|
3958
4065
|
onSome: (percentage) => ({
|
|
3959
4066
|
total: percentageTotal(percentage, availableParallelism),
|
|
3960
|
-
isPercentage: true
|
|
4067
|
+
isPercentage: true,
|
|
4068
|
+
announcement: Option$1.some(`Computed concurrency ${percentageTotal(percentage, availableParallelism)} from "${text}" based on ${availableParallelism} available parallelism.`)
|
|
3961
4069
|
}),
|
|
3962
4070
|
onNone: () => ({
|
|
3963
4071
|
total: defaultedTotal(availableParallelism),
|
|
3964
|
-
isPercentage: false
|
|
4072
|
+
isPercentage: false,
|
|
4073
|
+
announcement: Option$1.none()
|
|
3965
4074
|
})
|
|
3966
4075
|
});
|
|
3967
4076
|
const detailsOf = (concurrency, availableParallelism) => Match.value(concurrency).pipe(Match.when(Predicate$1.isString, (text) => percentageDetails(text, availableParallelism)), Match.when(Predicate$1.isNumber, (total) => ({
|
|
3968
4077
|
total,
|
|
3969
|
-
isPercentage: false
|
|
4078
|
+
isPercentage: false,
|
|
4079
|
+
announcement: Option$1.none()
|
|
3970
4080
|
})), Match.orElse(() => ({
|
|
3971
4081
|
total: defaultedTotal(availableParallelism),
|
|
3972
|
-
isPercentage: false
|
|
4082
|
+
isPercentage: false,
|
|
4083
|
+
announcement: Option$1.none()
|
|
3973
4084
|
})));
|
|
3974
4085
|
const splitOf = (details, checkerCount) => Boolean$1.match(checkerCount > 0, {
|
|
3975
4086
|
onTrue: () => TestRunnersAndCheckers.make({
|
|
3976
4087
|
testRunners: max$1(floor(details.total / 2), 1),
|
|
3977
4088
|
checkers: max$1(ceil(details.total / 2), 1),
|
|
3978
4089
|
total: details.total,
|
|
3979
|
-
isPercentage: details.isPercentage
|
|
4090
|
+
isPercentage: details.isPercentage,
|
|
4091
|
+
announcement: details.announcement
|
|
3980
4092
|
}),
|
|
3981
4093
|
onFalse: () => TestRunnersOnly.make({
|
|
3982
4094
|
testRunners: details.total,
|
|
3983
4095
|
total: details.total,
|
|
3984
|
-
isPercentage: details.isPercentage
|
|
4096
|
+
isPercentage: details.isPercentage,
|
|
4097
|
+
announcement: details.announcement
|
|
3985
4098
|
})
|
|
3986
4099
|
});
|
|
3987
4100
|
const decide$7 = (command) => Result.succeed(splitOf(detailsOf(command.concurrency, command.availableParallelism), command.checkerCount));
|
|
@@ -4003,19 +4116,15 @@ const readConcurrency = (record) => Effect$1.sync(() => ({
|
|
|
4003
4116
|
availableParallelism: availableParallelism(),
|
|
4004
4117
|
record
|
|
4005
4118
|
}));
|
|
4006
|
-
const announcePercentage = (command, total, isPercentage) => Boolean$1.match(isPercentage, {
|
|
4007
|
-
onTrue: () => Effect$1.logDebug(`Computed concurrency ${total} from "${command.concurrency}" based on ${command.availableParallelism} available parallelism.`),
|
|
4008
|
-
onFalse: () => Effect$1.void
|
|
4009
|
-
});
|
|
4010
4119
|
const concurrencyCell = Sandwich.named("stryker.concurrency")(readConcurrency).decide(resolveConcurrency).write({
|
|
4011
|
-
TestRunnersAndCheckers: (split, command) => Effect$1.as(Effect$1.andThen(
|
|
4120
|
+
TestRunnersAndCheckers: (split, command) => Effect$1.as(Effect$1.andThen(Effect$1.forEach(Option$1.toArray(split.announcement), (line) => Effect$1.logDebug(line), { discard: true }), Effect$1.logInfo(`Creating ${split.checkers} checker process(es) and ${split.testRunners} test runner process(es).`)), {
|
|
4012
4121
|
...command.record,
|
|
4013
4122
|
concurrency: {
|
|
4014
4123
|
testRunners: split.testRunners,
|
|
4015
4124
|
checkers: split.checkers
|
|
4016
4125
|
}
|
|
4017
4126
|
}),
|
|
4018
|
-
TestRunnersOnly: (split, command) => Effect$1.as(Effect$1.andThen(
|
|
4127
|
+
TestRunnersOnly: (split, command) => Effect$1.as(Effect$1.andThen(Effect$1.forEach(Option$1.toArray(split.announcement), (line) => Effect$1.logDebug(line), { discard: true }), Effect$1.logInfo(`Creating ${split.testRunners} test runner process(es).`)), {
|
|
4019
4128
|
...command.record,
|
|
4020
4129
|
concurrency: {
|
|
4021
4130
|
testRunners: split.testRunners,
|
|
@@ -4058,132 +4167,8 @@ const admitIncrementalReport = Workflow.make({
|
|
|
4058
4167
|
error: S.Never,
|
|
4059
4168
|
decide: (command) => Result.succeed(decide$6(command))
|
|
4060
4169
|
});
|
|
4061
|
-
const isVmRunner = (name) => typeof name === "string" && name.toLowerCase() === "vm";
|
|
4062
|
-
const vmRunnerCapabilities = { reloadEnvironment: true };
|
|
4063
|
-
const HOST_TIMEOUT_SLACK_MS = 1e3;
|
|
4064
|
-
const messageOf$1 = (cause) => cause instanceof Error ? cause.message : new Error("the vm test runner failed", { cause }).message;
|
|
4065
|
-
const testResultOf = (test) => {
|
|
4066
|
-
const base = {
|
|
4067
|
-
id: test.id,
|
|
4068
|
-
name: test.name,
|
|
4069
|
-
timeSpentMs: test.timeSpentMs
|
|
4070
|
-
};
|
|
4071
|
-
return Match.value(test.status).pipe(Match.when("failed", () => ({
|
|
4072
|
-
...base,
|
|
4073
|
-
status: "failed",
|
|
4074
|
-
failureMessage: test.failureMessage ?? ""
|
|
4075
|
-
})), Match.when("skipped", () => ({
|
|
4076
|
-
...base,
|
|
4077
|
-
status: "skipped"
|
|
4078
|
-
})), Match.orElse(() => ({
|
|
4079
|
-
...base,
|
|
4080
|
-
status: "success"
|
|
4081
|
-
})));
|
|
4082
|
-
};
|
|
4083
|
-
const dryRunResultOf = (response) => {
|
|
4084
|
-
const tests = response.tests.map(testResultOf);
|
|
4085
|
-
return Option$1.match(Option$1.fromUndefinedOr(response.mutantCoverage), {
|
|
4086
|
-
onNone: () => ({
|
|
4087
|
-
status: "complete",
|
|
4088
|
-
tests
|
|
4089
|
-
}),
|
|
4090
|
-
onSome: (mutantCoverage) => ({
|
|
4091
|
-
status: "complete",
|
|
4092
|
-
tests,
|
|
4093
|
-
mutantCoverage
|
|
4094
|
-
})
|
|
4095
|
-
});
|
|
4096
|
-
};
|
|
4097
|
-
const respond = (response) => Match.value(response).pipe(Match.discriminator("status")("init-failed", (failed) => Effect$1.fail(TestRunner_exports.TestRunnerFailed.make({
|
|
4098
|
-
runnerName: "vm",
|
|
4099
|
-
phase: "init",
|
|
4100
|
-
cause: failed.message
|
|
4101
|
-
}))), Match.discriminator("status")("timeout", () => Effect$1.succeed({ status: "timeout" })), Match.discriminator("status")("error", (errored) => Effect$1.succeed({
|
|
4102
|
-
status: "error",
|
|
4103
|
-
errorMessage: errored.errorMessage
|
|
4104
|
-
})), Match.discriminator("status")("complete", (complete) => Effect$1.succeed(dryRunResultOf(complete))), Match.exhaustive);
|
|
4105
|
-
const pooledVmRunner = (config, scope) => {
|
|
4106
|
-
let client;
|
|
4107
|
-
let sessionTestFiles = config.testFiles;
|
|
4108
|
-
const sessionOptions = () => ({
|
|
4109
|
-
sandboxWorkingDirectory: config.sandboxWorkingDirectory,
|
|
4110
|
-
testFiles: sessionTestFiles
|
|
4111
|
-
});
|
|
4112
|
-
const spawnClient = Effect$1.try({
|
|
4113
|
-
try: () => {
|
|
4114
|
-
const spawned = Session.createVmWorkerClient(sessionOptions(), { onExit: () => {
|
|
4115
|
-
if (client === spawned) client = void 0;
|
|
4116
|
-
} });
|
|
4117
|
-
return spawned;
|
|
4118
|
-
},
|
|
4119
|
-
catch: (cause) => TestRunner_exports.TestRunnerFailed.make({
|
|
4120
|
-
runnerName: "vm",
|
|
4121
|
-
phase: "init",
|
|
4122
|
-
cause: `the vm test runner could not start its worker: ${messageOf$1(cause)}`
|
|
4123
|
-
})
|
|
4124
|
-
});
|
|
4125
|
-
const dropClient = Effect$1.suspend(() => {
|
|
4126
|
-
const current = client;
|
|
4127
|
-
client = void 0;
|
|
4128
|
-
return current === void 0 ? Effect$1.void : Effect$1.promise(() => current.terminate());
|
|
4129
|
-
});
|
|
4130
|
-
const run = (request) => Effect$1.gen(function* () {
|
|
4131
|
-
if (client === void 0) {
|
|
4132
|
-
const spawned = yield* spawnClient;
|
|
4133
|
-
yield* Scope.addFinalizer(scope, Effect$1.promise(() => spawned.terminate()));
|
|
4134
|
-
client = spawned;
|
|
4135
|
-
}
|
|
4136
|
-
const current = client;
|
|
4137
|
-
const answer = yield* Effect$1.tryPromise({
|
|
4138
|
-
try: () => current.run(request),
|
|
4139
|
-
catch: (cause) => ({
|
|
4140
|
-
status: "error",
|
|
4141
|
-
errorMessage: messageOf$1(cause)
|
|
4142
|
-
})
|
|
4143
|
-
}).pipe(Effect$1.catch((failed) => Effect$1.succeed(failed)), Effect$1.timeoutOrElse({
|
|
4144
|
-
duration: request.timeoutMs + HOST_TIMEOUT_SLACK_MS,
|
|
4145
|
-
orElse: () => dropClient.pipe(Effect$1.as({ status: "timeout" }))
|
|
4146
|
-
}));
|
|
4147
|
-
return yield* respond(answer);
|
|
4148
|
-
}).pipe(Effect$1.onInterrupt(() => dropClient));
|
|
4149
|
-
const shouldAdoptTestFiles = () => config.testFiles.length === 0 && client === void 0;
|
|
4150
|
-
const adoptedTestFiles = (testFiles) => testFiles ?? [];
|
|
4151
|
-
const testFilterFieldOf = (testFilter) => testFilter === void 0 ? {} : { testFilter: [...testFilter] };
|
|
4152
|
-
const hitLimitFieldOf = (hitLimit) => hitLimit === void 0 ? {} : { hitLimit };
|
|
4153
|
-
const mutantRequestOf = (options) => ({
|
|
4154
|
-
kind: "mutant",
|
|
4155
|
-
timeoutMs: options.timeout,
|
|
4156
|
-
activeMutantId: String(options.activeMutant.id),
|
|
4157
|
-
...testFilterFieldOf(options.testFilter),
|
|
4158
|
-
...hitLimitFieldOf(options.hitLimit),
|
|
4159
|
-
reloadEnvironment: options.reloadEnvironment
|
|
4160
|
-
});
|
|
4161
|
-
return make$3({
|
|
4162
|
-
capabilities: Effect$1.succeed(vmRunnerCapabilities),
|
|
4163
|
-
init: Effect$1.void,
|
|
4164
|
-
dryRun: (options) => {
|
|
4165
|
-
if (shouldAdoptTestFiles()) sessionTestFiles = adoptedTestFiles(options.testFiles);
|
|
4166
|
-
return run({
|
|
4167
|
-
kind: "dry",
|
|
4168
|
-
timeoutMs: options.timeout,
|
|
4169
|
-
reloadEnvironment: true
|
|
4170
|
-
});
|
|
4171
|
-
},
|
|
4172
|
-
mutantRun: (options) => run(mutantRequestOf(options)).pipe(Effect$1.map((dryRunResult) => interpretDryRunResult(InterpretDryRunResultCommand.make({ dryRunResult }))), Effect$1.flatMap((decided) => Result.match(decided, {
|
|
4173
|
-
onFailure: (failure) => Effect$1.fail(failure),
|
|
4174
|
-
onSuccess: (decision) => Effect$1.succeed(decision.asResult)
|
|
4175
|
-
})), Effect$1.catchTag("TestRunnerFailed", (failure) => Effect$1.succeed({
|
|
4176
|
-
status: "error",
|
|
4177
|
-
errorMessage: failure.cause
|
|
4178
|
-
})))
|
|
4179
|
-
});
|
|
4180
|
-
};
|
|
4181
|
-
const vmTestRunner = (config) => Effect$1.gen(function* () {
|
|
4182
|
-
const scope = yield* Effect$1.scope;
|
|
4183
|
-
return pooledVmRunner(config, scope);
|
|
4184
|
-
});
|
|
4185
4170
|
//#endregion
|
|
4186
|
-
//#region src/read-project.
|
|
4171
|
+
//#region src/read-project.parts.ts
|
|
4187
4172
|
const ALWAYS_IGNORE = Object.freeze([
|
|
4188
4173
|
"node_modules",
|
|
4189
4174
|
".git",
|
|
@@ -4195,23 +4180,9 @@ const ALWAYS_IGNORE = Object.freeze([
|
|
|
4195
4180
|
]);
|
|
4196
4181
|
const IGNORE_PATTERN_CHARACTER = "!";
|
|
4197
4182
|
const DEFAULT_GLOB = "**/*.{js,ts,jsx,tsx,html,vue,mjs,mts,cts,cjs}";
|
|
4198
|
-
const
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
"**/dist/**",
|
|
4202
|
-
"**/.{idea,git,cache,output,temp}/**",
|
|
4203
|
-
`**/${tempDirName}/**`
|
|
4204
|
-
];
|
|
4205
|
-
const shouldDiscoverTestFiles = (options) => options.testFiles.length === 0 && isVmRunner(options.testRunner);
|
|
4206
|
-
const testFileSelectionOf = (options) => Boolean.match(shouldDiscoverTestFiles(options), {
|
|
4207
|
-
onTrue: () => ({
|
|
4208
|
-
testFilePatterns: VITEST_DEFAULT_TEST_FILE_PATTERNS,
|
|
4209
|
-
testFileIgnores: defaultTestFileIgnores(options.tempDirName)
|
|
4210
|
-
}),
|
|
4211
|
-
onFalse: () => ({
|
|
4212
|
-
testFilePatterns: options.testFiles,
|
|
4213
|
-
testFileIgnores: []
|
|
4214
|
-
})
|
|
4183
|
+
const testFileSelectionOf = (options) => ({
|
|
4184
|
+
testFilePatterns: options.testFiles,
|
|
4185
|
+
testFileIgnores: []
|
|
4215
4186
|
});
|
|
4216
4187
|
const normalizeFileName = (value) => value.replace(/\\/g, "/");
|
|
4217
4188
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -4596,7 +4567,7 @@ const readProjectCommand = (input) => Effect$1.gen(function* () {
|
|
|
4596
4567
|
const mutatePatterns = input.options.mutate;
|
|
4597
4568
|
const { testFileIgnores, testFilePatterns } = testFileSelectionOf(input.options);
|
|
4598
4569
|
const inputFileNames = yield* resolveInputFileNames(ignoreRulesOf(input.options), input.basePath);
|
|
4599
|
-
const defaults = yield*
|
|
4570
|
+
const defaults = yield* defaultOptions;
|
|
4600
4571
|
const decision = selectFiles(selectionOf$1(inputFileNames, mutatePatterns, testFilePatterns, testFileIgnores, input.basePath, input.targetMutatePatterns));
|
|
4601
4572
|
yield* Boolean.match(stringArrayEquivalence(mutatePatterns, defaults.mutate), {
|
|
4602
4573
|
onTrue: () => Effect$1.void,
|
|
@@ -4619,7 +4590,7 @@ const readProjectCommand = (input) => Effect$1.gen(function* () {
|
|
|
4619
4590
|
testFiles: [...decision.testFiles]
|
|
4620
4591
|
});
|
|
4621
4592
|
});
|
|
4622
|
-
const discardLogOf = (command, discard) => Boolean.match(command.incremental, {
|
|
4593
|
+
const discardLogOf = ({ command, discard }) => Boolean.match(command.incremental, {
|
|
4623
4594
|
onFalse: () => Effect$1.void,
|
|
4624
4595
|
onTrue: () => Option$1.match(Option$1.fromUndefinedOr(command.contents), {
|
|
4625
4596
|
onNone: () => Effect$1.void,
|
|
@@ -4629,15 +4600,26 @@ const discardLogOf = (command, discard) => Boolean.match(command.incremental, {
|
|
|
4629
4600
|
})
|
|
4630
4601
|
})
|
|
4631
4602
|
});
|
|
4632
|
-
const projectOf = (command, report) => ({
|
|
4603
|
+
const projectOf = ({ command, report }) => ({
|
|
4633
4604
|
options: command.options,
|
|
4634
4605
|
targetMutatePatterns: command.targetMutatePatterns,
|
|
4635
4606
|
basePath: command.basePath,
|
|
4636
4607
|
project: makeProject(command.fileDescriptions, report, command.testFiles)
|
|
4637
4608
|
});
|
|
4609
|
+
//#endregion
|
|
4610
|
+
//#region src/read-project.cell.ts
|
|
4638
4611
|
const readProjectCell = Sandwich.named("stryker.project_read")(readProjectCommand).decide(admitIncrementalReport).write({
|
|
4639
|
-
IncrementalReportKeep: (keep, command) => Effect$1.succeed(projectOf(
|
|
4640
|
-
|
|
4612
|
+
IncrementalReportKeep: (keep, command) => Effect$1.succeed(projectOf({
|
|
4613
|
+
command,
|
|
4614
|
+
report: keep.report
|
|
4615
|
+
})),
|
|
4616
|
+
IncrementalReportDiscard: (discard, command) => Effect$1.as(discardLogOf({
|
|
4617
|
+
command,
|
|
4618
|
+
discard
|
|
4619
|
+
}), projectOf({
|
|
4620
|
+
command,
|
|
4621
|
+
report: void 0
|
|
4622
|
+
})),
|
|
4641
4623
|
CommandRejected: ({ issue }) => Effect$1.fail(badArgument({
|
|
4642
4624
|
module: "stryker-js",
|
|
4643
4625
|
method: "incremental-report.cell",
|
|
@@ -4712,8 +4694,11 @@ const formatTotal = (total) => Option$1.match(Option$1.fromNullishOr(total), {
|
|
|
4712
4694
|
onSome: (val) => String(val)
|
|
4713
4695
|
});
|
|
4714
4696
|
const formatStderrEvent = (event) => Match.value(event).pipe(Match.tag("plan", (e) => `plan ${e.total} mutants`), Match.tag("phase", (e) => `phase ${e.phase}`), Match.tag("tick", (e) => `${e.completed}/${formatTotal(e.total)} elapsed ${e.elapsedMs}ms`), Match.tag("verdict", (e) => `score ${formatScore(e.score)} killed ${e.counts.killed} survived ${e.counts.survived}`), Match.tag("error", (e) => `error ${e.error}`), Match.tag("stream", () => null), Match.tag("mutant", () => null), Match.tag("help", () => null), Match.tag("plugins", () => null), Match.tag("formats", () => null), Match.tag("skipped", () => null), Match.exhaustive);
|
|
4715
|
-
const stderrLineFor = (state, event) =>
|
|
4716
|
-
|
|
4697
|
+
const stderrLineFor = (state, event) => Boolean$1.match(Boolean$1.and(state.mode === "human", !state.terminalSeen), {
|
|
4698
|
+
onTrue: () => formatStderrEvent(event),
|
|
4699
|
+
onFalse: () => null
|
|
4700
|
+
});
|
|
4701
|
+
const shouldFrame = (state) => !state.terminalSeen;
|
|
4717
4702
|
const decideFrame = (command) => {
|
|
4718
4703
|
const nextState = noteState(command.state, command.event);
|
|
4719
4704
|
const stderrLine = stderrLineFor(command.state, command.event);
|
|
@@ -4772,7 +4757,10 @@ const formatTemplate = (template, args) => {
|
|
|
4772
4757
|
};
|
|
4773
4758
|
const headOf = (args) => Option$1.fromNullishOr(args[0]);
|
|
4774
4759
|
const formatArgs = (args) => Option$1.match(Option$1.filter(headOf(args), Predicate$1.isString), {
|
|
4775
|
-
onSome: (first) =>
|
|
4760
|
+
onSome: (first) => Boolean$1.match(args.length === 1, {
|
|
4761
|
+
onTrue: () => first,
|
|
4762
|
+
onFalse: () => formatTemplate(first, args.slice(1))
|
|
4763
|
+
}),
|
|
4776
4764
|
onNone: () => args.map(inspectValue).join(" ")
|
|
4777
4765
|
});
|
|
4778
4766
|
const DEFAULT_CONSOLE_LABEL = "default";
|
|
@@ -5006,7 +4994,7 @@ const PriorReportDocument = S.Struct({
|
|
|
5006
4994
|
}))
|
|
5007
4995
|
});
|
|
5008
4996
|
//#endregion
|
|
5009
|
-
//#region src/Survivors/Survivors.
|
|
4997
|
+
//#region src/Survivors/Survivors.parts.ts
|
|
5010
4998
|
const DEFAULT_SURVIVORS_PRIOR_REPORT = "reports/mutation-report.json";
|
|
5011
4999
|
const EMPTY_CONFIG = {};
|
|
5012
5000
|
const hashContent = (content) => bytesToHex(sha256(utf8ToBytes(content)));
|
|
@@ -5035,9 +5023,9 @@ const reportMutantToMutant = (file, mutant, resolveAbsolutePath, relativize) =>
|
|
|
5035
5023
|
};
|
|
5036
5024
|
const extractSurvivors = (priorReport, resolveAbsolutePath, relativize) => Object.entries(priorReport.files).flatMap(([file, fileResult]) => fileResult.mutants.filter((mutant) => mutant.status === "Survived").map((mutant) => reportMutantToMutant(file, mutant, resolveAbsolutePath, relativize)));
|
|
5037
5025
|
const resolveAbsolutePathOf = (basePath) => (file) => `${basePath}/${file}`;
|
|
5038
|
-
const resolveSurvivorsRunOptions = (
|
|
5026
|
+
const resolveSurvivorsRunOptions = (input) => readConfig(input.cliOptions, {
|
|
5039
5027
|
command: "run",
|
|
5040
|
-
mode
|
|
5028
|
+
mode: input.mode
|
|
5041
5029
|
});
|
|
5042
5030
|
const priorReportPathOf = (resolved) => Option$1.getOrElse(Option$1.filter(Option$1.fromUndefinedOr(resolved["survivorsPriorReport"]), Predicate$1.isString), () => DEFAULT_SURVIVORS_PRIOR_REPORT);
|
|
5043
5031
|
const readPriorReport = (priorReportPath) => Effect$1.flatMap(FileSystem.FileSystem, (fs) => fs.readFileString(priorReportPath).pipe(Effect$1.map((text) => ({
|
|
@@ -5060,14 +5048,11 @@ const readSourceFile = (file) => Effect$1.flatMap(FileSystem.FileSystem, (fs) =>
|
|
|
5060
5048
|
}))));
|
|
5061
5049
|
const SOURCE_HASH_CONCURRENCY = 24;
|
|
5062
5050
|
const currentSourceHashesFor = (files) => Effect$1.map(Effect$1.forEach(files, (file) => Effect$1.map(readSourceFile(file), (content) => [file, hashContent(content)]), { concurrency: SOURCE_HASH_CONCURRENCY }), (pairs) => Object.fromEntries(pairs));
|
|
5063
|
-
|
|
5064
|
-
const
|
|
5065
|
-
const
|
|
5066
|
-
const
|
|
5067
|
-
|
|
5068
|
-
const read = yield* readPriorReport(priorReportPath);
|
|
5069
|
-
const sourceContentHashes = yield* currentSourceHashesFor(priorReportFileKeys(read.raw));
|
|
5070
|
-
return yield* Boolean$1.match(read.found, {
|
|
5051
|
+
const survivorsRawOf = (input) => {
|
|
5052
|
+
const { read, resolvedOptions, priorReportPath, basePath, sourceContentHashes } = input;
|
|
5053
|
+
const relativize = (fileName) => RelativeNormalizedFileName.fromAbsolute(fileName, basePath).fileName;
|
|
5054
|
+
const resolveAbsolutePath = resolveAbsolutePathOf(basePath);
|
|
5055
|
+
return Boolean$1.match(read.found, {
|
|
5071
5056
|
onFalse: () => Effect$1.succeed({
|
|
5072
5057
|
currentConfig: resolvedOptions,
|
|
5073
5058
|
frameworkVersion: StrykerPackage.version,
|
|
@@ -5095,6 +5080,22 @@ Sandwich.named("stryker.survivors_admission")((input) => Effect$1.gen(function*
|
|
|
5095
5080
|
})
|
|
5096
5081
|
}))
|
|
5097
5082
|
});
|
|
5083
|
+
};
|
|
5084
|
+
Sandwich.named("stryker.survivors_admission")((input) => Effect$1.gen(function* () {
|
|
5085
|
+
const resolvedOptions = yield* resolveSurvivorsRunOptions({
|
|
5086
|
+
cliOptions: input.cliOptions,
|
|
5087
|
+
mode: input.mode
|
|
5088
|
+
});
|
|
5089
|
+
const priorReportPath = priorReportPathOf(resolvedOptions);
|
|
5090
|
+
const read = yield* readPriorReport(priorReportPath);
|
|
5091
|
+
const sourceContentHashes = yield* currentSourceHashesFor(priorReportFileKeys(read.raw));
|
|
5092
|
+
return yield* survivorsRawOf({
|
|
5093
|
+
read,
|
|
5094
|
+
resolvedOptions,
|
|
5095
|
+
priorReportPath,
|
|
5096
|
+
basePath: input.basePath,
|
|
5097
|
+
sourceContentHashes
|
|
5098
|
+
});
|
|
5098
5099
|
})).decide(admitSurvivorsRun).write({
|
|
5099
5100
|
Admitted: (admitted, raw) => Effect$1.map(S.decodeEffect(Admitted)(admitted), (admission) => ({
|
|
5100
5101
|
admission,
|
|
@@ -5411,7 +5412,7 @@ var RunEventDrain = class RunEventDrain extends Context.Service()("@systemfsoftw
|
|
|
5411
5412
|
static layer = Layer.effect(RunEventDrain, Effect$1.gen(function* () {
|
|
5412
5413
|
const stdio = yield* Stdio.Stdio;
|
|
5413
5414
|
return RunEventDrain.of({
|
|
5414
|
-
drainFramed: (framed) => drainOf(stdio, framed),
|
|
5415
|
+
drainFramed: (framed, toStdout) => drainOf(stdio, framed, toStdout),
|
|
5415
5416
|
setProgressStreamFile: () => Effect$1.void
|
|
5416
5417
|
});
|
|
5417
5418
|
}));
|
|
@@ -5424,25 +5425,29 @@ var RunEventDrain = class RunEventDrain extends Context.Service()("@systemfsoftw
|
|
|
5424
5425
|
};
|
|
5425
5426
|
const RunEventDrainLive = RunEventDrain.layer;
|
|
5426
5427
|
const encodeUtf8 = (line) => new TextEncoder().encode(line);
|
|
5427
|
-
const
|
|
5428
|
+
const runToSink = (stdio, lines, toStdout) => Boolean$1.match(toStdout, {
|
|
5429
|
+
onTrue: () => Stream.run(lines, stdio.stdout({ endOnDone: true })),
|
|
5430
|
+
onFalse: () => Stream.runDrain(lines)
|
|
5431
|
+
});
|
|
5432
|
+
const drainToSinks = (fs, path, stdio, fileName, toStdout, framed) => Effect$1.gen(function* () {
|
|
5428
5433
|
yield* fs.makeDirectory(path.dirname(fileName), { recursive: true });
|
|
5429
5434
|
yield* Effect$1.scoped(Effect$1.gen(function* () {
|
|
5430
5435
|
const handle = yield* fs.open(fileName, { flag: "w" });
|
|
5431
5436
|
const withFile = framed.pipe(Stream.tap((line) => handle.writeAll(encodeUtf8(line)).pipe(Effect$1.flatMap(() => handle.sync))));
|
|
5432
|
-
yield*
|
|
5437
|
+
yield* runToSink(stdio, withFile, toStdout).pipe(Effect$1.ignore);
|
|
5433
5438
|
}));
|
|
5434
5439
|
}).pipe(Effect$1.orDie);
|
|
5435
5440
|
const drainFileOf = (stdio, fs, path) => Effect$1.gen(function* () {
|
|
5436
5441
|
const fileNameRef = yield* Ref.make(DEFAULT_PROGRESS_STREAM_FILE);
|
|
5437
5442
|
return RunEventDrain.of({
|
|
5438
|
-
drainFramed: (framed) => Effect$1.gen(function* () {
|
|
5443
|
+
drainFramed: (framed, toStdout) => Effect$1.gen(function* () {
|
|
5439
5444
|
const fileName = yield* Ref.get(fileNameRef);
|
|
5440
|
-
yield*
|
|
5445
|
+
yield* drainToSinks(fs, path, stdio, fileName, toStdout, framed);
|
|
5441
5446
|
}).pipe(Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_file_failed", cause)), Effect$1.ignoreCause),
|
|
5442
5447
|
setProgressStreamFile: (fileName) => Ref.set(fileNameRef, fileName)
|
|
5443
5448
|
});
|
|
5444
5449
|
});
|
|
5445
|
-
const drainOf = (stdio, framed) =>
|
|
5450
|
+
const drainOf = (stdio, framed, toStdout) => runToSink(stdio, framed, toStdout).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_failed", cause)), Effect$1.ignoreCause);
|
|
5446
5451
|
const writeStderr = (stdio, line) => Stream.run(Stream.succeed(`${line}\n`), stdio.stderr({ endOnDone: false })).pipe(Effect$1.ignore);
|
|
5447
5452
|
const emitNullScoreVerdict = (params) => {
|
|
5448
5453
|
const { stream, mode, thresholds, basePath, pathService } = params;
|
|
@@ -5490,7 +5495,7 @@ const emitHelpEnvelope = (stream, help) => Queue.offer(stream.queue, HelpRendere
|
|
|
5490
5495
|
const helpPayload = (ok, captured) => Option$1.filter(Option$1.some(captured), () => ok.help || captured.length > 0);
|
|
5491
5496
|
const emitNullScoreVerdictWhenOpen = (stream, mode, basePath, pathService) => Effect$1.andThen(stream.isOpen, (open) => Boolean$1.match(open, {
|
|
5492
5497
|
onTrue: () => Effect$1.gen(function* () {
|
|
5493
|
-
const defaults = yield*
|
|
5498
|
+
const defaults = yield* defaultOptions;
|
|
5494
5499
|
yield* emitNullScoreVerdict({
|
|
5495
5500
|
stream,
|
|
5496
5501
|
mode,
|
|
@@ -5589,7 +5594,8 @@ const makeRunEventStream = (resolved) => Effect$1.gen(function* () {
|
|
|
5589
5594
|
open: Effect$1.gen(function* () {
|
|
5590
5595
|
yield* Option$1.match(yield* Ref.get(drainFiberRef), {
|
|
5591
5596
|
onNone: () => Effect$1.gen(function* () {
|
|
5592
|
-
const
|
|
5597
|
+
const mode = (yield* Ref.get(stateRef)).mode;
|
|
5598
|
+
const drainFiber = yield* drain.drainFramed(framed, mode === "machine").pipe(Effect$1.forkDetach);
|
|
5593
5599
|
yield* Ref.set(drainFiberRef, Option$1.some(drainFiber));
|
|
5594
5600
|
}),
|
|
5595
5601
|
onSome: () => Effect$1.void
|
|
@@ -5611,6 +5617,14 @@ const makeRunEventStream = (resolved) => Effect$1.gen(function* () {
|
|
|
5611
5617
|
var DryRunError = class extends S.TaggedError()("DryRunError", {
|
|
5612
5618
|
stage: S.Literals(["dryRun", "dryRunNoTests"]),
|
|
5613
5619
|
reason: S.String
|
|
5620
|
+
}) {
|
|
5621
|
+
get message() {
|
|
5622
|
+
return this.reason;
|
|
5623
|
+
}
|
|
5624
|
+
};
|
|
5625
|
+
var FailedTestSummary = class extends S.Class("FailedTestSummary")({
|
|
5626
|
+
name: S.String,
|
|
5627
|
+
failureMessage: S.String
|
|
5614
5628
|
}) {};
|
|
5615
5629
|
var DryRunCommand = class extends S.TaggedClass()("DryRunCommand", {
|
|
5616
5630
|
status: S.Literals([
|
|
@@ -5620,6 +5634,7 @@ var DryRunCommand = class extends S.TaggedClass()("DryRunCommand", {
|
|
|
5620
5634
|
]),
|
|
5621
5635
|
testCount: S.Finite,
|
|
5622
5636
|
failedTestCount: S.Finite,
|
|
5637
|
+
failedTests: S.Array(FailedTestSummary),
|
|
5623
5638
|
allowEmpty: S.Boolean,
|
|
5624
5639
|
errorMessage: S.optional(S.String),
|
|
5625
5640
|
reason: S.optional(S.String)
|
|
@@ -5637,7 +5652,8 @@ var DryRunPassed = class extends S.TaggedClass()("DryRunPassed", { testCount: S.
|
|
|
5637
5652
|
};
|
|
5638
5653
|
var DryRunFailed = class extends S.TaggedClass()("DryRunFailed", {
|
|
5639
5654
|
testCount: S.Finite,
|
|
5640
|
-
failedTestCount: S.Finite
|
|
5655
|
+
failedTestCount: S.Finite,
|
|
5656
|
+
failedTests: S.Array(FailedTestSummary)
|
|
5641
5657
|
}) {
|
|
5642
5658
|
[DryRunDecisionTypeId] = DryRunDecisionTypeId;
|
|
5643
5659
|
};
|
|
@@ -5648,13 +5664,15 @@ const completeOutcomeOf = (command) => Match.value(command).pipe(Match.when({
|
|
|
5648
5664
|
const decideComplete = (command) => Match.value({
|
|
5649
5665
|
outcome: completeOutcomeOf(command),
|
|
5650
5666
|
testCount: command.testCount,
|
|
5651
|
-
failedTestCount: command.failedTestCount
|
|
5667
|
+
failedTestCount: command.failedTestCount,
|
|
5668
|
+
failedTests: command.failedTests
|
|
5652
5669
|
}).pipe(Match.when({ outcome: "noTests" }, () => Result.fail(DryRunError.make({
|
|
5653
5670
|
stage: "dryRunNoTests",
|
|
5654
5671
|
reason: "No tests were executed. Stryker will exit prematurely. Please check your configuration."
|
|
5655
|
-
}))), Match.when({ outcome: "failed" }, ({ testCount, failedTestCount }) => Result.succeed(DryRunFailed.make({
|
|
5672
|
+
}))), Match.when({ outcome: "failed" }, ({ testCount, failedTestCount, failedTests }) => Result.succeed(DryRunFailed.make({
|
|
5656
5673
|
testCount,
|
|
5657
|
-
failedTestCount
|
|
5674
|
+
failedTestCount,
|
|
5675
|
+
failedTests
|
|
5658
5676
|
}))), Match.when({ outcome: "passed" }, ({ testCount }) => Result.succeed(DryRunPassed.make({ testCount }))), Match.exhaustive);
|
|
5659
5677
|
const reasonOrDefault = (reason, fallback) => Match.value(reason).pipe(Match.when(void 0, () => fallback), Match.orElse((present) => present));
|
|
5660
5678
|
const decide$5 = (command) => Match.value(command.status).pipe(Match.when("Error", () => Result.fail(DryRunError.make({
|
|
@@ -5704,7 +5722,52 @@ var PluginLoadRefusedError = class extends Schema.TaggedError()("PluginLoadRefus
|
|
|
5704
5722
|
}
|
|
5705
5723
|
};
|
|
5706
5724
|
//#endregion
|
|
5707
|
-
//#region src/
|
|
5725
|
+
//#region src/Sandbox.handle.ts
|
|
5726
|
+
const TypeId$3 = Symbol.for("~systemfsoftware/stryker-js/Sandbox");
|
|
5727
|
+
const SandboxHandle = Handle.make()(TypeId$3);
|
|
5728
|
+
SandboxHandle.is;
|
|
5729
|
+
const sandboxFileNameOf = (fileMap, fileName) => Match.value(fileMap.get(fileName)).pipe(Match.when(Predicate$1.isString, (sandboxFileName) => Result.succeed(sandboxFileName)), Match.orElse(() => Result.fail(StrykerError.make({ message: `Cannot find sandbox file for ${fileName}` }))));
|
|
5730
|
+
const withoutLeadingSeparator = (suffix) => Boolean$1.match(suffix.startsWith("/"), {
|
|
5731
|
+
onTrue: () => suffix.slice(1),
|
|
5732
|
+
onFalse: () => suffix
|
|
5733
|
+
});
|
|
5734
|
+
const relativeToBase = (resolvedSandbox, resolvedWorking, base, pathService) => {
|
|
5735
|
+
const trimmed = withoutLeadingSeparator(resolvedSandbox.slice(resolvedWorking.length));
|
|
5736
|
+
return Boolean$1.match(trimmed.length === 0, {
|
|
5737
|
+
onTrue: () => base,
|
|
5738
|
+
onFalse: () => pathService.join(base, trimmed)
|
|
5739
|
+
});
|
|
5740
|
+
};
|
|
5741
|
+
const originalFileNameOf = (sandboxFileName, workingDirectory, base, pathService) => {
|
|
5742
|
+
const resolvedSandbox = pathService.resolve(sandboxFileName);
|
|
5743
|
+
const resolvedWorking = pathService.resolve(workingDirectory);
|
|
5744
|
+
return Boolean$1.match(resolvedSandbox.startsWith(resolvedWorking), {
|
|
5745
|
+
onTrue: () => relativeToBase(resolvedSandbox, resolvedWorking, base, pathService),
|
|
5746
|
+
onFalse: () => resolvedSandbox.replace(resolvedWorking, base)
|
|
5747
|
+
});
|
|
5748
|
+
};
|
|
5749
|
+
const make$1 = (options) => SandboxHandle.make({ workingDirectory: options.workingDirectory }, {
|
|
5750
|
+
fileMap: options.fileMap,
|
|
5751
|
+
basePath: options.basePath,
|
|
5752
|
+
pathService: options.pathService
|
|
5753
|
+
});
|
|
5754
|
+
const sandboxFileFor = dual(2, (self, fileName) => sandboxFileNameOf(SandboxHandle.slot(self).fileMap, fileName));
|
|
5755
|
+
const originalFileFor = dual(2, (self, sandboxFileName) => {
|
|
5756
|
+
const slot = SandboxHandle.slot(self);
|
|
5757
|
+
return originalFileNameOf(sandboxFileName, self.workingDirectory, slot.basePath, slot.pathService);
|
|
5758
|
+
});
|
|
5759
|
+
const VM_RUNNER_SPECIFIER = "@systemfsoftware/stryker-js-vm-runner";
|
|
5760
|
+
const vmRunnerOptions = { pool: "threads" };
|
|
5761
|
+
const vmRunnerPluginUrl = () => import.meta.resolve(VM_RUNNER_SPECIFIER);
|
|
5762
|
+
const isVmRunner = (name) => typeof name === "string" && name.toLowerCase() === "vm";
|
|
5763
|
+
const vmTestRunnerConfig = () => ({
|
|
5764
|
+
plugin: vmRunnerPluginUrl(),
|
|
5765
|
+
options: { ...vmRunnerOptions }
|
|
5766
|
+
});
|
|
5767
|
+
const testRunnerConfigOf = (configured) => Match.value(configured).pipe(Match.when(isVmRunner, vmTestRunnerConfig), Match.orElse((unchanged) => unchanged));
|
|
5768
|
+
//#endregion
|
|
5769
|
+
//#region src/TestRunner.blueprint.ts
|
|
5770
|
+
const TypeId$2 = Symbol.for("~systemfsoftware/stryker-js/TestRunner");
|
|
5708
5771
|
const toRunnerBootFailure = (runnerName) => (error) => Match.value(error).pipe(Match.tag("WorkerBootTimeoutError", (timeout) => TestRunner_exports.TestRunnerFailed.make({
|
|
5709
5772
|
runnerName,
|
|
5710
5773
|
phase: "init",
|
|
@@ -5727,12 +5790,16 @@ const toRunnerFailure = (runnerName, phase) => (error) => Match.value(error).pip
|
|
|
5727
5790
|
* `Pool.invalidate` and the crash-retry combinator can only act on a failure they
|
|
5728
5791
|
* can see.
|
|
5729
5792
|
*/
|
|
5730
|
-
const
|
|
5731
|
-
const
|
|
5732
|
-
|
|
5793
|
+
const scopedOf = (params) => Effect$1.gen(function* () {
|
|
5794
|
+
const options = {
|
|
5795
|
+
...params.options,
|
|
5796
|
+
testRunner: testRunnerConfigOf(params.options.testRunner)
|
|
5797
|
+
};
|
|
5798
|
+
const runnerName = Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
5799
|
+
const execArgv = Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => Match.value(runner.nodeArgs).pipe(Match.when(Match.undefined, () => options.testRunnerNodeArgs), Match.orElse((args) => args))), Match.orElse(() => options.testRunnerNodeArgs));
|
|
5733
5800
|
const client = yield* makeWorkerClient({
|
|
5734
5801
|
rpcs: Plugin_exports.TestRunnerRpcs,
|
|
5735
|
-
options
|
|
5802
|
+
options,
|
|
5736
5803
|
entrypoint: params.workerEntrypoint,
|
|
5737
5804
|
workingDirectory: params.sandboxWorkingDirectory,
|
|
5738
5805
|
execArgv: [...execArgv],
|
|
@@ -5750,11 +5817,13 @@ const makeChildProcessTestRunner = (params) => Effect$1.gen(function* () {
|
|
|
5750
5817
|
mutantRun: (options) => client.mutantRun({ options }).pipe(Effect$1.mapError(toRunnerFailure(runnerName, "mutantRun")))
|
|
5751
5818
|
});
|
|
5752
5819
|
});
|
|
5820
|
+
const TestRunners = Blueprint.make()(TypeId$2).steps({
|
|
5821
|
+
steps: {},
|
|
5822
|
+
targets: { scoped: scopedOf }
|
|
5823
|
+
});
|
|
5824
|
+
const makeChildProcessTestRunner = (params) => TestRunners.of(params).scoped;
|
|
5753
5825
|
const commandRunnerEffect = (context) => ChildProcessSpawner.ChildProcessSpawner.pipe(Effect$1.map((spawner) => commandRunner(context, spawner).pipe(withTimeout, withRetry)));
|
|
5754
|
-
const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option$1.some(commandRunnerEffect(context))), Match.
|
|
5755
|
-
testFiles: context.testFiles,
|
|
5756
|
-
sandboxWorkingDirectory: context.sandboxWorkingDirectory
|
|
5757
|
-
}))), Match.orElse(() => Option$1.none()));
|
|
5826
|
+
const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option$1.some(commandRunnerEffect(context))), Match.orElse(() => Option$1.none()));
|
|
5758
5827
|
const buildTestRunner = dual(2, (context, childProcessRunner) => Option$1.match(inProcessRunner(context), {
|
|
5759
5828
|
onSome: (inProcess) => inProcess,
|
|
5760
5829
|
onNone: () => Effect$1.gen(function* () {
|
|
@@ -5911,9 +5980,9 @@ const resolveConfiguredPlugin = Workflow.make({
|
|
|
5911
5980
|
decide: decide$4
|
|
5912
5981
|
});
|
|
5913
5982
|
//#endregion
|
|
5914
|
-
//#region src/run/dry-run.
|
|
5915
|
-
const sandboxPathsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) =>
|
|
5916
|
-
const configuredPluginOf$1 = (configured) => Match.value(configured).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
|
|
5983
|
+
//#region src/run/dry-run.parts.ts
|
|
5984
|
+
const sandboxPathsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => sandboxFileFor(sandbox, fileName)));
|
|
5985
|
+
const configuredPluginOf$1 = (configured) => Match.value(testRunnerConfigOf(configured)).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
|
|
5917
5986
|
const workerSpawnOf$1 = (stage, loaded, kind, configured) => Effect$1.mapError(Effect$1.fromResult(resolveConfiguredPlugin(WorkerSpawnCommand.make({
|
|
5918
5987
|
sources: loaded.pluginSources,
|
|
5919
5988
|
kind,
|
|
@@ -5927,7 +5996,11 @@ const optionalSandboxPathsOf = (command) => Boolean$1.match(command.options.test
|
|
|
5927
5996
|
onTrue: () => Result.succeed(void 0),
|
|
5928
5997
|
onFalse: () => sandboxPathsOf(command.sandbox, command.project.testFiles)
|
|
5929
5998
|
});
|
|
5930
|
-
const
|
|
5999
|
+
const mutatedFileNamesOf = (command) => {
|
|
6000
|
+
const mutated = MutableHashSet.fromIterable(command.mutants.map((mutant) => mutant.fileName));
|
|
6001
|
+
return [...MutableHashMap.keys(command.project.filesToMutate)].filter((name) => MutableHashSet.has(mutated, name));
|
|
6002
|
+
};
|
|
6003
|
+
const buildDryRunFiles = (command) => Result.flatMap(sandboxPathsOf(command.sandbox, mutatedFileNamesOf(command)), (files) => Result.map(optionalSandboxPathsOf(command), (testFiles) => ({
|
|
5931
6004
|
files,
|
|
5932
6005
|
testFiles
|
|
5933
6006
|
})));
|
|
@@ -5936,11 +6009,16 @@ const resolveDryRunFiles = (command) => Effect$1.fromResult(buildDryRunFiles(com
|
|
|
5936
6009
|
reason: "Failed to resolve sandbox file",
|
|
5937
6010
|
cause
|
|
5938
6011
|
})));
|
|
6012
|
+
const failedTestSummariesOf = (tests) => tests.filter((test) => test.status === "failed").map((test) => FailedTestSummary.make({
|
|
6013
|
+
name: test.name,
|
|
6014
|
+
failureMessage: test.failureMessage
|
|
6015
|
+
}));
|
|
5939
6016
|
const commandEncodedComplete = (complete, allowEmpty) => ({
|
|
5940
6017
|
_tag: "DryRunCommand",
|
|
5941
6018
|
status: "Complete",
|
|
5942
6019
|
testCount: complete.tests.length,
|
|
5943
6020
|
failedTestCount: complete.tests.filter((test) => test.status === "failed").length,
|
|
6021
|
+
failedTests: failedTestSummariesOf(complete.tests),
|
|
5944
6022
|
allowEmpty
|
|
5945
6023
|
});
|
|
5946
6024
|
const commandEncodedFailed = (failed, allowEmpty) => ({
|
|
@@ -5948,6 +6026,7 @@ const commandEncodedFailed = (failed, allowEmpty) => ({
|
|
|
5948
6026
|
status: "Error",
|
|
5949
6027
|
testCount: 0,
|
|
5950
6028
|
failedTestCount: 0,
|
|
6029
|
+
failedTests: [],
|
|
5951
6030
|
allowEmpty,
|
|
5952
6031
|
errorMessage: failed.errorMessage
|
|
5953
6032
|
});
|
|
@@ -5956,6 +6035,7 @@ const commandEncodedTimedOut = (timedOut, allowEmpty) => ({
|
|
|
5956
6035
|
status: "Timeout",
|
|
5957
6036
|
testCount: 0,
|
|
5958
6037
|
failedTestCount: 0,
|
|
6038
|
+
failedTests: [],
|
|
5959
6039
|
allowEmpty,
|
|
5960
6040
|
...Option$1.match(Option$1.fromNullishOr(timedOut.reason), {
|
|
5961
6041
|
onNone: () => ({}),
|
|
@@ -5987,7 +6067,7 @@ const totalTestTime = (tests) => tests.reduce((total, test) => total + test.time
|
|
|
5987
6067
|
const overheadMillisOf = (grossMillis, tests) => Math.max(0, grossMillis - totalTestTime(tests));
|
|
5988
6068
|
const withOriginalFileName = (test, prev) => Match.value(test.fileName).pipe(Match.when(Predicate$1.isString, (fileName) => ({
|
|
5989
6069
|
...test,
|
|
5990
|
-
fileName: prev.sandbox
|
|
6070
|
+
fileName: originalFileFor(prev.sandbox, fileName)
|
|
5991
6071
|
})), Match.orElse(() => test));
|
|
5992
6072
|
const withOriginalFileNames = (tests, prev) => tests.map((test) => withOriginalFileName(test, prev));
|
|
5993
6073
|
const ZERO = 0;
|
|
@@ -6110,20 +6190,32 @@ const writeDryRunPassed = (raw) => withPhaseSpan("dryRun", {}, () => Effect$1.ge
|
|
|
6110
6190
|
yield* phaseEntered("dry-run");
|
|
6111
6191
|
return yield* completeDryRunPassed(raw);
|
|
6112
6192
|
}));
|
|
6113
|
-
const
|
|
6193
|
+
const FAILED_TESTS_REASON = "There were failed tests in the initial test run.";
|
|
6194
|
+
const failedTestsDetail = (failedTests) => failedTests.map((test) => ` ${test.name}${test.failureMessage.length > 0 ? `: ${test.failureMessage}` : ""}`).join("\n");
|
|
6195
|
+
const reasonWithFailedTests = (detail) => detail.length > 0 ? `${FAILED_TESTS_REASON}\n${detail}` : FAILED_TESTS_REASON;
|
|
6196
|
+
const writeDryRunFailed = ({ testCount, failedTestCount, failedTests }) => withPhaseSpan("dryRun", {}, () => Effect$1.gen(function* () {
|
|
6114
6197
|
yield* phaseEntered("dry-run");
|
|
6198
|
+
const detail = failedTestsDetail(failedTests);
|
|
6199
|
+
yield* Effect$1.logError(`Initial test run failed. ${failedTestCount} of ${testCount} test(s) failed:\n${detail}`);
|
|
6115
6200
|
return yield* StageError.make({
|
|
6116
6201
|
stage: "dryRun",
|
|
6117
|
-
reason:
|
|
6202
|
+
reason: reasonWithFailedTests(detail),
|
|
6118
6203
|
cause: DryRunFailed.make({
|
|
6119
6204
|
testCount,
|
|
6120
|
-
failedTestCount
|
|
6205
|
+
failedTestCount,
|
|
6206
|
+
failedTests
|
|
6121
6207
|
})
|
|
6122
6208
|
});
|
|
6123
6209
|
}));
|
|
6210
|
+
//#endregion
|
|
6211
|
+
//#region src/run/dry-run.cell.ts
|
|
6124
6212
|
const dryRunCell = Sandwich.named("stryker.dry_run")(readDryRun).decide(dryRun).write({
|
|
6125
6213
|
DryRunPassed: (_decision, raw) => writeDryRunPassed(raw),
|
|
6126
|
-
DryRunFailed: ({ testCount, failedTestCount },
|
|
6214
|
+
DryRunFailed: ({ testCount, failedTestCount, failedTests }, _raw) => writeDryRunFailed({
|
|
6215
|
+
testCount,
|
|
6216
|
+
failedTestCount,
|
|
6217
|
+
failedTests
|
|
6218
|
+
}),
|
|
6127
6219
|
DryRunError: ({ stage, reason }) => Effect$1.fail(StageError.make({
|
|
6128
6220
|
stage,
|
|
6129
6221
|
reason,
|
|
@@ -6139,14 +6231,11 @@ const dryRunCell = Sandwich.named("stryker.dry_run")(readDryRun).decide(dryRun).
|
|
|
6139
6231
|
});
|
|
6140
6232
|
//#endregion
|
|
6141
6233
|
//#region src/plan-instrumentation.workflow.ts
|
|
6142
|
-
|
|
6143
|
-
stage: S.Literal("instrument"),
|
|
6144
|
-
reason: S.String
|
|
6145
|
-
}) {};
|
|
6234
|
+
const Count = S.Int.check(S.isGreaterThanOrEqualTo(0));
|
|
6146
6235
|
var InstrumentCommand = class extends S.TaggedClass()("InstrumentCommand", {
|
|
6147
|
-
fileCount:
|
|
6236
|
+
fileCount: Count,
|
|
6148
6237
|
inPlace: S.Boolean,
|
|
6149
|
-
pluginCount:
|
|
6238
|
+
pluginCount: Count
|
|
6150
6239
|
}) {
|
|
6151
6240
|
static [Workflow.InstrumentationBrand] = {
|
|
6152
6241
|
fileCount: "stryker.instrument.file_count",
|
|
@@ -6157,32 +6246,28 @@ const InstrumentDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/Instrum
|
|
|
6157
6246
|
var InPlaceInstrument = class extends S.TaggedClass()("InPlaceInstrument", {
|
|
6158
6247
|
workingDirectoryHint: S.String,
|
|
6159
6248
|
backupDirectoryHint: S.String,
|
|
6160
|
-
fileCount:
|
|
6249
|
+
fileCount: Count
|
|
6161
6250
|
}) {
|
|
6162
6251
|
[InstrumentDecisionTypeId] = InstrumentDecisionTypeId;
|
|
6163
6252
|
};
|
|
6164
6253
|
var EphemeralInstrument = class extends S.TaggedClass()("EphemeralInstrument", {
|
|
6165
6254
|
workingDirectoryHint: S.String,
|
|
6166
|
-
fileCount:
|
|
6255
|
+
fileCount: Count
|
|
6167
6256
|
}) {
|
|
6168
6257
|
[InstrumentDecisionTypeId] = InstrumentDecisionTypeId;
|
|
6169
6258
|
};
|
|
6170
|
-
const
|
|
6171
|
-
const decide$3 = (command) => Match.value(commandShape(command)).pipe(Match.when("empty", () => Result.fail(InstrumentError.make({
|
|
6172
|
-
stage: "instrument",
|
|
6173
|
-
reason: "No files to instrument."
|
|
6174
|
-
}))), Match.when("inPlace", () => Result.succeed(InPlaceInstrument.make({
|
|
6259
|
+
const decide$3 = (command) => Match.value(command.inPlace).pipe(Match.when(true, () => Result.succeed(InPlaceInstrument.make({
|
|
6175
6260
|
workingDirectoryHint: "inPlace",
|
|
6176
6261
|
backupDirectoryHint: "backup",
|
|
6177
6262
|
fileCount: command.fileCount
|
|
6178
|
-
}))), Match.when(
|
|
6263
|
+
}))), Match.when(false, () => Result.succeed(EphemeralInstrument.make({
|
|
6179
6264
|
workingDirectoryHint: "temp",
|
|
6180
6265
|
fileCount: command.fileCount
|
|
6181
6266
|
}))), Match.exhaustive);
|
|
6182
6267
|
const planInstrumentation = Workflow.make({
|
|
6183
6268
|
command: InstrumentCommand,
|
|
6184
6269
|
decision: S.Union([InPlaceInstrument, EphemeralInstrument]),
|
|
6185
|
-
error:
|
|
6270
|
+
error: S.Never,
|
|
6186
6271
|
decide: decide$3
|
|
6187
6272
|
});
|
|
6188
6273
|
//#endregion
|
|
@@ -6406,37 +6491,6 @@ function buildErrorMessage({ type, sourceText, position }) {
|
|
|
6406
6491
|
return `Cannot parse JSONC: unexpected token "${token}" in JSONC at position ${position}`;
|
|
6407
6492
|
}
|
|
6408
6493
|
//#endregion
|
|
6409
|
-
//#region src/Sandbox.handle.ts
|
|
6410
|
-
const TypeId$1 = Symbol.for("@systemfsoftware/stryker-js/SandboxHandle");
|
|
6411
|
-
const sandboxFileNameOf = (fileMap, fileName) => Match.value(fileMap.get(fileName)).pipe(Match.when(Predicate.isString, (sandboxFileName) => Result.succeed(sandboxFileName)), Match.orElse(() => Result.fail(StrykerError.make({ message: `Cannot find sandbox file for ${fileName}` }))));
|
|
6412
|
-
const withoutLeadingSeparator = (suffix) => Boolean.match(suffix.startsWith("/"), {
|
|
6413
|
-
onTrue: () => suffix.slice(1),
|
|
6414
|
-
onFalse: () => suffix
|
|
6415
|
-
});
|
|
6416
|
-
const relativeToBase = (resolvedSandbox, resolvedWorking, base, pathService) => {
|
|
6417
|
-
const trimmed = withoutLeadingSeparator(resolvedSandbox.slice(resolvedWorking.length));
|
|
6418
|
-
return Boolean.match(trimmed.length === 0, {
|
|
6419
|
-
onTrue: () => base,
|
|
6420
|
-
onFalse: () => pathService.join(base, trimmed)
|
|
6421
|
-
});
|
|
6422
|
-
};
|
|
6423
|
-
const originalFileNameOf = (sandboxFileName, workingDirectory, base, pathService) => {
|
|
6424
|
-
const resolvedSandbox = pathService.resolve(sandboxFileName);
|
|
6425
|
-
const resolvedWorking = pathService.resolve(workingDirectory);
|
|
6426
|
-
return Boolean.match(resolvedSandbox.startsWith(resolvedWorking), {
|
|
6427
|
-
onTrue: () => relativeToBase(resolvedSandbox, resolvedWorking, base, pathService),
|
|
6428
|
-
onFalse: () => resolvedSandbox.replace(resolvedWorking, base)
|
|
6429
|
-
});
|
|
6430
|
-
};
|
|
6431
|
-
const make$1 = (options) => {
|
|
6432
|
-
const handle = {
|
|
6433
|
-
workingDirectory: options.workingDirectory,
|
|
6434
|
-
sandboxFileFor: (fileName) => sandboxFileNameOf(options.fileMap, fileName),
|
|
6435
|
-
originalFileFor: (sandboxFileName) => originalFileNameOf(sandboxFileName, options.workingDirectory, options.basePath, options.pathService)
|
|
6436
|
-
};
|
|
6437
|
-
return Object.assign(handle, { [TypeId$1]: TypeId$1 });
|
|
6438
|
-
};
|
|
6439
|
-
//#endregion
|
|
6440
6494
|
//#region src/Sandbox.schema.ts
|
|
6441
6495
|
/**
|
|
6442
6496
|
* Sandbox.schema — declarations for the Sandbox capability.
|
|
@@ -6463,7 +6517,7 @@ const TsConfigSchema = Schema.StructWithRest(Schema.Struct({
|
|
|
6463
6517
|
/** A tsconfig `extends` entry list: the array form of `extends`. */
|
|
6464
6518
|
const ExtendsArraySchema = Schema.Array(Schema.String);
|
|
6465
6519
|
//#endregion
|
|
6466
|
-
//#region src/Sandbox.
|
|
6520
|
+
//#region src/Sandbox.blueprint.ts
|
|
6467
6521
|
const combinePreprocessors = (preprocessors) => (project) => Effect$1.forEach(preprocessors, (pre) => pre(project), { discard: true });
|
|
6468
6522
|
const mergeUpdatedFile = (project, updated) => {
|
|
6469
6523
|
MutableHashMap.set(project.files, updated.name, updated);
|
|
@@ -6723,13 +6777,13 @@ const symlinkNodeModules = (options, workingDirectory, basePath, pathService) =>
|
|
|
6723
6777
|
onFalse: () => Effect$1.void
|
|
6724
6778
|
});
|
|
6725
6779
|
});
|
|
6726
|
-
const acquireSandbox = (
|
|
6727
|
-
const { options, project, workingDirectory, backupDirectory, basePath } =
|
|
6780
|
+
const acquireSandbox = (spec) => Effect$1.gen(function* () {
|
|
6781
|
+
const { options, project, workingDirectory, backupDirectory, basePath } = spec;
|
|
6728
6782
|
yield* Scope.Scope;
|
|
6729
6783
|
const pathService = yield* Path.Path;
|
|
6730
6784
|
yield* announceSandbox(options, workingDirectory, backupDirectory, basePath, pathService);
|
|
6731
6785
|
yield* Effect$1.when(restoreOriginalFiles(workingDirectory, backupDirectory, basePath), Effect$1.succeed(hasBackupToRestore(options, backupDirectory)));
|
|
6732
|
-
yield* combinePreprocessors([createPreprocessor(options, basePath,
|
|
6786
|
+
yield* combinePreprocessors([createPreprocessor(options, basePath, spec.formatRegistry), ...spec.preprocessors])(project).pipe(Effect$1.mapError((cause) => StrykerError.make({
|
|
6733
6787
|
message: "Sandbox preprocessor failed",
|
|
6734
6788
|
cause
|
|
6735
6789
|
})));
|
|
@@ -6754,31 +6808,22 @@ const acquireSandbox = (state) => Effect$1.gen(function* () {
|
|
|
6754
6808
|
pathService
|
|
6755
6809
|
});
|
|
6756
6810
|
});
|
|
6757
|
-
const TypeId = Symbol.for("
|
|
6758
|
-
const
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
return acquireSandbox(state);
|
|
6771
|
-
},
|
|
6772
|
-
layer(service) {
|
|
6773
|
-
return Layer.effect(service)(acquireSandbox(state));
|
|
6774
|
-
}
|
|
6775
|
-
};
|
|
6776
|
-
};
|
|
6777
|
-
const make = (spec) => makeProto({
|
|
6778
|
-
spec,
|
|
6811
|
+
const TypeId$1 = Symbol.for("~systemfsoftware/stryker-js/Sandbox");
|
|
6812
|
+
const Sandboxes = Blueprint.make()(TypeId$1).steps({
|
|
6813
|
+
steps: { withPreprocessor: (spec, preprocessor) => ({
|
|
6814
|
+
...spec,
|
|
6815
|
+
preprocessors: [...spec.preprocessors, preprocessor]
|
|
6816
|
+
}) },
|
|
6817
|
+
targets: {
|
|
6818
|
+
scoped: (spec) => acquireSandbox(spec),
|
|
6819
|
+
layer: (spec) => (service) => Layer.effect(service)(acquireSandbox(spec))
|
|
6820
|
+
}
|
|
6821
|
+
});
|
|
6822
|
+
const make = (spec) => Sandboxes.of({
|
|
6823
|
+
...spec,
|
|
6779
6824
|
preprocessors: []
|
|
6780
6825
|
});
|
|
6781
|
-
|
|
6826
|
+
Sandboxes.operations.withPreprocessor;
|
|
6782
6827
|
const makeSandbox = (input) => make(input).scoped;
|
|
6783
6828
|
//#endregion
|
|
6784
6829
|
//#region src/run/explain-file-skip.workflow.ts
|
|
@@ -6847,13 +6892,13 @@ const explainFileSkip = Workflow.make({
|
|
|
6847
6892
|
decide: (command) => Match.value(skipKnownOrUnknownOf(explainedOf(command))).pipe(Match.tag("SkipKnownExplained", (known) => Result.succeed(known)), Match.tag("SkipUnknownExplained", (unknown) => Result.succeed(unknown)), Match.exhaustive)
|
|
6848
6893
|
});
|
|
6849
6894
|
//#endregion
|
|
6850
|
-
//#region src/run/instrument.
|
|
6851
|
-
const offerSkipsIfAny = (
|
|
6895
|
+
//#region src/run/instrument.parts.ts
|
|
6896
|
+
const offerSkipsIfAny = (input) => Boolean$1.match(input.skipped.length === 0, {
|
|
6852
6897
|
onTrue: () => Effect$1.void,
|
|
6853
6898
|
onFalse: () => Effect$1.gen(function* () {
|
|
6854
|
-
const files = skipped.map((skip) => Result.match(explainFileSkip(ExplainFileSkipCommand.make({
|
|
6899
|
+
const files = input.skipped.map((skip) => Result.match(explainFileSkip(ExplainFileSkipCommand.make({
|
|
6855
6900
|
extension: skip.extension,
|
|
6856
|
-
claimants: [...claimants]
|
|
6901
|
+
claimants: [...input.claimants]
|
|
6857
6902
|
})), {
|
|
6858
6903
|
onFailure: absurd,
|
|
6859
6904
|
onSuccess: (explained) => ({
|
|
@@ -6866,11 +6911,40 @@ const offerSkipsIfAny = (skipped, claimants) => Boolean$1.match(skipped.length =
|
|
|
6866
6911
|
yield* Queue.offer(queue, SkippedReported.make({ files }));
|
|
6867
6912
|
})
|
|
6868
6913
|
});
|
|
6914
|
+
const sandboxDirectoriesOf = (input) => Boolean$1.match(input.command.options.inPlace, {
|
|
6915
|
+
onTrue: () => ({
|
|
6916
|
+
workingDirectory: input.basePath,
|
|
6917
|
+
backupDirectory: input.command.temporaryDirectoryPath
|
|
6918
|
+
}),
|
|
6919
|
+
onFalse: () => ({
|
|
6920
|
+
workingDirectory: input.command.temporaryDirectoryPath,
|
|
6921
|
+
backupDirectory: ""
|
|
6922
|
+
})
|
|
6923
|
+
});
|
|
6924
|
+
const mergeInstrumentedFile = (input) => {
|
|
6925
|
+
const files = MutableHashMap.fromIterable(input.project.files);
|
|
6926
|
+
MutableHashMap.set(files, input.file.name, input.file);
|
|
6927
|
+
const filesToMutate = MutableHashMap.fromIterable(input.project.filesToMutate);
|
|
6928
|
+
Boolean$1.match(input.file.mutate !== false, {
|
|
6929
|
+
onTrue: () => MutableHashMap.set(filesToMutate, input.file.name, input.file),
|
|
6930
|
+
onFalse: () => MutableHashMap.remove(filesToMutate, input.file.name)
|
|
6931
|
+
});
|
|
6932
|
+
return {
|
|
6933
|
+
...input.project,
|
|
6934
|
+
files,
|
|
6935
|
+
filesToMutate
|
|
6936
|
+
};
|
|
6937
|
+
};
|
|
6938
|
+
//#endregion
|
|
6939
|
+
//#region src/run/instrument.cell.ts
|
|
6869
6940
|
const enteringInstrumentPhase = (raw, body) => withPhaseSpan("instrument", { fileCount: raw.filesToMutate.length }, () => Effect$1.gen(function* () {
|
|
6870
6941
|
yield* phaseEntered("instrument");
|
|
6871
6942
|
return yield* body;
|
|
6872
6943
|
}));
|
|
6873
|
-
const writeInstrument = (raw) => enteringInstrumentPhase(raw, Effect$1.as(offerSkipsIfAny(
|
|
6944
|
+
const writeInstrument = (raw) => enteringInstrumentPhase(raw, Effect$1.as(offerSkipsIfAny({
|
|
6945
|
+
skipped: raw.instrumentResult.skipped,
|
|
6946
|
+
claimants: raw.prev.frameworkClaimants
|
|
6947
|
+
}), {
|
|
6874
6948
|
...raw.prev,
|
|
6875
6949
|
project: raw.instrumentedProject,
|
|
6876
6950
|
mutants: raw.instrumentResult.mutants,
|
|
@@ -6880,37 +6954,13 @@ const writeInstrument = (raw) => enteringInstrumentPhase(raw, Effect$1.as(offerS
|
|
|
6880
6954
|
checkers: raw.concurrency.checkers
|
|
6881
6955
|
}
|
|
6882
6956
|
}));
|
|
6883
|
-
const
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
backupDirectory: command.temporaryDirectoryPath
|
|
6887
|
-
}),
|
|
6888
|
-
onFalse: () => ({
|
|
6889
|
-
workingDirectory: command.temporaryDirectoryPath,
|
|
6890
|
-
backupDirectory: ""
|
|
6891
|
-
})
|
|
6892
|
-
});
|
|
6893
|
-
const mergeInstrumentedFile = (project, file) => {
|
|
6894
|
-
const files = MutableHashMap.fromIterable(project.files);
|
|
6895
|
-
MutableHashMap.set(files, file.name, file);
|
|
6896
|
-
const filesToMutate = MutableHashMap.fromIterable(project.filesToMutate);
|
|
6897
|
-
Boolean$1.match(file.mutate !== false, {
|
|
6898
|
-
onTrue: () => MutableHashMap.set(filesToMutate, file.name, file),
|
|
6899
|
-
onFalse: () => MutableHashMap.remove(filesToMutate, file.name)
|
|
6900
|
-
});
|
|
6901
|
-
return {
|
|
6902
|
-
...project,
|
|
6903
|
-
files,
|
|
6904
|
-
filesToMutate
|
|
6905
|
-
};
|
|
6906
|
-
};
|
|
6907
|
-
const withInstrumentedFiles = (project, instrumented) => Arr.reduce([...instrumented], project, (current, { name, content }) => Option$1.match(MutableHashMap.get(current.files, name), {
|
|
6908
|
-
onNone: () => current,
|
|
6909
|
-
onSome: (existing) => mergeInstrumentedFile(current, {
|
|
6957
|
+
const withInstrumentedFiles = (project, instrumented) => Arr.reduce([...instrumented], project, (current, { name, content }) => Option$1.getOrElse(Option$1.map(MutableHashMap.get(current.files, name), (existing) => mergeInstrumentedFile({
|
|
6958
|
+
project: current,
|
|
6959
|
+
file: {
|
|
6910
6960
|
...existing,
|
|
6911
6961
|
content
|
|
6912
|
-
}
|
|
6913
|
-
}));
|
|
6962
|
+
}
|
|
6963
|
+
})), () => current));
|
|
6914
6964
|
const instrumentCell = Sandwich.named("stryker.instrument")((command) => Effect$1.gen(function* () {
|
|
6915
6965
|
yield* Scope.Scope;
|
|
6916
6966
|
const env = yield* RunEnvironment;
|
|
@@ -6934,7 +6984,10 @@ const instrumentCell = Sandwich.named("stryker.instrument")((command) => Effect$
|
|
|
6934
6984
|
cause
|
|
6935
6985
|
})));
|
|
6936
6986
|
const instrumentedProject = withInstrumentedFiles(command.project, instrumentResult.files);
|
|
6937
|
-
const directories = sandboxDirectoriesOf(
|
|
6987
|
+
const directories = sandboxDirectoriesOf({
|
|
6988
|
+
command,
|
|
6989
|
+
basePath: env.basePath
|
|
6990
|
+
});
|
|
6938
6991
|
const sandbox = yield* makeSandbox({
|
|
6939
6992
|
options: command.options,
|
|
6940
6993
|
project: instrumentedProject,
|
|
@@ -6962,14 +7015,6 @@ const instrumentCell = Sandwich.named("stryker.instrument")((command) => Effect$
|
|
|
6962
7015
|
})).decide(planInstrumentation).write({
|
|
6963
7016
|
InPlaceInstrument: (_decision, raw) => writeInstrument(raw),
|
|
6964
7017
|
EphemeralInstrument: (_decision, raw) => writeInstrument(raw),
|
|
6965
|
-
InstrumentError: ({ stage, reason }, raw) => enteringInstrumentPhase(raw, Effect$1.fail(StageError.make({
|
|
6966
|
-
stage,
|
|
6967
|
-
reason,
|
|
6968
|
-
cause: InstrumentError.make({
|
|
6969
|
-
stage,
|
|
6970
|
-
reason
|
|
6971
|
-
})
|
|
6972
|
-
}))),
|
|
6973
7018
|
CommandRejected: ({ issue }) => Effect$1.fail(StageError.make({
|
|
6974
7019
|
stage: "instrument",
|
|
6975
7020
|
reason: issue
|
|
@@ -6994,7 +7039,11 @@ var MutationTestCommand = class extends S.TaggedClass()("MutationTestCommand", {
|
|
|
6994
7039
|
var MutationTestError = class extends S.TaggedError()("MutationTestError", {
|
|
6995
7040
|
stage: S.Literal("mutationTest"),
|
|
6996
7041
|
reason: S.String
|
|
6997
|
-
}) {
|
|
7042
|
+
}) {
|
|
7043
|
+
get message() {
|
|
7044
|
+
return this.reason;
|
|
7045
|
+
}
|
|
7046
|
+
};
|
|
6998
7047
|
const MutationTestDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/MutationTestDecision");
|
|
6999
7048
|
var MutationTestProceed = class extends S.TaggedClass()("MutationTestProceed", {}) {
|
|
7000
7049
|
[MutationTestDecisionTypeId] = MutationTestDecisionTypeId;
|
|
@@ -7028,13 +7077,18 @@ const admitMutationTest = Workflow.make({
|
|
|
7028
7077
|
decide: decide$2
|
|
7029
7078
|
});
|
|
7030
7079
|
//#endregion
|
|
7031
|
-
//#region src/Checker/Checker.
|
|
7080
|
+
//#region src/Checker/Checker.blueprint.ts
|
|
7081
|
+
const TypeId = Symbol.for("~systemfsoftware/stryker-js/CheckerBlueprint");
|
|
7032
7082
|
const checkerProcessCrashes = Metric.counter("stryker.checker.process_crashes", {
|
|
7033
7083
|
description: "Checker worker processes that never became usable",
|
|
7034
7084
|
incremental: true
|
|
7035
7085
|
});
|
|
7036
7086
|
const TEMP_DIR_PREFIX = "stryker-checker-";
|
|
7037
7087
|
const nodeArgsOf = (options) => Match.value(options.checkers[0]?.nodeArgs).pipe(Match.when(Match.undefined, () => options.checkerNodeArgs), Match.orElse((args) => args));
|
|
7088
|
+
const serviceOf = (handle) => ({
|
|
7089
|
+
check: (checkerName, mutants) => check(handle, checkerName, mutants),
|
|
7090
|
+
group: (checkerName, mutants) => group(handle, checkerName, mutants)
|
|
7091
|
+
});
|
|
7038
7092
|
const acquire = (spec) => Effect$1.gen(function* () {
|
|
7039
7093
|
const client = yield* makeWorkerClient({
|
|
7040
7094
|
rpcs: Plugin_exports.CheckerRpcs,
|
|
@@ -7044,9 +7098,13 @@ const acquire = (spec) => Effect$1.gen(function* () {
|
|
|
7044
7098
|
execArgv: [...nodeArgsOf(spec.options)],
|
|
7045
7099
|
tempDirPrefix: TEMP_DIR_PREFIX
|
|
7046
7100
|
}).pipe(Effect$1.mapError((error) => Match.value(error).pipe(Match.tag("ChildProcessCrashedError", "OutOfMemoryError", (crash) => crash), Match.tag("WorkerBootTimeoutError", () => connectionCrashed(`Checker worker failed to start: its boot window closed before it accepted the RPC connection`)), Match.exhaustive)), Effect$1.tapError(() => Metric.update(checkerProcessCrashes, 1)));
|
|
7047
|
-
return makeCheckerHandle(client);
|
|
7101
|
+
return serviceOf(makeCheckerHandle(client));
|
|
7048
7102
|
});
|
|
7049
|
-
const
|
|
7103
|
+
const Checkers = Blueprint.make()(TypeId).steps({
|
|
7104
|
+
steps: {},
|
|
7105
|
+
targets: { scoped: acquire }
|
|
7106
|
+
});
|
|
7107
|
+
const scoped = (spec) => Checkers.of(spec).scoped;
|
|
7050
7108
|
//#endregion
|
|
7051
7109
|
//#region src/incremental-diff.workflow.ts
|
|
7052
7110
|
const REMEMBERED_STATUS = /* @__PURE__ */ new Set([
|
|
@@ -7351,7 +7409,7 @@ const planMutantTests = Workflow.make({
|
|
|
7351
7409
|
decide
|
|
7352
7410
|
});
|
|
7353
7411
|
//#endregion
|
|
7354
|
-
//#region src/run/mutation-test.
|
|
7412
|
+
//#region src/run/mutation-test.parts.ts
|
|
7355
7413
|
const relativeFileNameOf = (fileName, basePath) => RelativeNormalizedFileName.fromAbsolute(fileName, basePath).fileName;
|
|
7356
7414
|
const readCurrentRelativeFiles = (project, basePath) => Effect$1.gen(function* () {
|
|
7357
7415
|
const entries = yield* (yield* ProjectFiles).readAllOriginal(MutableHashMap.values(project.files));
|
|
@@ -7368,7 +7426,7 @@ const reportingInputOf = (prev, env, results) => ({
|
|
|
7368
7426
|
reporterStage: prev.reporterStage,
|
|
7369
7427
|
formatRegistry: prev.formatRegistry
|
|
7370
7428
|
});
|
|
7371
|
-
const sandboxFilePairsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => Result.map(
|
|
7429
|
+
const sandboxFilePairsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => Result.map(sandboxFileFor(sandbox, fileName), (sandboxFileName) => [fileName, sandboxFileName])));
|
|
7372
7430
|
const sandboxFilesOf = (sandbox, fileNames) => Effect$1.fromResult(sandboxFilePairsOf(sandbox, fileNames)).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
7373
7431
|
stage: "mutationTest",
|
|
7374
7432
|
reason: "Failed to resolve sandbox file",
|
|
@@ -7422,8 +7480,9 @@ const toReportedMutant = (mutant) => Object.assign(mutant, {
|
|
|
7422
7480
|
static: mutant.static
|
|
7423
7481
|
});
|
|
7424
7482
|
const CHECKER_ACQUIRE_RETRIES = 2;
|
|
7483
|
+
const TEST_RUNNER_POOL_IDLE_TIME_TO_LIVE = Duration.minutes(1);
|
|
7425
7484
|
const isCheckerCrash = (error) => Match.value(error).pipe(Match.tag("ChildProcessCrashedError", "OutOfMemoryError", () => true), Match.orElse(() => false));
|
|
7426
|
-
const configuredPluginOf = (configured) => Match.value(configured).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
|
|
7485
|
+
const configuredPluginOf = (configured) => Match.value(testRunnerConfigOf(configured)).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
|
|
7427
7486
|
const workerSpawnOf = (stage, loaded, kind, configured) => Effect$1.mapError(Effect$1.fromResult(resolveConfiguredPlugin(WorkerSpawnCommand.make({
|
|
7428
7487
|
sources: loaded.pluginSources,
|
|
7429
7488
|
kind,
|
|
@@ -7617,13 +7676,17 @@ const checkerBreachToStageError = (error) => Match.value(error).pipe(Match.tag("
|
|
|
7617
7676
|
cause: breach
|
|
7618
7677
|
})), Match.exhaustive);
|
|
7619
7678
|
const invalidateSlot = (pool, slot, error) => Effect$1.flatMap(Pool.invalidate(pool, slot), () => Effect$1.fail(error));
|
|
7620
|
-
const
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7679
|
+
const onCheckerSlot = (pool, checkerIndex, run) => Pool.use(pool, (slot) => Option$1.match(Option$1.fromUndefinedOr(slot[checkerIndex]), {
|
|
7680
|
+
onNone: () => Effect$1.die(/* @__PURE__ */ new Error(`checker slot has no entry at index ${checkerIndex}`)),
|
|
7681
|
+
onSome: ({ checker }) => run(checker).pipe(Effect$1.catchTags({
|
|
7682
|
+
OutOfMemoryError: (error) => invalidateSlot(pool, slot, error),
|
|
7683
|
+
ChildProcessCrashedError: (error) => invalidateSlot(pool, slot, error),
|
|
7684
|
+
CheckerFailed: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail),
|
|
7685
|
+
CheckerAnsweredUnrequested: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail),
|
|
7686
|
+
CheckerSkippedRequested: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail)
|
|
7687
|
+
}))
|
|
7626
7688
|
}));
|
|
7689
|
+
const checkGroupsConcurrently = (pool, checkerIndex, checkerName, currentPlans) => Effect$1.flatMap(onCheckerSlot(pool, checkerIndex, (checker) => groupPlans(checker, checkerName, currentPlans)), (groups) => Effect$1.map(Effect$1.forEach(groups, (group) => onCheckerSlot(pool, checkerIndex, (checker) => checkPlans(checker, checkerName, group)), { concurrency: "unbounded" }), (perGroup) => perGroup.flat()));
|
|
7627
7690
|
const isFailedCheck = (check) => check[1].status !== "passed";
|
|
7628
7691
|
const splitCheckedPlans = (checked, reporting) => {
|
|
7629
7692
|
const failures = checked.filter(isFailedCheck);
|
|
@@ -7633,18 +7696,15 @@ const splitCheckedPlans = (checked, reporting) => {
|
|
|
7633
7696
|
results
|
|
7634
7697
|
}));
|
|
7635
7698
|
};
|
|
7636
|
-
const stepOneChecker = (pool,
|
|
7699
|
+
const stepOneChecker = (pool, checkerIndex, checkerName, currentPlans, reporting) => checkGroupsConcurrently(pool, checkerIndex, checkerName, currentPlans).pipe(Effect$1.flatMap((checked) => splitCheckedPlans(checked, reporting)));
|
|
7637
7700
|
const emptyRunResults = [];
|
|
7638
|
-
const runConfiguredCheckers = (pool, plans, reporting) => Effect$1.
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
checkerResults: [...acc.checkerResults, ...split.results]
|
|
7646
|
-
})));
|
|
7647
|
-
}));
|
|
7701
|
+
const runConfiguredCheckers = (pool, plans, reporting) => Effect$1.flatMap(Pool.use(pool, (slot) => Effect$1.succeed(slot.map(({ checkerName }) => checkerName))), (checkerNames) => Effect$1.reduce(checkerNames, () => ({
|
|
7702
|
+
passedPlans: plans,
|
|
7703
|
+
checkerResults: emptyRunResults
|
|
7704
|
+
}), (acc, checkerName, checkerIndex) => Effect$1.map(stepOneChecker(pool, checkerIndex, checkerName, acc.passedPlans, reporting), (split) => ({
|
|
7705
|
+
passedPlans: split.passed,
|
|
7706
|
+
checkerResults: [...acc.checkerResults, ...split.results]
|
|
7707
|
+
}))));
|
|
7648
7708
|
const checkPlansWithConfiguredCheckers = (checkerPool, plans, reporting) => Option$1.match(Option$1.fromNullishOr(checkerPool), {
|
|
7649
7709
|
onNone: () => Effect$1.succeed({
|
|
7650
7710
|
passedPlans: plans,
|
|
@@ -7652,6 +7712,14 @@ const checkPlansWithConfiguredCheckers = (checkerPool, plans, reporting) => Opti
|
|
|
7652
7712
|
}),
|
|
7653
7713
|
onSome: (pool) => runConfiguredCheckers(pool, plans, reporting)
|
|
7654
7714
|
});
|
|
7715
|
+
const checkerResourcesInOwnScope = (acquire) => Effect$1.gen(function* () {
|
|
7716
|
+
const checkerScope = yield* Scope.make();
|
|
7717
|
+
yield* Effect$1.addFinalizer(() => Scope.close(checkerScope, Exit.void));
|
|
7718
|
+
return {
|
|
7719
|
+
resources: yield* acquire.pipe(Scope.provide(checkerScope)),
|
|
7720
|
+
releaseInBackground: Scope.close(checkerScope, Exit.void).pipe(Effect$1.forkScoped({ uninterruptible: true }))
|
|
7721
|
+
};
|
|
7722
|
+
});
|
|
7655
7723
|
const isPlannable = (mutant) => Result.isSuccess(S.decodeResult(CheckerMutantFromMutant)(mutant));
|
|
7656
7724
|
const DROPPED_IDS_IN_WARNING = 5;
|
|
7657
7725
|
const configuredTestFilesOf = (run) => run.options.testFiles.length === 0 ? [] : run.project.testFiles;
|
|
@@ -7676,7 +7744,7 @@ const stopWallClock = (result) => Boolean$1.match(wallClockTimeoutStopsRun(resul
|
|
|
7676
7744
|
})),
|
|
7677
7745
|
onFalse: () => Effect$1.void
|
|
7678
7746
|
});
|
|
7679
|
-
const writeMutationTestNoTests =
|
|
7747
|
+
const writeMutationTestNoTests = Effect$1.gen(function* () {
|
|
7680
7748
|
const env = yield* RunEnvironment;
|
|
7681
7749
|
const now = yield* Clock.currentTimeMillis;
|
|
7682
7750
|
const elapsed = Duration.millis(now - env.runStartedAt);
|
|
@@ -7687,7 +7755,7 @@ const writeMutationTestNoTests = () => Effect$1.gen(function* () {
|
|
|
7687
7755
|
verdict: null
|
|
7688
7756
|
};
|
|
7689
7757
|
});
|
|
7690
|
-
const writeMutationTestDryRunOnly =
|
|
7758
|
+
const writeMutationTestDryRunOnly = Effect$1.gen(function* () {
|
|
7691
7759
|
yield* phaseEntered("mutation-test");
|
|
7692
7760
|
yield* Effect$1.logInfo("The dry-run has been completed successfully. No mutations have been executed.");
|
|
7693
7761
|
return {
|
|
@@ -7697,14 +7765,15 @@ const writeMutationTestDryRunOnly = () => Effect$1.gen(function* () {
|
|
|
7697
7765
|
});
|
|
7698
7766
|
const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
|
|
7699
7767
|
const prev = raw.prev;
|
|
7768
|
+
const testRunnerCapacity = prev.concurrency.testRunners + prev.concurrency.checkers;
|
|
7700
7769
|
const { dropped, plannable: plannableMutants } = partitionPlannable(prev.mutants);
|
|
7701
7770
|
yield* reportDroppedMutants(dropped);
|
|
7702
7771
|
yield* phaseEntered("mutation-test");
|
|
7703
7772
|
const idGenerator = yield* IdGenerator;
|
|
7704
7773
|
const env = yield* RunEnvironment;
|
|
7705
|
-
const
|
|
7774
|
+
const scopedCheckers = yield* checkerResourcesInOwnScope(makeCheckerPool(prev, env.basePath));
|
|
7706
7775
|
const testFiles = yield* Effect$1.map(sandboxFilesOf(prev.sandbox, configuredTestFilesOf(prev)), (pairs) => pairs.map(([, sandboxFileName]) => sandboxFileName));
|
|
7707
|
-
const testRunnerPool = yield* Pool.
|
|
7776
|
+
const testRunnerPool = yield* Pool.makeWithTTL({
|
|
7708
7777
|
acquire: buildTestRunner({
|
|
7709
7778
|
options: prev.options,
|
|
7710
7779
|
fileDescriptions: prev.project.fileDescriptions,
|
|
@@ -7722,7 +7791,9 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
|
|
|
7722
7791
|
idGenerator
|
|
7723
7792
|
})));
|
|
7724
7793
|
})),
|
|
7725
|
-
|
|
7794
|
+
min: prev.concurrency.testRunners,
|
|
7795
|
+
max: testRunnerCapacity,
|
|
7796
|
+
timeToLive: TEST_RUNNER_POOL_IDLE_TIME_TO_LIVE
|
|
7726
7797
|
});
|
|
7727
7798
|
const reporting = yield* MutationReporting;
|
|
7728
7799
|
const sandboxFileByName = Object.fromEntries(yield* sandboxFilesOf(prev.sandbox, [...MutableHashMap.keys(prev.project.filesToMutate)]));
|
|
@@ -7765,7 +7836,8 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
|
|
|
7765
7836
|
})).pipe(Effect$1.ignoreCause);
|
|
7766
7837
|
const progressQueue = yield* RunEvents;
|
|
7767
7838
|
yield* Queue.offer(progressQueue, PlanKnown.make({ total: allPlansForReporter.length + noCoverageResults.length }));
|
|
7768
|
-
const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(
|
|
7839
|
+
const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(scopedCheckers.resources, sortedPlans, reporting);
|
|
7840
|
+
const checkerRelease = yield* scopedCheckers.releaseInBackground;
|
|
7769
7841
|
const testRunnerStream = Stream.fromIterable(passedPlans);
|
|
7770
7842
|
const plannedTotal = sortedPlans.length + noCoverageResults.length + rememberedResults.length;
|
|
7771
7843
|
const completedRef = yield* Ref.make(0);
|
|
@@ -7866,7 +7938,7 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
|
|
|
7866
7938
|
yield* offerStreamTested(reported, finished, prepared);
|
|
7867
7939
|
yield* persist(reported);
|
|
7868
7940
|
return reported;
|
|
7869
|
-
})), { concurrency: Math.max(1,
|
|
7941
|
+
})), { concurrency: Math.max(1, testRunnerCapacity) }).pipe(Stream.runCollect, Effect$1.map((chunk) => [...chunk])));
|
|
7870
7942
|
const allResults = [
|
|
7871
7943
|
...rememberedResults,
|
|
7872
7944
|
...noCoverageResults,
|
|
@@ -7874,16 +7946,24 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
|
|
|
7874
7946
|
...runResults
|
|
7875
7947
|
];
|
|
7876
7948
|
const outcomeResult = yield* reporting.reportAll(reportingInputOf(prev, env, allResults));
|
|
7949
|
+
yield* Fiber.await(checkerRelease);
|
|
7877
7950
|
const doneNow = yield* Clock.currentTimeMillis;
|
|
7878
7951
|
const elapsed = Duration.millis(doneNow - env.runStartedAt);
|
|
7879
7952
|
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
7880
7953
|
return outcomeResult;
|
|
7881
7954
|
}).pipe(Effect$1.mapError((cause) => mapMutationTestCause(cause)));
|
|
7882
|
-
const writeMutationTestOutcome = (raw, outcome) => withPhaseSpan("mutationTest", {
|
|
7955
|
+
const writeMutationTestOutcome = ({ raw, outcome }) => withPhaseSpan("mutationTest", {
|
|
7883
7956
|
mutantCount: raw.prev.mutants.length,
|
|
7884
7957
|
skippedMutantCount: partitionPlannable(raw.prev.mutants).dropped.length,
|
|
7885
7958
|
testCount: raw.prev.dryRunResult.tests.length
|
|
7886
7959
|
}, () => outcome);
|
|
7960
|
+
const mapMutationTestCause = (cause) => Match.value({ cause }).pipe(Match.when({ cause: isStageError }, ({ cause }) => cause), Match.orElse(({ cause }) => StageError.make({
|
|
7961
|
+
stage: "mutationTest",
|
|
7962
|
+
reason: "Mutation testing failed",
|
|
7963
|
+
cause
|
|
7964
|
+
})));
|
|
7965
|
+
//#endregion
|
|
7966
|
+
//#region src/run/mutation-test.cell.ts
|
|
7887
7967
|
const mutationTestCell$1 = Sandwich.named("stryker.mutation_test")((command) => Effect$1.gen(function* () {
|
|
7888
7968
|
yield* Scope.Scope;
|
|
7889
7969
|
const prev = command;
|
|
@@ -7896,9 +7976,18 @@ const mutationTestCell$1 = Sandwich.named("stryker.mutation_test")((command) =>
|
|
|
7896
7976
|
prev
|
|
7897
7977
|
};
|
|
7898
7978
|
})).decide(admitMutationTest).write({
|
|
7899
|
-
MutationTestDryRunOnly: (_decision, raw) => writeMutationTestOutcome(
|
|
7900
|
-
|
|
7901
|
-
|
|
7979
|
+
MutationTestDryRunOnly: (_decision, raw) => writeMutationTestOutcome({
|
|
7980
|
+
raw,
|
|
7981
|
+
outcome: writeMutationTestDryRunOnly
|
|
7982
|
+
}),
|
|
7983
|
+
MutationTestNoTests: (_decision, raw) => writeMutationTestOutcome({
|
|
7984
|
+
raw,
|
|
7985
|
+
outcome: writeMutationTestNoTests
|
|
7986
|
+
}),
|
|
7987
|
+
MutationTestProceed: (_decision, raw) => writeMutationTestOutcome({
|
|
7988
|
+
raw,
|
|
7989
|
+
outcome: writeMutationTestProceed(raw)
|
|
7990
|
+
}),
|
|
7902
7991
|
MutationTestError: ({ stage, reason }) => Effect$1.fail(StageError.make({
|
|
7903
7992
|
stage,
|
|
7904
7993
|
reason,
|
|
@@ -7912,11 +8001,6 @@ const mutationTestCell$1 = Sandwich.named("stryker.mutation_test")((command) =>
|
|
|
7912
8001
|
reason: issue
|
|
7913
8002
|
}))
|
|
7914
8003
|
});
|
|
7915
|
-
const mapMutationTestCause = (cause) => Match.value({ cause }).pipe(Match.when({ cause: isStageError }, ({ cause }) => cause), Match.orElse(({ cause }) => StageError.make({
|
|
7916
|
-
stage: "mutationTest",
|
|
7917
|
-
reason: "Mutation testing failed",
|
|
7918
|
-
cause
|
|
7919
|
-
})));
|
|
7920
8004
|
//#endregion
|
|
7921
8005
|
//#region src/framework-claimant.service.ts
|
|
7922
8006
|
const dependencyNamesOf = (dependencies) => Object.keys(dependencies ?? {});
|
|
@@ -8342,7 +8426,7 @@ const pluginUrlsFromOptions = (options) => [
|
|
|
8342
8426
|
...options.plugins,
|
|
8343
8427
|
...options.appendPlugins,
|
|
8344
8428
|
...options.ignorers,
|
|
8345
|
-
...Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => [runner.plugin]), Match.orElse(() => [])),
|
|
8429
|
+
...Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => [runner.plugin]), Match.when(isVmRunner, () => [vmRunnerPluginUrl()]), Match.orElse(() => [])),
|
|
8346
8430
|
...options.checkers.map((checker) => checker.plugin)
|
|
8347
8431
|
];
|
|
8348
8432
|
//#endregion
|
|
@@ -8463,24 +8547,48 @@ const planPrepare = Workflow.make({
|
|
|
8463
8547
|
decide: (decoded) => Match.value(decoded.mode).pipe(Match.when("human", () => Result.succeed(HumanReporters.make({ reporters: decoded.reporters }))), Match.when("machine", () => Result.succeed(MachineReporters.make({ reporters: decoded.reporters }))), Match.exhaustive)
|
|
8464
8548
|
});
|
|
8465
8549
|
//#endregion
|
|
8550
|
+
//#region src/run/prepare.parts.ts
|
|
8551
|
+
const announceSummary = (input) => Match.value(input.env.resolvedMode.mode).pipe(Match.when("human", () => announceHumanSummary({
|
|
8552
|
+
allowConsoleColors: input.env.allowConsoleColors,
|
|
8553
|
+
summary: input.summary
|
|
8554
|
+
})), Match.orElse(() => Effect$1.logInfo(input.summary)));
|
|
8555
|
+
const announceHumanSummary = (input) => Boolean$1.match(input.allowConsoleColors, {
|
|
8556
|
+
onTrue: () => Console.log(`${AnsiCode.fields.green.literal}${input.summary}${AnsiCode.fields.reset.literal}`),
|
|
8557
|
+
onFalse: () => Console.log(input.summary)
|
|
8558
|
+
});
|
|
8559
|
+
const STREAM_REPORTER = "progress-stream";
|
|
8560
|
+
const HUMAN_REPORTER = "clear-text";
|
|
8561
|
+
const STDOUT_REPORTERS = {
|
|
8562
|
+
"clear-text": true,
|
|
8563
|
+
"progress": true
|
|
8564
|
+
};
|
|
8565
|
+
const asHumanReporter = (name) => {
|
|
8566
|
+
if (name === STREAM_REPORTER) return HUMAN_REPORTER;
|
|
8567
|
+
return name;
|
|
8568
|
+
};
|
|
8569
|
+
const selectReporters = dual(2, (configured, mode) => Match.value(mode).pipe(Match.when("human", () => [...new Set(configured.map(asHumanReporter))]), Match.when("machine", () => {
|
|
8570
|
+
const permitted = configured.filter((name) => STDOUT_REPORTERS[name] !== true);
|
|
8571
|
+
return Match.value(permitted.includes(STREAM_REPORTER)).pipe(Match.when(true, () => permitted), Match.when(false, () => [...permitted, STREAM_REPORTER]), Match.exhaustive);
|
|
8572
|
+
}), Match.exhaustive));
|
|
8573
|
+
const failOnEmptyProject = (fileCount) => Match.value(fileCount).pipe(Match.when(0, () => Effect$1.fail(StageError.make({
|
|
8574
|
+
stage: "prepare",
|
|
8575
|
+
reason: "No input files found.",
|
|
8576
|
+
cause: PrepareError.make({
|
|
8577
|
+
stage: "prepare",
|
|
8578
|
+
reason: "No input files found."
|
|
8579
|
+
})
|
|
8580
|
+
}))), Match.orElse(() => Effect$1.void));
|
|
8581
|
+
//#endregion
|
|
8466
8582
|
//#region src/run/prepare.cell.ts
|
|
8467
8583
|
const NO_PLUGIN_DESCRIPTORS = [];
|
|
8468
8584
|
const schemaPropertiesOf = (document) => Option$1.getOrElse(Option$1.fromNullishOr(document.properties), () => ({}));
|
|
8469
|
-
const buildMergedSchema = (core, contributions) =>
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
...
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
}), schemaPropertiesOf(core))
|
|
8477
|
-
})
|
|
8478
|
-
});
|
|
8479
|
-
const announceSummary = (env, summary) => Match.value(env.resolvedMode.mode).pipe(Match.when("human", () => announceHumanSummary(env.allowConsoleColors, summary)), Match.orElse(() => Effect$1.logInfo(summary)));
|
|
8480
|
-
const announceHumanSummary = (allowConsoleColors, summary) => Boolean$1.match(allowConsoleColors, {
|
|
8481
|
-
onTrue: () => Console.log(`${AnsiCode.fields.green.literal}${summary}${AnsiCode.fields.reset.literal}`),
|
|
8482
|
-
onFalse: () => Console.log(summary)
|
|
8483
|
-
});
|
|
8585
|
+
const buildMergedSchema = (core, contributions) => contributions.reduce((merged, contribution) => ({
|
|
8586
|
+
...merged,
|
|
8587
|
+
properties: {
|
|
8588
|
+
...schemaPropertiesOf(merged),
|
|
8589
|
+
...schemaPropertiesOf(contribution)
|
|
8590
|
+
}
|
|
8591
|
+
}), core);
|
|
8484
8592
|
const readPrepare = (command) => Effect$1.gen(function* () {
|
|
8485
8593
|
yield* Scope.Scope;
|
|
8486
8594
|
const env = yield* RunEnvironment;
|
|
@@ -8531,9 +8639,10 @@ const readPrepare = (command) => Effect$1.gen(function* () {
|
|
|
8531
8639
|
}])]);
|
|
8532
8640
|
const frameworkClaimants = yield* installedFrameworkClaimants(env.basePath);
|
|
8533
8641
|
return {
|
|
8642
|
+
now: yield* Clock.currentTimeMillis,
|
|
8534
8643
|
mode: env.resolvedMode.mode,
|
|
8535
8644
|
reporters: [...options.reporters],
|
|
8536
|
-
fileCount:
|
|
8645
|
+
fileCount: pipe(command.project.files, MutableHashMap.size),
|
|
8537
8646
|
availableReporters: [...HashMap.values(reporterChoicesByName)].map((choice) => choice.name),
|
|
8538
8647
|
env,
|
|
8539
8648
|
queue,
|
|
@@ -8548,22 +8657,17 @@ const readPrepare = (command) => Effect$1.gen(function* () {
|
|
|
8548
8657
|
};
|
|
8549
8658
|
});
|
|
8550
8659
|
const writePrepare = (reporters, raw) => withPhaseSpan("prepare", {}, (span) => Effect$1.gen(function* () {
|
|
8551
|
-
const mutateCount =
|
|
8552
|
-
yield* announceSummary(
|
|
8660
|
+
const mutateCount = pipe(raw.project.filesToMutate, MutableHashMap.size);
|
|
8661
|
+
yield* announceSummary({
|
|
8662
|
+
env: raw.env,
|
|
8663
|
+
summary: `Found ${mutateCount} of ${pipe(raw.project.files, MutableHashMap.size)} file(s) to be mutated.`
|
|
8664
|
+
});
|
|
8553
8665
|
yield* validateReporterNames(raw.options.reporters, [...HashMap.values(raw.reporterChoicesByName)].map((choice) => choice.name)).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
8554
8666
|
stage: "prepare",
|
|
8555
8667
|
reason: cause.message,
|
|
8556
8668
|
cause
|
|
8557
8669
|
})));
|
|
8558
|
-
|
|
8559
|
-
stage: "prepare",
|
|
8560
|
-
reason: "No input files found.",
|
|
8561
|
-
cause: PrepareError.make({
|
|
8562
|
-
stage: "prepare",
|
|
8563
|
-
reason: "No input files found."
|
|
8564
|
-
})
|
|
8565
|
-
}))), Match.orElse(() => Effect$1.void));
|
|
8566
|
-
yield* failOnEmptyProject(raw.project.files.pipe(MutableHashMap.size));
|
|
8670
|
+
yield* failOnEmptyProject(pipe(raw.project.files, MutableHashMap.size));
|
|
8567
8671
|
const temporaryDirectoryPath = yield* Effect$1.map(Layer.build(TemporaryDirectory.layer(raw.options)), (temporaryDirectory) => Context.get(temporaryDirectory, TemporaryDirectory).path).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
8568
8672
|
stage: "prepare",
|
|
8569
8673
|
reason: "Failed to create temporary directory",
|
|
@@ -8572,7 +8676,7 @@ const writePrepare = (reporters, raw) => withPhaseSpan("prepare", {}, (span) =>
|
|
|
8572
8676
|
const reporterInputs = yield* reporterInputsOf(reporters, raw.reporterChoicesByName, raw.loaded, raw.env.basePath, raw.options);
|
|
8573
8677
|
const reporterInit = yield* currentReporterInit(span);
|
|
8574
8678
|
const reporterStage = yield* attachReporterFactories(reporterInputs, raw.options, reporterInit);
|
|
8575
|
-
const now =
|
|
8679
|
+
const { now } = raw;
|
|
8576
8680
|
yield* Queue.offer(raw.queue, PhaseEntered.make({
|
|
8577
8681
|
phase: "prepare",
|
|
8578
8682
|
elapsedMs: now - raw.env.runStartedAt
|
|
@@ -8588,20 +8692,6 @@ const writePrepare = (reporters, raw) => withPhaseSpan("prepare", {}, (span) =>
|
|
|
8588
8692
|
frameworkClaimants: raw.frameworkClaimants
|
|
8589
8693
|
};
|
|
8590
8694
|
}));
|
|
8591
|
-
const STREAM_REPORTER = "progress-stream";
|
|
8592
|
-
const HUMAN_REPORTER = "clear-text";
|
|
8593
|
-
const STDOUT_REPORTERS = {
|
|
8594
|
-
"clear-text": true,
|
|
8595
|
-
"progress": true
|
|
8596
|
-
};
|
|
8597
|
-
const asHumanReporter = (name) => {
|
|
8598
|
-
if (name === STREAM_REPORTER) return HUMAN_REPORTER;
|
|
8599
|
-
return name;
|
|
8600
|
-
};
|
|
8601
|
-
const selectReporters = dual(2, (configured, mode) => Match.value(mode).pipe(Match.when("human", () => [...new Set(configured.map(asHumanReporter))]), Match.when("machine", () => {
|
|
8602
|
-
const permitted = configured.filter((name) => STDOUT_REPORTERS[name] !== true);
|
|
8603
|
-
return Match.value(permitted.includes(STREAM_REPORTER)).pipe(Match.when(true, () => permitted), Match.when(false, () => [...permitted, STREAM_REPORTER]), Match.exhaustive);
|
|
8604
|
-
}), Match.exhaustive));
|
|
8605
8695
|
const prepareCell = Sandwich.named("stryker.prepare")(readPrepare).decide(planPrepare).write({
|
|
8606
8696
|
HumanReporters: ({ reporters }, raw) => writePrepare(reporters, raw),
|
|
8607
8697
|
MachineReporters: ({ reporters }, raw) => writePrepare(reporters, raw),
|
|
@@ -8636,4 +8726,4 @@ const strykerCell = dual((args) => Predicate$1.isObject(args[0]), (options, targ
|
|
|
8636
8726
|
})
|
|
8637
8727
|
})), Effect$1.scoped));
|
|
8638
8728
|
//#endregion
|
|
8639
|
-
export {
|
|
8729
|
+
export { ExtendsStepDone as $, RunEvents as A, make$2 as B, forkCoreSchema as C, validateOptions as D, mergeConfigs as E, MetricsResultFromReport as F, ConfigFileInvalidError as G, isCommandRunner as H, reporterWorkerFactory as I, ConfigFileUnsupportedError as J, ConfigFileNotFoundError as K, spawnReporterWorker as L, VerdictEnvelope as M, VerdictMutant as N, RunEnvironment as O, VerdictThresholds as P, ExtendsStepDocumentSchema as Q, makeWorkerClient as R, describeErrors as S, initialExtendsStepState as T, FileMatcher as U, StrykerError as V, ConfigError as W, defaultOptions as X, createDefaultOptions as Y, ConfigDocumentSchema as Z, ClassifyWorkerExitDecision as _, isVmRunner as a, MergeCommand as at, readConfig as b, vmTestRunnerConfig as c, extendsPropertySchema as ct, makeRunEventStream as d, checkGroupedPlans as dt, ExtendsStepRead as et, RunEventWireLine as f, ChildProcessCrashedError as ft, ClassifyWorkerExitCommand as g, CheckerSkippedRequested as gt, layerWorkerProtocol as h, CheckerAnsweredUnrequested as ht, makeChildProcessTestRunner as i, ImportedModuleSchema as it, RunIdentity as j, IdGenerator as k, RunEventDrain as l, forkOptionsSchema as lt, nodePlatformLayer as m, WorkerBootTimeoutError as mt, strykerCell as n, ExtendsStepResolve as nt, testRunnerConfigOf as o, MergeResult as ot, IncrementalReportSchema as p, OutOfMemoryError as pt, ConfigFileUnreadableError as q, buildTestRunner as r, ExtendsStepStateSchema as rt, vmRunnerPluginUrl as s, ReadConfigCommand as st, mutationTestCell as t, ExtendsStepRefused as tt, RunEventDrainLive as u, survivorsPriorReport as ut, classifyWorkerExit as v, importModule as w, decideExtendsStep as x, loadConfigCell as y, WorkerLauncher as z };
|