@systemfsoftware/stryker-js 11.0.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +18 -18
- package/dist/{dist-ClUhPgb6.mjs → Run.schema-BxsyHwHr.mjs} +2941 -2700
- package/dist/{Run.schema-CUpTIyrj.d.mts → Run.schema-D43Nx5kI.d.mts} +1 -1
- package/dist/{RunEnvironment.service-zgwzyXpO.d.mts → RunEnvironment.service-pCzdC0Sy.d.mts} +51 -43
- 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-f-U3oZaJ.d.mts} +4 -5
- package/dist/index.d.mts +22 -20
- package/dist/index.mjs +4 -4
- package/dist/main.mjs +6940 -6391
- 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-MyhsNxH2.mjs} +605 -424
- package/dist/stryker-config.schema-GS_4_5gX.d.mts +18 -0
- package/package.json +15 -20
- package/dist/Run.schema-B_qdjbe9.mjs +0 -226
- 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-BxsyHwHr.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,8 +59,8 @@ 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";
|
|
63
|
+
import * as Equivalence from "effect/Equivalence";
|
|
66
64
|
import { Session } from "@systemfsoftware/stryker-vm-harness";
|
|
67
65
|
import * as Console from "effect/Console";
|
|
68
66
|
import * as Formatter from "effect/Formatter";
|
|
@@ -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$11 = 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$11);
|
|
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",
|
|
@@ -418,7 +419,11 @@ const checkCell = Sandwich.named("stryker.checker.check_plans")(readCheckCommand
|
|
|
418
419
|
CommandRejected: ({ issue }, raw) => Effect$1.fail(commandFailed(issue, raw))
|
|
419
420
|
});
|
|
420
421
|
const checkGroupedCell = Sandwich.named("stryker.checker.group_plans")(readGroupCommand).decide(admitCheckerAnswer).write({
|
|
421
|
-
CheckGroupDecision: ({ groups }, raw) => writeDecidedGroups(
|
|
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",
|
|
@@ -479,6 +484,22 @@ const forkOptionsSchema = S.StructWithRest(S.Struct({
|
|
|
479
484
|
extends: extendsPropertySchema
|
|
480
485
|
}), [S.Record(S.String, S.Unknown)]);
|
|
481
486
|
//#endregion
|
|
487
|
+
//#region src/config/default-options.ts
|
|
488
|
+
const isNonNullObject$1 = (value) => typeof value === "object" && value !== null;
|
|
489
|
+
const isRecordValue = (value) => isNonNullObject$1(value) && Array.isArray(value) === false;
|
|
490
|
+
const isArrayValue$1 = (value) => Array.isArray(value);
|
|
491
|
+
const freezeArrayValue = (value) => Object.freeze(value.map((element) => deepFreeze(element)));
|
|
492
|
+
const freezeMapEntry = ([entryKey, entryValue]) => [deepFreeze(entryKey), deepFreeze(entryValue)];
|
|
493
|
+
const freezeMapValue = (value) => Object.freeze(new Map([...value.entries()].map(freezeMapEntry)));
|
|
494
|
+
const freezeSetValue = (value) => Object.freeze(new Set([...value.values()].map((element) => deepFreeze(element))));
|
|
495
|
+
const freezeRegExpValue = (value) => Object.freeze(value);
|
|
496
|
+
const freezeRecordValue = (value) => Object.freeze(Record.map(value, (propertyValue) => deepFreeze(propertyValue)));
|
|
497
|
+
function deepFreeze(target) {
|
|
498
|
+
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));
|
|
499
|
+
}
|
|
500
|
+
const createDefaultOptions = S.decodeEffect(Options_exports.StrykerOptionsSchema)({}).pipe(Effect$1.orDie);
|
|
501
|
+
const defaultOptions = Effect$1.map(createDefaultOptions, (options) => deepFreeze(options));
|
|
502
|
+
//#endregion
|
|
482
503
|
//#region src/ConfigError.schema.ts
|
|
483
504
|
var ConfigFileNotFoundError = class extends S.TaggedError()("ConfigFileNotFoundError", { file: S.String }) {
|
|
484
505
|
exitClass = "ConfigError";
|
|
@@ -697,13 +718,16 @@ const interpretDryRunResult = Workflow.make({
|
|
|
697
718
|
});
|
|
698
719
|
//#endregion
|
|
699
720
|
//#region src/pooled-test-runner.handle.ts
|
|
700
|
-
const TypeId$
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
721
|
+
const TypeId$10 = Symbol.for("~systemfsoftware/stryker-js/PooledTestRunner");
|
|
722
|
+
const PooledTestRunner = Handle.make()(TypeId$10);
|
|
723
|
+
PooledTestRunner.is;
|
|
724
|
+
const make$3 = (runner) => PooledTestRunner.make({
|
|
725
|
+
capabilities: runner.capabilities,
|
|
726
|
+
init: runner.init,
|
|
727
|
+
dryRun: runner.dryRun,
|
|
728
|
+
mutantRun: runner.mutantRun
|
|
729
|
+
});
|
|
730
|
+
const withTimeout = (inner) => make$3({
|
|
707
731
|
...inner,
|
|
708
732
|
dryRun: (options) => inner.dryRun(options).pipe(Effect$1.timeoutOrElse({
|
|
709
733
|
duration: Duration.millis(options.timeout),
|
|
@@ -725,7 +749,7 @@ const maxRetries = 2;
|
|
|
725
749
|
const exhaustedMessage = (cause) => `Test runner crashed. Tried ${maxRetries} times to restart it without any luck. ${Cause.pretty(cause)}`;
|
|
726
750
|
const withRetry = (inner) => {
|
|
727
751
|
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 {
|
|
752
|
+
return make$3({
|
|
729
753
|
...inner,
|
|
730
754
|
dryRun: (options) => attempt(inner.dryRun(options), (errorMessage) => ({
|
|
731
755
|
status: "error",
|
|
@@ -735,11 +759,11 @@ const withRetry = (inner) => {
|
|
|
735
759
|
status: "error",
|
|
736
760
|
errorMessage
|
|
737
761
|
}))
|
|
738
|
-
};
|
|
762
|
+
});
|
|
739
763
|
};
|
|
740
764
|
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
765
|
const runs = yield* Ref.make(0);
|
|
742
|
-
return {
|
|
766
|
+
return make$3({
|
|
743
767
|
...inner,
|
|
744
768
|
mutantRun: (runOptions) => {
|
|
745
769
|
const policy = (self) => Effect$1.gen(function* () {
|
|
@@ -752,7 +776,7 @@ const withMaxReuse = dual(2, (options, retire) => (inner) => Match.value(options
|
|
|
752
776
|
});
|
|
753
777
|
return policy(inner.mutantRun(runOptions));
|
|
754
778
|
}
|
|
755
|
-
};
|
|
779
|
+
});
|
|
756
780
|
}))));
|
|
757
781
|
const nextEnvironmentState = (requested) => Boolean$1.match(requested, {
|
|
758
782
|
onTrue: () => "loaded-static-mutant",
|
|
@@ -768,7 +792,7 @@ const reloadPlanOf = (requested, current, canReload) => ({
|
|
|
768
792
|
});
|
|
769
793
|
const withEnvironmentReload = dual(2, (inner, retire) => Effect$1.gen(function* () {
|
|
770
794
|
const state = yield* Ref.make("pristine");
|
|
771
|
-
return {
|
|
795
|
+
return make$3({
|
|
772
796
|
...inner,
|
|
773
797
|
dryRun: (options) => {
|
|
774
798
|
const policy = (self) => Ref.set(state, "loaded").pipe(Effect$1.andThen(self));
|
|
@@ -792,8 +816,11 @@ const withEnvironmentReload = dual(2, (inner, retire) => Effect$1.gen(function*
|
|
|
792
816
|
reloadEnvironment: plan.reloadEnvironment
|
|
793
817
|
}));
|
|
794
818
|
})
|
|
795
|
-
};
|
|
819
|
+
});
|
|
796
820
|
}));
|
|
821
|
+
//#endregion
|
|
822
|
+
//#region src/command-runner.blueprint.ts
|
|
823
|
+
const TypeId$9 = Symbol.for("~systemfsoftware/stryker-js/CommandRunner");
|
|
797
824
|
const ALL_TESTS_NAME = "All tests";
|
|
798
825
|
const isCommandRunner = (name) => typeof name === "string" && name.toLowerCase() === "command";
|
|
799
826
|
const commandRunnerCapabilities = { reloadEnvironment: true };
|
|
@@ -845,11 +872,7 @@ const commandRunnerMutantRun = (config, mutantPick) => runCommand(config, mutant
|
|
|
845
872
|
onFailure: (failure) => Effect$1.fail(failure),
|
|
846
873
|
onSuccess: (decision) => Effect$1.succeed(decision.asResult)
|
|
847
874
|
})));
|
|
848
|
-
const
|
|
849
|
-
const config = {
|
|
850
|
-
workingDir: context.sandboxWorkingDirectory,
|
|
851
|
-
options: context.options
|
|
852
|
-
};
|
|
875
|
+
const pooledRunnerOf = (config, spawner) => {
|
|
853
876
|
const provided = Effect$1.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner);
|
|
854
877
|
return make$3({
|
|
855
878
|
capabilities: Effect$1.succeed(commandRunnerCapabilities),
|
|
@@ -857,6 +880,23 @@ const commandRunner = dual(2, (context, spawner) => {
|
|
|
857
880
|
dryRun: () => commandRunnerDryRun(config).pipe(provided),
|
|
858
881
|
mutantRun: (options) => commandRunnerMutantRun(config, options).pipe(provided)
|
|
859
882
|
});
|
|
883
|
+
};
|
|
884
|
+
const CommandRunners = Blueprint.make()(TypeId$9).steps({
|
|
885
|
+
steps: {},
|
|
886
|
+
targets: { runner: (spec) => (spawner) => pooledRunnerOf({
|
|
887
|
+
workingDir: spec.workingDir,
|
|
888
|
+
options: spec.options
|
|
889
|
+
}, spawner) }
|
|
890
|
+
});
|
|
891
|
+
const commandRunner = dual(2, (context, spawner) => CommandRunners.of({
|
|
892
|
+
workingDir: context.sandboxWorkingDirectory,
|
|
893
|
+
options: context.options
|
|
894
|
+
}).runner(spawner));
|
|
895
|
+
S.Struct({
|
|
896
|
+
command: S.Literals(["run", "merge-reports"]),
|
|
897
|
+
isDryRun: S.Boolean,
|
|
898
|
+
mode: S.Literals(["human", "machine"]),
|
|
899
|
+
isCi: S.Boolean
|
|
860
900
|
});
|
|
861
901
|
//#endregion
|
|
862
902
|
//#region src/config/warning-enabled.workflow.ts
|
|
@@ -1203,7 +1243,14 @@ var Trace_exports = /* @__PURE__ */ __exportAll$1({
|
|
|
1203
1243
|
layerTraceContextServer: () => layerTraceContextServer,
|
|
1204
1244
|
withLinkedSpan: () => withLinkedSpan
|
|
1205
1245
|
});
|
|
1206
|
-
const
|
|
1246
|
+
const isEscapedKey = (key) => JSON.stringify(key) !== `"${key}"`;
|
|
1247
|
+
const omitEscapedKeys = (key, value) => isEscapedKey(key) ? void 0 : value;
|
|
1248
|
+
const withoutEscapedKeys = (options) => Option$1.getOrThrow(S.decodeUnknownOption(Options_exports.StrykerOptionsSchema)(JSON.parse(JSON.stringify(options, omitEscapedKeys))));
|
|
1249
|
+
const OptionsLawDomain = S.declare((value) => S.is(Options_exports.StrykerOptionsSchema)(value), { toCodecArbitrary: () => S.link()(Options_exports.StrykerOptionsSchema, {
|
|
1250
|
+
decode: SchemaGetter.transform(withoutEscapedKeys),
|
|
1251
|
+
encode: SchemaGetter.passthrough()
|
|
1252
|
+
}) });
|
|
1253
|
+
const WorkerOptionsWire = S.fromJsonString(Options_exports.StrykerOptionsSchema.pipe(S.decodeTo(OptionsLawDomain, SchemaTransformation.passthrough())));
|
|
1207
1254
|
var WorkerOptions = class WorkerOptions extends Context.Service()("@systemfsoftware/stryker-js-plugin-runtime/worker-options.service/WorkerOptions") {
|
|
1208
1255
|
static layer = Layer.effect(WorkerOptions, Effect$1.gen(function* () {
|
|
1209
1256
|
const workerDir = yield* Config.String("STRYKER_WORKER_DIR");
|
|
@@ -1219,17 +1266,29 @@ const restrictSocket = (address) => Match.value(address).pipe(Match.tag("UnixPat
|
|
|
1219
1266
|
onTrue: () => Effect$1.void,
|
|
1220
1267
|
onFalse: () => Effect$1.flatMap(FileSystem.FileSystem, (fs) => fs.chmod(path, 384))
|
|
1221
1268
|
})), Match.orElse(() => Effect$1.void));
|
|
1222
|
-
const
|
|
1269
|
+
const TypeId$8 = Symbol.for("~systemfsoftware/stryker-js-plugin-runtime/WorkerServer");
|
|
1270
|
+
const workerServerLayerOf = (params) => Layer.unwrap(Effect$1.gen(function* () {
|
|
1223
1271
|
const socket = yield* SocketServer.SocketServer;
|
|
1224
1272
|
yield* restrictSocket(socket.address);
|
|
1225
1273
|
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
1274
|
}));
|
|
1275
|
+
Blueprint.make()(TypeId$8).steps({
|
|
1276
|
+
steps: {},
|
|
1277
|
+
targets: { layer: workerServerLayerOf }
|
|
1278
|
+
}).is;
|
|
1279
|
+
const workerServerLayer = workerServerLayerOf;
|
|
1227
1280
|
const TRACES_SUFFIX = "/v1/traces";
|
|
1228
1281
|
const tracesUrlOf = (endpoint) => Option$1.match(Option$1.liftPredicate(endpoint.replace(/\/+$/u, ""), (trimmed) => trimmed.endsWith(TRACES_SUFFIX)), {
|
|
1229
1282
|
onSome: (trimmed) => trimmed,
|
|
1230
1283
|
onNone: () => `${endpoint.replace(/\/+$/u, "")}${TRACES_SUFFIX}`
|
|
1231
1284
|
});
|
|
1232
|
-
const canonicalTracesUrl = S.String.pipe(S.check(S.isPattern(/\/v1\/traces$/u
|
|
1285
|
+
const canonicalTracesUrl = S.String.pipe(S.check(S.isPattern(/\/v1\/traces$/u, { arbitraryConstraint: {
|
|
1286
|
+
patterns: [{
|
|
1287
|
+
source: "\\/v1\\/traces$",
|
|
1288
|
+
flags: "u"
|
|
1289
|
+
}],
|
|
1290
|
+
minLength: 12
|
|
1291
|
+
} })));
|
|
1233
1292
|
const TracesUrl = S.String.pipe(S.decodeTo(canonicalTracesUrl, {
|
|
1234
1293
|
decode: SchemaGetter$1.transform(tracesUrlOf),
|
|
1235
1294
|
encode: SchemaGetter$1.passthrough()
|
|
@@ -1261,23 +1320,22 @@ var Worker_exports = /* @__PURE__ */ __exportAll$1({
|
|
|
1261
1320
|
});
|
|
1262
1321
|
//#endregion
|
|
1263
1322
|
//#region src/spawned-socket-worker.handle.ts
|
|
1264
|
-
const TypeId$
|
|
1265
|
-
const
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
[ClientLayerTypeId]: worker.clientLayer,
|
|
1323
|
+
const TypeId$7 = Symbol.for("~systemfsoftware/stryker-js/SpawnedSocketWorker");
|
|
1324
|
+
const SpawnedSocketWorker = Handle.make()(TypeId$7);
|
|
1325
|
+
SpawnedSocketWorker.is;
|
|
1326
|
+
const make$2 = (worker) => SpawnedSocketWorker.make({
|
|
1269
1327
|
pid: worker.pid,
|
|
1270
|
-
exited: worker.exited
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
const clientLayer = (self) => self[ClientLayerTypeId];
|
|
1328
|
+
exited: worker.exited
|
|
1329
|
+
}, { clientLayer: worker.clientLayer });
|
|
1330
|
+
const clientLayer = (self) => SpawnedSocketWorker.slot(self).clientLayer;
|
|
1274
1331
|
//#endregion
|
|
1275
1332
|
//#region src/WorkerLauncher.service.ts
|
|
1276
1333
|
var WorkerLauncher = class extends Context.Service()("@systemfsoftware/stryker-js/WorkerLauncher.service/WorkerLauncher") {};
|
|
1277
1334
|
//#endregion
|
|
1278
|
-
//#region src/worker-client.
|
|
1335
|
+
//#region src/worker-client.blueprint.ts
|
|
1336
|
+
const TypeId$6 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
|
|
1279
1337
|
const connectRetry = Schedule.max([Schedule.spaced(50), Schedule.recurs(100)]);
|
|
1280
|
-
const
|
|
1338
|
+
const scopedOf$2 = (params) => Effect$1.gen(function* () {
|
|
1281
1339
|
const launcher = yield* WorkerLauncher;
|
|
1282
1340
|
const optionsJson = yield* S.encodeEffect(Worker_exports.WorkerOptionsWire)(params.options).pipe(Effect$1.orDie);
|
|
1283
1341
|
const worker = yield* launcher.spawn({
|
|
@@ -1292,6 +1350,11 @@ const makeWorkerClient = (params) => Effect$1.gen(function* () {
|
|
|
1292
1350
|
const traceContext = yield* Layer.build(Trace_exports.layerTraceContextClient);
|
|
1293
1351
|
return yield* RpcClient.make(params.rpcs).pipe(Effect$1.provideContext(Context.merge(protocol, traceContext)));
|
|
1294
1352
|
});
|
|
1353
|
+
const WorkerClients = () => Blueprint.make()(TypeId$6).steps({
|
|
1354
|
+
steps: {},
|
|
1355
|
+
targets: { scoped: scopedOf$2 }
|
|
1356
|
+
});
|
|
1357
|
+
const makeWorkerClient = (params) => WorkerClients().of(params).scoped;
|
|
1295
1358
|
const ReporterStageTypeId = Symbol.for("@systemfsoftware/stryker-js/ReporterStage");
|
|
1296
1359
|
const carriesAttachments = (stage) => "attachments" in stage;
|
|
1297
1360
|
const makeReporterStage = (attachments) => {
|
|
@@ -1677,7 +1740,7 @@ var RunEvents = class extends Context.Service()("@systemfsoftware/stryker-js/run
|
|
|
1677
1740
|
var RunIdentity = class extends Context.Service()("@systemfsoftware/stryker-js/run-events.service/RunIdentity") {};
|
|
1678
1741
|
//#endregion
|
|
1679
1742
|
//#region package.json
|
|
1680
|
-
var version = "
|
|
1743
|
+
var version = "12.0.0";
|
|
1681
1744
|
//#endregion
|
|
1682
1745
|
//#region src/stryker-package.schema.ts
|
|
1683
1746
|
var StrykerPackage = class extends S.Class("StrykerPackage")({
|
|
@@ -2108,7 +2171,8 @@ var ClearTextReportCommand = class extends S.TaggedClass()("ClearTextReportComma
|
|
|
2108
2171
|
};
|
|
2109
2172
|
var ClearTextReportRendered = class extends S.TaggedClass()("ClearTextReportRendered", {
|
|
2110
2173
|
stdout: S.Array(ReportChunkSchema),
|
|
2111
|
-
diagnostics: S.Array(ReportChunkSchema)
|
|
2174
|
+
diagnostics: S.Array(ReportChunkSchema),
|
|
2175
|
+
stderr: S.Array(ReportChunkSchema)
|
|
2112
2176
|
}) {
|
|
2113
2177
|
[ClearTextReportTypeId] = ClearTextReportTypeId;
|
|
2114
2178
|
};
|
|
@@ -2525,7 +2589,11 @@ const renderClearTextReport = Workflow.make({
|
|
|
2525
2589
|
const sections = renderClearText(report, metrics, command.render);
|
|
2526
2590
|
return Result.succeed(ClearTextReportRendered.make({
|
|
2527
2591
|
stdout: [...sections.stdout],
|
|
2528
|
-
diagnostics: [...sections.diagnostics]
|
|
2592
|
+
diagnostics: [...sections.diagnostics],
|
|
2593
|
+
stderr: Boolean$1.match(command.render.debug, {
|
|
2594
|
+
onTrue: () => [...sections.diagnostics],
|
|
2595
|
+
onFalse: () => []
|
|
2596
|
+
})
|
|
2529
2597
|
}));
|
|
2530
2598
|
}
|
|
2531
2599
|
})
|
|
@@ -2575,14 +2643,8 @@ const renderOptionsOf = (options) => ({
|
|
|
2575
2643
|
});
|
|
2576
2644
|
const readClearTextReport = (input) => Effect$1.map(Stream.fromAsyncIterable(input.events, failAsClearText).pipe(Stream.filterMap(terminalReportOf), Stream.run(Sink.last())), (terminal) => ({
|
|
2577
2645
|
_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
|
-
}),
|
|
2646
|
+
reported: Option$1.getOrUndefined(Option$1.map(terminal, (ready) => ready.report)),
|
|
2647
|
+
computed: Option$1.getOrUndefined(Option$1.map(terminal, (ready) => ready.metrics)),
|
|
2586
2648
|
render: renderOptionsOf(input.options),
|
|
2587
2649
|
rendered: true
|
|
2588
2650
|
}));
|
|
@@ -2619,13 +2681,10 @@ const renderLine = (line) => runsOf(line).map(renderSpan).join("");
|
|
|
2619
2681
|
const renderChunk = (chunk) => chunk.map(renderLine).join("\n");
|
|
2620
2682
|
const writeChunks = (output, channel, chunks) => output.write(channel, chunks.map((chunk) => `${renderChunk(chunk)}\n`)).pipe(Effect$1.mapError(failAsClearText), Effect$1.asVoid);
|
|
2621
2683
|
const clearTextReportCell = Sandwich.named("stryker.report.clearText")(readClearTextReport).decide(renderClearTextReport).write({
|
|
2622
|
-
ClearTextReportRendered: (rendered,
|
|
2684
|
+
ClearTextReportRendered: (rendered, _raw) => Effect$1.gen(function* () {
|
|
2623
2685
|
const output = yield* ReporterOutput;
|
|
2624
2686
|
yield* writeChunks(output, "stdout", rendered.stdout);
|
|
2625
|
-
yield*
|
|
2626
|
-
onTrue: () => writeChunks(output, "stderr", rendered.diagnostics),
|
|
2627
|
-
onFalse: () => Effect$1.void
|
|
2628
|
-
});
|
|
2687
|
+
yield* Effect$1.forEach(rendered.stderr, (chunk) => writeChunks(output, "stderr", [chunk]), { discard: true });
|
|
2629
2688
|
}),
|
|
2630
2689
|
ClearTextReportSuppressed: () => Effect$1.void,
|
|
2631
2690
|
CommandRejected: ({ issue }) => Effect$1.fail(failAsClearText(issue))
|
|
@@ -2642,11 +2701,16 @@ const clearTextReporterFactory = (context) => {
|
|
|
2642
2701
|
const JsonReportTypeId = Symbol.for("@systemfsoftware/stryker-js/JsonReport");
|
|
2643
2702
|
var JsonReportCommand = class extends S.TaggedClass()("JsonReportCommand", {
|
|
2644
2703
|
reported: S.optional(Report_exports.MutationTestResultSchema),
|
|
2645
|
-
rendered: S.Boolean
|
|
2704
|
+
rendered: S.Boolean,
|
|
2705
|
+
debug: S.Boolean,
|
|
2706
|
+
fileName: S.String
|
|
2646
2707
|
}) {
|
|
2647
2708
|
static [Workflow.InstrumentationBrand] = { rendered: "stryker.report.render" };
|
|
2648
2709
|
};
|
|
2649
|
-
var JsonReportRendered = class extends S.TaggedClass()("JsonReportRendered", {
|
|
2710
|
+
var JsonReportRendered = class extends S.TaggedClass()("JsonReportRendered", {
|
|
2711
|
+
report: Report_exports.MutationTestResultSchema,
|
|
2712
|
+
announceFileName: S.Option(S.String)
|
|
2713
|
+
}) {
|
|
2650
2714
|
[JsonReportTypeId] = JsonReportTypeId;
|
|
2651
2715
|
};
|
|
2652
2716
|
var JsonReportSuppressed = class extends S.TaggedClass()("JsonReportSuppressed", {}) {
|
|
@@ -2659,7 +2723,13 @@ const renderJsonReport = Workflow.make({
|
|
|
2659
2723
|
error: S.Never,
|
|
2660
2724
|
decide: (command) => Option$1.match(Option$1.fromUndefinedOr(command.reported), {
|
|
2661
2725
|
onNone: () => Result.succeed(JsonReportSuppressed.make({})),
|
|
2662
|
-
onSome: (report) => Result.succeed(JsonReportRendered.make({
|
|
2726
|
+
onSome: (report) => Result.succeed(JsonReportRendered.make({
|
|
2727
|
+
report,
|
|
2728
|
+
announceFileName: Boolean$1.match(command.debug, {
|
|
2729
|
+
onTrue: () => Option$1.some(command.fileName),
|
|
2730
|
+
onFalse: () => Option$1.none()
|
|
2731
|
+
})
|
|
2732
|
+
}))
|
|
2663
2733
|
})
|
|
2664
2734
|
});
|
|
2665
2735
|
//#endregion
|
|
@@ -2674,13 +2744,11 @@ const readJsonReport = (input) => Effect$1.map(Stream.fromAsyncIterable(input.ev
|
|
|
2674
2744
|
_tag: "JsonReportCommand",
|
|
2675
2745
|
reported: Option$1.getOrUndefined(last),
|
|
2676
2746
|
rendered: true,
|
|
2747
|
+
debug: input.options.logLevel === "debug",
|
|
2748
|
+
fileName: input.options.jsonReporter.fileName,
|
|
2677
2749
|
options: input.options
|
|
2678
2750
|
}));
|
|
2679
2751
|
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
2752
|
const jsonReportCell = Sandwich.named("stryker.report.json")(readJsonReport).decide(renderJsonReport).write({
|
|
2685
2753
|
JsonReportRendered: (rendered, raw) => Effect$1.gen(function* () {
|
|
2686
2754
|
const output = yield* ReporterOutput;
|
|
@@ -2688,7 +2756,7 @@ const jsonReportCell = Sandwich.named("stryker.report.json")(readJsonReport).dec
|
|
|
2688
2756
|
const path = yield* Path.Path;
|
|
2689
2757
|
const json = yield* jsonBytesOf(rendered.report);
|
|
2690
2758
|
const fileName = path.resolve(raw.options.jsonReporter.fileName);
|
|
2691
|
-
yield*
|
|
2759
|
+
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
2760
|
yield* fs.makeDirectory(path.dirname(fileName), { recursive: true }).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
2693
2761
|
yield* fs.writeFileString(fileName, json).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
2694
2762
|
const url = yield* path.toFileUrl(fileName).pipe(Effect$1.mapError(failAsJsonReporter));
|
|
@@ -2705,116 +2773,11 @@ const jsonReporterFactory = (context) => {
|
|
|
2705
2773
|
}));
|
|
2706
2774
|
};
|
|
2707
2775
|
//#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
|
-
});
|
|
2776
|
+
//#region src/progress-report.steps.ts
|
|
2795
2777
|
const PROGRESS_BAR_FORMAT = "Mutation testing [:bar] :percent (elapsed: :et, remaining: :etc) :tested/:mutants Mutants tested (:survived survived, :timedOut timed out)";
|
|
2796
2778
|
const PROGRESS_BAR_WIDTH = 50;
|
|
2797
2779
|
const PROGRESS_BAR_COMPLETE = "=";
|
|
2798
2780
|
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
2781
|
const TALLY_COUNTED = {
|
|
2819
2782
|
Killed: {
|
|
2820
2783
|
survived: 0,
|
|
@@ -2917,24 +2880,14 @@ const advance = (state, event, now) => Match.value(event).pipe(Match.tag("dryRun
|
|
|
2917
2880
|
kind: "skip",
|
|
2918
2881
|
state
|
|
2919
2882
|
})));
|
|
2920
|
-
const
|
|
2883
|
+
const progressStep = (input) => Option$1.match(Option$1.fromNullishOr(input.event), {
|
|
2921
2884
|
onNone: () => ({
|
|
2922
|
-
_tag: "ProgressReportCommand",
|
|
2923
2885
|
kind: "finalize",
|
|
2924
|
-
state: input.state
|
|
2925
|
-
now
|
|
2886
|
+
state: input.state
|
|
2926
2887
|
}),
|
|
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;
|
|
2888
|
+
onSome: (present) => advance(input.state, present, input.now)
|
|
2889
|
+
});
|
|
2890
|
+
const isComplete$1 = (bar) => bar.curr >= bar.total;
|
|
2938
2891
|
const secondsBetween = (now, startedAt) => Math.floor((now - startedAt) / 1e3);
|
|
2939
2892
|
const formatTime = (timeInSeconds) => {
|
|
2940
2893
|
const hours = Math.floor(timeInSeconds / 3600);
|
|
@@ -2972,7 +2925,128 @@ const lineBreakOf = (complete) => Boolean$1.match(complete, {
|
|
|
2972
2925
|
onTrue: () => "\n",
|
|
2973
2926
|
onFalse: () => ""
|
|
2974
2927
|
});
|
|
2975
|
-
const renderTick = (tick) => `\r${formatBar(tick.bar, progressData(tick.tally, tick.now))}${lineBreakOf(isComplete(tick.bar))}`;
|
|
2928
|
+
const renderTick = (tick) => `\r${formatBar(tick.bar, progressData(tick.tally, tick.now))}${lineBreakOf(isComplete$1(tick.bar))}`;
|
|
2929
|
+
//#endregion
|
|
2930
|
+
//#region src/render-progress-report.workflow.ts
|
|
2931
|
+
const ProgressReportTypeId = Symbol.for("@systemfsoftware/stryker-js/ProgressReport");
|
|
2932
|
+
const ProgressTimingSchema = S.Struct({
|
|
2933
|
+
net: S.Finite,
|
|
2934
|
+
overhead: S.Finite
|
|
2935
|
+
});
|
|
2936
|
+
const ProgressCapabilitiesSchema = S.Struct({ reloadEnvironment: S.Boolean });
|
|
2937
|
+
const ProgressTallySchema = S.Struct({
|
|
2938
|
+
survived: S.Finite,
|
|
2939
|
+
timedOut: S.Finite,
|
|
2940
|
+
tested: S.Finite,
|
|
2941
|
+
mutants: S.Finite,
|
|
2942
|
+
total: S.Finite,
|
|
2943
|
+
ticks: S.Finite,
|
|
2944
|
+
ticksByMutantId: S.Record(S.String, S.Finite),
|
|
2945
|
+
timing: ProgressTimingSchema,
|
|
2946
|
+
capabilities: ProgressCapabilitiesSchema,
|
|
2947
|
+
startedAt: S.Finite
|
|
2948
|
+
});
|
|
2949
|
+
const ProgressBarStateSchema = S.Struct({
|
|
2950
|
+
format: S.String,
|
|
2951
|
+
total: S.Finite,
|
|
2952
|
+
curr: S.Finite,
|
|
2953
|
+
width: S.Finite,
|
|
2954
|
+
complete: S.String,
|
|
2955
|
+
incomplete: S.String
|
|
2956
|
+
});
|
|
2957
|
+
const ProgressStateSchema = S.Struct({
|
|
2958
|
+
tally: ProgressTallySchema,
|
|
2959
|
+
bar: S.NullOr(ProgressBarStateSchema)
|
|
2960
|
+
});
|
|
2961
|
+
var ProgressReportCommand = class extends S.TaggedClass()("ProgressReportCommand", {
|
|
2962
|
+
kind: S.Literals([
|
|
2963
|
+
"tick",
|
|
2964
|
+
"skip",
|
|
2965
|
+
"finalize"
|
|
2966
|
+
]),
|
|
2967
|
+
state: ProgressStateSchema,
|
|
2968
|
+
now: S.Finite
|
|
2969
|
+
}) {
|
|
2970
|
+
static [Workflow.InstrumentationBrand] = { now: "stryker.report.rendered" };
|
|
2971
|
+
};
|
|
2972
|
+
var ProgressBarTick = class extends S.TaggedClass()("ProgressBarTick", {
|
|
2973
|
+
bar: ProgressBarStateSchema,
|
|
2974
|
+
tally: ProgressTallySchema,
|
|
2975
|
+
now: S.Finite
|
|
2976
|
+
}) {
|
|
2977
|
+
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2978
|
+
};
|
|
2979
|
+
var ProgressLineBreak = class extends S.TaggedClass()("ProgressLineBreak", {}) {
|
|
2980
|
+
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2981
|
+
};
|
|
2982
|
+
var ProgressChunkSuppressed = class extends S.TaggedClass()("ProgressChunkSuppressed", {}) {
|
|
2983
|
+
[ProgressReportTypeId] = ProgressReportTypeId;
|
|
2984
|
+
};
|
|
2985
|
+
const ProgressReportDecision = S.Union([
|
|
2986
|
+
ProgressBarTick,
|
|
2987
|
+
ProgressLineBreak,
|
|
2988
|
+
ProgressChunkSuppressed
|
|
2989
|
+
]);
|
|
2990
|
+
const isComplete = (bar) => bar.curr >= bar.total;
|
|
2991
|
+
const renderProgressReport = Workflow.make({
|
|
2992
|
+
command: ProgressReportCommand,
|
|
2993
|
+
decision: ProgressReportDecision,
|
|
2994
|
+
error: S.Never,
|
|
2995
|
+
decide: (command) => Result.succeed(Match.value(command.kind).pipe(Match.when("finalize", () => Option$1.match(Option$1.fromNullishOr(command.state.bar), {
|
|
2996
|
+
onNone: () => ProgressChunkSuppressed.make({}),
|
|
2997
|
+
onSome: (bar) => Boolean$1.match(isComplete(bar), {
|
|
2998
|
+
onTrue: () => ProgressChunkSuppressed.make({}),
|
|
2999
|
+
onFalse: () => ProgressLineBreak.make({})
|
|
3000
|
+
})
|
|
3001
|
+
})), Match.when("skip", () => ProgressChunkSuppressed.make({})), Match.when("tick", () => Option$1.match(Option$1.fromNullishOr(command.state.bar), {
|
|
3002
|
+
onNone: () => ProgressChunkSuppressed.make({}),
|
|
3003
|
+
onSome: (bar) => ProgressBarTick.make({
|
|
3004
|
+
bar,
|
|
3005
|
+
tally: command.state.tally,
|
|
3006
|
+
now: command.now
|
|
3007
|
+
})
|
|
3008
|
+
})), Match.exhaustive))
|
|
3009
|
+
});
|
|
3010
|
+
//#endregion
|
|
3011
|
+
//#region src/progress-report.cell.ts
|
|
3012
|
+
const failAsProgress = (cause) => Reporter_exports.ReporterFailed.make({
|
|
3013
|
+
reporterName: "progress",
|
|
3014
|
+
event: "mutationTestReportReady",
|
|
3015
|
+
cause: Option$1.getOrElse(Option$1.map(ErrorText_exports.ErrorText.fromCause(cause), (rendered) => rendered.text), () => "")
|
|
3016
|
+
});
|
|
3017
|
+
const emptyTally = (startedAt) => ({
|
|
3018
|
+
survived: 0,
|
|
3019
|
+
timedOut: 0,
|
|
3020
|
+
tested: 0,
|
|
3021
|
+
mutants: 0,
|
|
3022
|
+
total: 0,
|
|
3023
|
+
ticks: 0,
|
|
3024
|
+
ticksByMutantId: {},
|
|
3025
|
+
timing: {
|
|
3026
|
+
net: 0,
|
|
3027
|
+
overhead: 0
|
|
3028
|
+
},
|
|
3029
|
+
capabilities: { reloadEnvironment: false },
|
|
3030
|
+
startedAt
|
|
3031
|
+
});
|
|
3032
|
+
const INITIAL_PROGRESS = {
|
|
3033
|
+
tally: emptyTally(0),
|
|
3034
|
+
bar: null
|
|
3035
|
+
};
|
|
3036
|
+
const readProgressStep = (input) => Effect$1.gen(function* () {
|
|
3037
|
+
const now = yield* Clock.currentTimeMillis;
|
|
3038
|
+
const step = progressStep({
|
|
3039
|
+
state: input.state,
|
|
3040
|
+
event: input.event,
|
|
3041
|
+
now
|
|
3042
|
+
});
|
|
3043
|
+
return {
|
|
3044
|
+
_tag: "ProgressReportCommand",
|
|
3045
|
+
kind: step.kind,
|
|
3046
|
+
state: step.state,
|
|
3047
|
+
now
|
|
3048
|
+
};
|
|
3049
|
+
});
|
|
2976
3050
|
const writeChunk = (chunk) => Effect$1.flatMap(ReporterOutput, (output) => Effect$1.ignore(output.write("stdout", [chunk])));
|
|
2977
3051
|
const progressReportCell = Sandwich.named("stryker.report.progress")(readProgressStep).decide(renderProgressReport).write({
|
|
2978
3052
|
ProgressBarTick: (tick, raw) => Effect$1.as(writeChunk(renderTick(tick)), raw.state),
|
|
@@ -3061,7 +3135,7 @@ const phaseEntered = (phase) => Effect$1.gen(function* () {
|
|
|
3061
3135
|
}));
|
|
3062
3136
|
});
|
|
3063
3137
|
//#endregion
|
|
3064
|
-
//#region src/run/load-config.
|
|
3138
|
+
//#region src/run/load-config.parts.ts
|
|
3065
3139
|
const isNonNullObject = (value) => typeof value === "object" && value !== null;
|
|
3066
3140
|
const combine = (prefixes, suffixes, extensions) => prefixes.flatMap((prefix) => suffixes.flatMap((suffix) => extensions.map((extension) => `${prefix}stryker${suffix}.${extension}`)));
|
|
3067
3141
|
const CONFIG_FILE_NAME_PREFIXES = ["", "."];
|
|
@@ -3228,7 +3302,7 @@ const applyConfigFactory = (factory, configEnv) => factory(configEnv);
|
|
|
3228
3302
|
/**
|
|
3229
3303
|
* Settle a config module's default export into the object the document schema decodes.
|
|
3230
3304
|
*
|
|
3231
|
-
* `./config` types `
|
|
3305
|
+
* `./config` types `defineConfig` as accepting the config object, a promise of it,
|
|
3232
3306
|
* or a factory receiving `ConfigEnv`, so the loader accepts all three. The factory
|
|
3233
3307
|
* is invoked here because this is the only place that knows the invocation the
|
|
3234
3308
|
* config is being read for; the promise is awaited here because a promise is a
|
|
@@ -3536,20 +3610,10 @@ const readLoadConfig = (input) => Effect$1.gen(function* () {
|
|
|
3536
3610
|
};
|
|
3537
3611
|
const cliRecord = yield* S.decodeEffect(ConfigDocumentSchema)(input.cliOptions).pipe(Effect$1.orDie);
|
|
3538
3612
|
return yield* loadOptionsFromConfigFile(cliRecord, configEnv).pipe(Effect$1.map((fileOptions) => LoadConfigCommand.make({
|
|
3539
|
-
document:
|
|
3613
|
+
document: mergeConfig(Option$1.getOrElse(fileOptions, () => ({})), cliRecord),
|
|
3540
3614
|
fileFound: Option$1.isSome(fileOptions)
|
|
3541
3615
|
})));
|
|
3542
3616
|
});
|
|
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
3617
|
const emitPreparePhaseEntered = phaseEntered("prepare");
|
|
3554
3618
|
const failConfigWith = (message) => Effect$1.fail(ConfigError.make({ message })).pipe(Effect$1.tapCause(() => emitPreparePhaseEntered));
|
|
3555
3619
|
const readRunConfig = (input) => Effect$1.gen(function* () {
|
|
@@ -3566,6 +3630,18 @@ const readRunConfig = (input) => Effect$1.gen(function* () {
|
|
|
3566
3630
|
basePath: env.basePath
|
|
3567
3631
|
});
|
|
3568
3632
|
});
|
|
3633
|
+
//#endregion
|
|
3634
|
+
//#region src/run/load-config.cell.ts
|
|
3635
|
+
const loadConfig = Sandwich.named("stryker.config_read")(readLoadConfig).decide(resolveConfig).write({
|
|
3636
|
+
ConfigFromFile: ({ options }) => Effect$1.succeed(options),
|
|
3637
|
+
ConfigFromDefaults: ({ options }) => Effect$1.succeed(options),
|
|
3638
|
+
ConfigOptionsRefused: ({ message }) => Effect$1.fail(ConfigError.make({ message: configErrorMessage(describeMessageOf(message)) })),
|
|
3639
|
+
CommandRejected: ({ issue }) => Effect$1.fail(ConfigError.make({ message: issue }))
|
|
3640
|
+
});
|
|
3641
|
+
const readConfig = dual(2, (cliOptions, invocation) => loadConfig.run({
|
|
3642
|
+
cliOptions,
|
|
3643
|
+
invocation
|
|
3644
|
+
}));
|
|
3569
3645
|
const loadConfigCell = Sandwich.named("stryker.load_config")(readRunConfig).decide(resolveConfig).write({
|
|
3570
3646
|
ConfigFromFile: ({ options }, raw) => Effect$1.succeed({
|
|
3571
3647
|
options,
|
|
@@ -3620,9 +3696,10 @@ const classifyWorkerExit = Workflow.make({
|
|
|
3620
3696
|
decide: decide$8
|
|
3621
3697
|
});
|
|
3622
3698
|
//#endregion
|
|
3623
|
-
//#region src/worker-protocol.
|
|
3699
|
+
//#region src/worker-protocol.blueprint.ts
|
|
3700
|
+
const TypeId$5 = Symbol.for("~systemfsoftware/stryker-js/WorkerProtocol");
|
|
3624
3701
|
const droppedConnection = RpcClientError.make({ reason: Socket.SocketReadError.make({ cause: /* @__PURE__ */ new Error("worker connection dropped with the request in flight") }) });
|
|
3625
|
-
const
|
|
3702
|
+
const layerOf = (socket) => Layer.effect(RpcClient.Protocol, Effect$1.gen(function* () {
|
|
3626
3703
|
const handlers = MutableHashMap.empty();
|
|
3627
3704
|
const inFlight = MutableHashMap.empty();
|
|
3628
3705
|
const connected = yield* Ref.make(false);
|
|
@@ -3661,6 +3738,11 @@ const layerWorkerProtocol = (socket) => Layer.effect(RpcClient.Protocol, Effect$
|
|
|
3661
3738
|
send: (clientId, request, transferables) => track(clientId, request).pipe(Effect$1.andThen(inner.send(clientId, request, transferables)))
|
|
3662
3739
|
});
|
|
3663
3740
|
}));
|
|
3741
|
+
const WorkerProtocol = Blueprint.make()(TypeId$5).steps({
|
|
3742
|
+
steps: {},
|
|
3743
|
+
targets: { layer: (spec) => layerOf(spec.socket) }
|
|
3744
|
+
});
|
|
3745
|
+
const layerWorkerProtocol = (socket) => WorkerProtocol.of({ socket }).layer;
|
|
3664
3746
|
//#endregion
|
|
3665
3747
|
//#region src/drivers/node.ts
|
|
3666
3748
|
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));
|
|
@@ -3897,7 +3979,7 @@ const writeHtmlFile = (fileName, html) => Effect$1.gen(function* () {
|
|
|
3897
3979
|
const readRenderCommand = (input) => Effect$1.succeed({
|
|
3898
3980
|
_tag: "RenderHtmlReport",
|
|
3899
3981
|
fileName: input.fileName,
|
|
3900
|
-
inlinedBundle: inlinedBundle
|
|
3982
|
+
inlinedBundle: input.inlinedBundle,
|
|
3901
3983
|
report: input.report
|
|
3902
3984
|
});
|
|
3903
3985
|
const writeHtmlReport = Sandwich.named("html_report.write")(readRenderCommand).decide(renderHtmlReport).write({
|
|
@@ -3916,7 +3998,8 @@ const failAsHtmlReporter = (cause) => Reporter_exports.ReporterFailed.make({
|
|
|
3916
3998
|
});
|
|
3917
3999
|
const drainEvents = (fileName, events) => Stream.runForEach(Stream.fromAsyncIterable(events, failAsHtmlReporter).pipe(Stream.filter(S.is(Reporter_exports.MutationTestReportReady))), (ready) => writeHtmlReport.run({
|
|
3918
4000
|
fileName,
|
|
3919
|
-
report: ready.report
|
|
4001
|
+
report: ready.report,
|
|
4002
|
+
inlinedBundle: inlinedBundle()
|
|
3920
4003
|
}).pipe(Effect$1.mapError(failAsHtmlReporter)));
|
|
3921
4004
|
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
4005
|
var HtmlReporter_exports = /* @__PURE__ */ __exportAll({ makeHtmlReporter: () => makeHtmlReporter });
|
|
@@ -3927,7 +4010,8 @@ const PERCENTAGE_OPTION = /^(100|[1-9]?[0-9])%$/;
|
|
|
3927
4010
|
var TestRunnersOnly = class extends S.TaggedClass()("TestRunnersOnly", {
|
|
3928
4011
|
testRunners: S.Finite,
|
|
3929
4012
|
total: S.Finite,
|
|
3930
|
-
isPercentage: S.Boolean
|
|
4013
|
+
isPercentage: S.Boolean,
|
|
4014
|
+
announcement: S.Option(S.String)
|
|
3931
4015
|
}) {
|
|
3932
4016
|
[ConcurrencyDecisionTypeId] = ConcurrencyDecisionTypeId;
|
|
3933
4017
|
};
|
|
@@ -3935,7 +4019,8 @@ var TestRunnersAndCheckers = class extends S.TaggedClass()("TestRunnersAndChecke
|
|
|
3935
4019
|
testRunners: S.Finite,
|
|
3936
4020
|
checkers: S.Finite,
|
|
3937
4021
|
total: S.Finite,
|
|
3938
|
-
isPercentage: S.Boolean
|
|
4022
|
+
isPercentage: S.Boolean,
|
|
4023
|
+
announcement: S.Option(S.String)
|
|
3939
4024
|
}) {
|
|
3940
4025
|
[ConcurrencyDecisionTypeId] = ConcurrencyDecisionTypeId;
|
|
3941
4026
|
};
|
|
@@ -3957,31 +4042,37 @@ const defaultedTotal = (availableParallelism) => Boolean$1.match(availableParall
|
|
|
3957
4042
|
const percentageDetails = (text, availableParallelism) => Option$1.match(percentageOf(text), {
|
|
3958
4043
|
onSome: (percentage) => ({
|
|
3959
4044
|
total: percentageTotal(percentage, availableParallelism),
|
|
3960
|
-
isPercentage: true
|
|
4045
|
+
isPercentage: true,
|
|
4046
|
+
announcement: Option$1.some(`Computed concurrency ${percentageTotal(percentage, availableParallelism)} from "${text}" based on ${availableParallelism} available parallelism.`)
|
|
3961
4047
|
}),
|
|
3962
4048
|
onNone: () => ({
|
|
3963
4049
|
total: defaultedTotal(availableParallelism),
|
|
3964
|
-
isPercentage: false
|
|
4050
|
+
isPercentage: false,
|
|
4051
|
+
announcement: Option$1.none()
|
|
3965
4052
|
})
|
|
3966
4053
|
});
|
|
3967
4054
|
const detailsOf = (concurrency, availableParallelism) => Match.value(concurrency).pipe(Match.when(Predicate$1.isString, (text) => percentageDetails(text, availableParallelism)), Match.when(Predicate$1.isNumber, (total) => ({
|
|
3968
4055
|
total,
|
|
3969
|
-
isPercentage: false
|
|
4056
|
+
isPercentage: false,
|
|
4057
|
+
announcement: Option$1.none()
|
|
3970
4058
|
})), Match.orElse(() => ({
|
|
3971
4059
|
total: defaultedTotal(availableParallelism),
|
|
3972
|
-
isPercentage: false
|
|
4060
|
+
isPercentage: false,
|
|
4061
|
+
announcement: Option$1.none()
|
|
3973
4062
|
})));
|
|
3974
4063
|
const splitOf = (details, checkerCount) => Boolean$1.match(checkerCount > 0, {
|
|
3975
4064
|
onTrue: () => TestRunnersAndCheckers.make({
|
|
3976
4065
|
testRunners: max$1(floor(details.total / 2), 1),
|
|
3977
4066
|
checkers: max$1(ceil(details.total / 2), 1),
|
|
3978
4067
|
total: details.total,
|
|
3979
|
-
isPercentage: details.isPercentage
|
|
4068
|
+
isPercentage: details.isPercentage,
|
|
4069
|
+
announcement: details.announcement
|
|
3980
4070
|
}),
|
|
3981
4071
|
onFalse: () => TestRunnersOnly.make({
|
|
3982
4072
|
testRunners: details.total,
|
|
3983
4073
|
total: details.total,
|
|
3984
|
-
isPercentage: details.isPercentage
|
|
4074
|
+
isPercentage: details.isPercentage,
|
|
4075
|
+
announcement: details.announcement
|
|
3985
4076
|
})
|
|
3986
4077
|
});
|
|
3987
4078
|
const decide$7 = (command) => Result.succeed(splitOf(detailsOf(command.concurrency, command.availableParallelism), command.checkerCount));
|
|
@@ -4003,19 +4094,15 @@ const readConcurrency = (record) => Effect$1.sync(() => ({
|
|
|
4003
4094
|
availableParallelism: availableParallelism(),
|
|
4004
4095
|
record
|
|
4005
4096
|
}));
|
|
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
4097
|
const concurrencyCell = Sandwich.named("stryker.concurrency")(readConcurrency).decide(resolveConcurrency).write({
|
|
4011
|
-
TestRunnersAndCheckers: (split, command) => Effect$1.as(Effect$1.andThen(
|
|
4098
|
+
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
4099
|
...command.record,
|
|
4013
4100
|
concurrency: {
|
|
4014
4101
|
testRunners: split.testRunners,
|
|
4015
4102
|
checkers: split.checkers
|
|
4016
4103
|
}
|
|
4017
4104
|
}),
|
|
4018
|
-
TestRunnersOnly: (split, command) => Effect$1.as(Effect$1.andThen(
|
|
4105
|
+
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
4106
|
...command.record,
|
|
4020
4107
|
concurrency: {
|
|
4021
4108
|
testRunners: split.testRunners,
|
|
@@ -4058,6 +4145,9 @@ const admitIncrementalReport = Workflow.make({
|
|
|
4058
4145
|
error: S.Never,
|
|
4059
4146
|
decide: (command) => Result.succeed(decide$6(command))
|
|
4060
4147
|
});
|
|
4148
|
+
//#endregion
|
|
4149
|
+
//#region src/VmRunner.blueprint.ts
|
|
4150
|
+
const TypeId$4 = Symbol.for("~systemfsoftware/stryker-js/VmTestRunner");
|
|
4061
4151
|
const isVmRunner = (name) => typeof name === "string" && name.toLowerCase() === "vm";
|
|
4062
4152
|
const vmRunnerCapabilities = { reloadEnvironment: true };
|
|
4063
4153
|
const HOST_TIMEOUT_SLACK_MS = 1e3;
|
|
@@ -4178,12 +4268,17 @@ const pooledVmRunner = (config, scope) => {
|
|
|
4178
4268
|
})))
|
|
4179
4269
|
});
|
|
4180
4270
|
};
|
|
4181
|
-
const
|
|
4271
|
+
const scopedOf$1 = (config) => Effect$1.gen(function* () {
|
|
4182
4272
|
const scope = yield* Effect$1.scope;
|
|
4183
4273
|
return pooledVmRunner(config, scope);
|
|
4184
4274
|
});
|
|
4275
|
+
const VmRunners = Blueprint.make()(TypeId$4).steps({
|
|
4276
|
+
steps: {},
|
|
4277
|
+
targets: { scoped: scopedOf$1 }
|
|
4278
|
+
});
|
|
4279
|
+
const vmTestRunner = (config) => VmRunners.of(config).scoped;
|
|
4185
4280
|
//#endregion
|
|
4186
|
-
//#region src/read-project.
|
|
4281
|
+
//#region src/read-project.parts.ts
|
|
4187
4282
|
const ALWAYS_IGNORE = Object.freeze([
|
|
4188
4283
|
"node_modules",
|
|
4189
4284
|
".git",
|
|
@@ -4596,7 +4691,7 @@ const readProjectCommand = (input) => Effect$1.gen(function* () {
|
|
|
4596
4691
|
const mutatePatterns = input.options.mutate;
|
|
4597
4692
|
const { testFileIgnores, testFilePatterns } = testFileSelectionOf(input.options);
|
|
4598
4693
|
const inputFileNames = yield* resolveInputFileNames(ignoreRulesOf(input.options), input.basePath);
|
|
4599
|
-
const defaults = yield*
|
|
4694
|
+
const defaults = yield* defaultOptions;
|
|
4600
4695
|
const decision = selectFiles(selectionOf$1(inputFileNames, mutatePatterns, testFilePatterns, testFileIgnores, input.basePath, input.targetMutatePatterns));
|
|
4601
4696
|
yield* Boolean.match(stringArrayEquivalence(mutatePatterns, defaults.mutate), {
|
|
4602
4697
|
onTrue: () => Effect$1.void,
|
|
@@ -4619,7 +4714,7 @@ const readProjectCommand = (input) => Effect$1.gen(function* () {
|
|
|
4619
4714
|
testFiles: [...decision.testFiles]
|
|
4620
4715
|
});
|
|
4621
4716
|
});
|
|
4622
|
-
const discardLogOf = (command, discard) => Boolean.match(command.incremental, {
|
|
4717
|
+
const discardLogOf = ({ command, discard }) => Boolean.match(command.incremental, {
|
|
4623
4718
|
onFalse: () => Effect$1.void,
|
|
4624
4719
|
onTrue: () => Option$1.match(Option$1.fromUndefinedOr(command.contents), {
|
|
4625
4720
|
onNone: () => Effect$1.void,
|
|
@@ -4629,15 +4724,26 @@ const discardLogOf = (command, discard) => Boolean.match(command.incremental, {
|
|
|
4629
4724
|
})
|
|
4630
4725
|
})
|
|
4631
4726
|
});
|
|
4632
|
-
const projectOf = (command, report) => ({
|
|
4727
|
+
const projectOf = ({ command, report }) => ({
|
|
4633
4728
|
options: command.options,
|
|
4634
4729
|
targetMutatePatterns: command.targetMutatePatterns,
|
|
4635
4730
|
basePath: command.basePath,
|
|
4636
4731
|
project: makeProject(command.fileDescriptions, report, command.testFiles)
|
|
4637
4732
|
});
|
|
4733
|
+
//#endregion
|
|
4734
|
+
//#region src/read-project.cell.ts
|
|
4638
4735
|
const readProjectCell = Sandwich.named("stryker.project_read")(readProjectCommand).decide(admitIncrementalReport).write({
|
|
4639
|
-
IncrementalReportKeep: (keep, command) => Effect$1.succeed(projectOf(
|
|
4640
|
-
|
|
4736
|
+
IncrementalReportKeep: (keep, command) => Effect$1.succeed(projectOf({
|
|
4737
|
+
command,
|
|
4738
|
+
report: keep.report
|
|
4739
|
+
})),
|
|
4740
|
+
IncrementalReportDiscard: (discard, command) => Effect$1.as(discardLogOf({
|
|
4741
|
+
command,
|
|
4742
|
+
discard
|
|
4743
|
+
}), projectOf({
|
|
4744
|
+
command,
|
|
4745
|
+
report: void 0
|
|
4746
|
+
})),
|
|
4641
4747
|
CommandRejected: ({ issue }) => Effect$1.fail(badArgument({
|
|
4642
4748
|
module: "stryker-js",
|
|
4643
4749
|
method: "incremental-report.cell",
|
|
@@ -5006,7 +5112,7 @@ const PriorReportDocument = S.Struct({
|
|
|
5006
5112
|
}))
|
|
5007
5113
|
});
|
|
5008
5114
|
//#endregion
|
|
5009
|
-
//#region src/Survivors/Survivors.
|
|
5115
|
+
//#region src/Survivors/Survivors.parts.ts
|
|
5010
5116
|
const DEFAULT_SURVIVORS_PRIOR_REPORT = "reports/mutation-report.json";
|
|
5011
5117
|
const EMPTY_CONFIG = {};
|
|
5012
5118
|
const hashContent = (content) => bytesToHex(sha256(utf8ToBytes(content)));
|
|
@@ -5035,9 +5141,9 @@ const reportMutantToMutant = (file, mutant, resolveAbsolutePath, relativize) =>
|
|
|
5035
5141
|
};
|
|
5036
5142
|
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
5143
|
const resolveAbsolutePathOf = (basePath) => (file) => `${basePath}/${file}`;
|
|
5038
|
-
const resolveSurvivorsRunOptions = (
|
|
5144
|
+
const resolveSurvivorsRunOptions = (input) => readConfig(input.cliOptions, {
|
|
5039
5145
|
command: "run",
|
|
5040
|
-
mode
|
|
5146
|
+
mode: input.mode
|
|
5041
5147
|
});
|
|
5042
5148
|
const priorReportPathOf = (resolved) => Option$1.getOrElse(Option$1.filter(Option$1.fromUndefinedOr(resolved["survivorsPriorReport"]), Predicate$1.isString), () => DEFAULT_SURVIVORS_PRIOR_REPORT);
|
|
5043
5149
|
const readPriorReport = (priorReportPath) => Effect$1.flatMap(FileSystem.FileSystem, (fs) => fs.readFileString(priorReportPath).pipe(Effect$1.map((text) => ({
|
|
@@ -5060,14 +5166,11 @@ const readSourceFile = (file) => Effect$1.flatMap(FileSystem.FileSystem, (fs) =>
|
|
|
5060
5166
|
}))));
|
|
5061
5167
|
const SOURCE_HASH_CONCURRENCY = 24;
|
|
5062
5168
|
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, {
|
|
5169
|
+
const survivorsRawOf = (input) => {
|
|
5170
|
+
const { read, resolvedOptions, priorReportPath, basePath, sourceContentHashes } = input;
|
|
5171
|
+
const relativize = (fileName) => RelativeNormalizedFileName.fromAbsolute(fileName, basePath).fileName;
|
|
5172
|
+
const resolveAbsolutePath = resolveAbsolutePathOf(basePath);
|
|
5173
|
+
return Boolean$1.match(read.found, {
|
|
5071
5174
|
onFalse: () => Effect$1.succeed({
|
|
5072
5175
|
currentConfig: resolvedOptions,
|
|
5073
5176
|
frameworkVersion: StrykerPackage.version,
|
|
@@ -5095,6 +5198,22 @@ Sandwich.named("stryker.survivors_admission")((input) => Effect$1.gen(function*
|
|
|
5095
5198
|
})
|
|
5096
5199
|
}))
|
|
5097
5200
|
});
|
|
5201
|
+
};
|
|
5202
|
+
Sandwich.named("stryker.survivors_admission")((input) => Effect$1.gen(function* () {
|
|
5203
|
+
const resolvedOptions = yield* resolveSurvivorsRunOptions({
|
|
5204
|
+
cliOptions: input.cliOptions,
|
|
5205
|
+
mode: input.mode
|
|
5206
|
+
});
|
|
5207
|
+
const priorReportPath = priorReportPathOf(resolvedOptions);
|
|
5208
|
+
const read = yield* readPriorReport(priorReportPath);
|
|
5209
|
+
const sourceContentHashes = yield* currentSourceHashesFor(priorReportFileKeys(read.raw));
|
|
5210
|
+
return yield* survivorsRawOf({
|
|
5211
|
+
read,
|
|
5212
|
+
resolvedOptions,
|
|
5213
|
+
priorReportPath,
|
|
5214
|
+
basePath: input.basePath,
|
|
5215
|
+
sourceContentHashes
|
|
5216
|
+
});
|
|
5098
5217
|
})).decide(admitSurvivorsRun).write({
|
|
5099
5218
|
Admitted: (admitted, raw) => Effect$1.map(S.decodeEffect(Admitted)(admitted), (admission) => ({
|
|
5100
5219
|
admission,
|
|
@@ -5490,7 +5609,7 @@ const emitHelpEnvelope = (stream, help) => Queue.offer(stream.queue, HelpRendere
|
|
|
5490
5609
|
const helpPayload = (ok, captured) => Option$1.filter(Option$1.some(captured), () => ok.help || captured.length > 0);
|
|
5491
5610
|
const emitNullScoreVerdictWhenOpen = (stream, mode, basePath, pathService) => Effect$1.andThen(stream.isOpen, (open) => Boolean$1.match(open, {
|
|
5492
5611
|
onTrue: () => Effect$1.gen(function* () {
|
|
5493
|
-
const defaults = yield*
|
|
5612
|
+
const defaults = yield* defaultOptions;
|
|
5494
5613
|
yield* emitNullScoreVerdict({
|
|
5495
5614
|
stream,
|
|
5496
5615
|
mode,
|
|
@@ -5612,6 +5731,10 @@ var DryRunError = class extends S.TaggedError()("DryRunError", {
|
|
|
5612
5731
|
stage: S.Literals(["dryRun", "dryRunNoTests"]),
|
|
5613
5732
|
reason: S.String
|
|
5614
5733
|
}) {};
|
|
5734
|
+
var FailedTestSummary = class extends S.Class("FailedTestSummary")({
|
|
5735
|
+
name: S.String,
|
|
5736
|
+
failureMessage: S.String
|
|
5737
|
+
}) {};
|
|
5615
5738
|
var DryRunCommand = class extends S.TaggedClass()("DryRunCommand", {
|
|
5616
5739
|
status: S.Literals([
|
|
5617
5740
|
"Complete",
|
|
@@ -5620,6 +5743,7 @@ var DryRunCommand = class extends S.TaggedClass()("DryRunCommand", {
|
|
|
5620
5743
|
]),
|
|
5621
5744
|
testCount: S.Finite,
|
|
5622
5745
|
failedTestCount: S.Finite,
|
|
5746
|
+
failedTests: S.Array(FailedTestSummary),
|
|
5623
5747
|
allowEmpty: S.Boolean,
|
|
5624
5748
|
errorMessage: S.optional(S.String),
|
|
5625
5749
|
reason: S.optional(S.String)
|
|
@@ -5637,7 +5761,8 @@ var DryRunPassed = class extends S.TaggedClass()("DryRunPassed", { testCount: S.
|
|
|
5637
5761
|
};
|
|
5638
5762
|
var DryRunFailed = class extends S.TaggedClass()("DryRunFailed", {
|
|
5639
5763
|
testCount: S.Finite,
|
|
5640
|
-
failedTestCount: S.Finite
|
|
5764
|
+
failedTestCount: S.Finite,
|
|
5765
|
+
failedTests: S.Array(FailedTestSummary)
|
|
5641
5766
|
}) {
|
|
5642
5767
|
[DryRunDecisionTypeId] = DryRunDecisionTypeId;
|
|
5643
5768
|
};
|
|
@@ -5648,13 +5773,15 @@ const completeOutcomeOf = (command) => Match.value(command).pipe(Match.when({
|
|
|
5648
5773
|
const decideComplete = (command) => Match.value({
|
|
5649
5774
|
outcome: completeOutcomeOf(command),
|
|
5650
5775
|
testCount: command.testCount,
|
|
5651
|
-
failedTestCount: command.failedTestCount
|
|
5776
|
+
failedTestCount: command.failedTestCount,
|
|
5777
|
+
failedTests: command.failedTests
|
|
5652
5778
|
}).pipe(Match.when({ outcome: "noTests" }, () => Result.fail(DryRunError.make({
|
|
5653
5779
|
stage: "dryRunNoTests",
|
|
5654
5780
|
reason: "No tests were executed. Stryker will exit prematurely. Please check your configuration."
|
|
5655
|
-
}))), Match.when({ outcome: "failed" }, ({ testCount, failedTestCount }) => Result.succeed(DryRunFailed.make({
|
|
5781
|
+
}))), Match.when({ outcome: "failed" }, ({ testCount, failedTestCount, failedTests }) => Result.succeed(DryRunFailed.make({
|
|
5656
5782
|
testCount,
|
|
5657
|
-
failedTestCount
|
|
5783
|
+
failedTestCount,
|
|
5784
|
+
failedTests
|
|
5658
5785
|
}))), Match.when({ outcome: "passed" }, ({ testCount }) => Result.succeed(DryRunPassed.make({ testCount }))), Match.exhaustive);
|
|
5659
5786
|
const reasonOrDefault = (reason, fallback) => Match.value(reason).pipe(Match.when(void 0, () => fallback), Match.orElse((present) => present));
|
|
5660
5787
|
const decide$5 = (command) => Match.value(command.status).pipe(Match.when("Error", () => Result.fail(DryRunError.make({
|
|
@@ -5704,7 +5831,43 @@ var PluginLoadRefusedError = class extends Schema.TaggedError()("PluginLoadRefus
|
|
|
5704
5831
|
}
|
|
5705
5832
|
};
|
|
5706
5833
|
//#endregion
|
|
5707
|
-
//#region src/
|
|
5834
|
+
//#region src/Sandbox.handle.ts
|
|
5835
|
+
const TypeId$3 = Symbol.for("~systemfsoftware/stryker-js/Sandbox");
|
|
5836
|
+
const SandboxHandle = Handle.make()(TypeId$3);
|
|
5837
|
+
SandboxHandle.is;
|
|
5838
|
+
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}` }))));
|
|
5839
|
+
const withoutLeadingSeparator = (suffix) => Boolean$1.match(suffix.startsWith("/"), {
|
|
5840
|
+
onTrue: () => suffix.slice(1),
|
|
5841
|
+
onFalse: () => suffix
|
|
5842
|
+
});
|
|
5843
|
+
const relativeToBase = (resolvedSandbox, resolvedWorking, base, pathService) => {
|
|
5844
|
+
const trimmed = withoutLeadingSeparator(resolvedSandbox.slice(resolvedWorking.length));
|
|
5845
|
+
return Boolean$1.match(trimmed.length === 0, {
|
|
5846
|
+
onTrue: () => base,
|
|
5847
|
+
onFalse: () => pathService.join(base, trimmed)
|
|
5848
|
+
});
|
|
5849
|
+
};
|
|
5850
|
+
const originalFileNameOf = (sandboxFileName, workingDirectory, base, pathService) => {
|
|
5851
|
+
const resolvedSandbox = pathService.resolve(sandboxFileName);
|
|
5852
|
+
const resolvedWorking = pathService.resolve(workingDirectory);
|
|
5853
|
+
return Boolean$1.match(resolvedSandbox.startsWith(resolvedWorking), {
|
|
5854
|
+
onTrue: () => relativeToBase(resolvedSandbox, resolvedWorking, base, pathService),
|
|
5855
|
+
onFalse: () => resolvedSandbox.replace(resolvedWorking, base)
|
|
5856
|
+
});
|
|
5857
|
+
};
|
|
5858
|
+
const make$1 = (options) => SandboxHandle.make({ workingDirectory: options.workingDirectory }, {
|
|
5859
|
+
fileMap: options.fileMap,
|
|
5860
|
+
basePath: options.basePath,
|
|
5861
|
+
pathService: options.pathService
|
|
5862
|
+
});
|
|
5863
|
+
const sandboxFileFor = dual(2, (self, fileName) => sandboxFileNameOf(SandboxHandle.slot(self).fileMap, fileName));
|
|
5864
|
+
const originalFileFor = dual(2, (self, sandboxFileName) => {
|
|
5865
|
+
const slot = SandboxHandle.slot(self);
|
|
5866
|
+
return originalFileNameOf(sandboxFileName, self.workingDirectory, slot.basePath, slot.pathService);
|
|
5867
|
+
});
|
|
5868
|
+
//#endregion
|
|
5869
|
+
//#region src/TestRunner.blueprint.ts
|
|
5870
|
+
const TypeId$2 = Symbol.for("~systemfsoftware/stryker-js/TestRunner");
|
|
5708
5871
|
const toRunnerBootFailure = (runnerName) => (error) => Match.value(error).pipe(Match.tag("WorkerBootTimeoutError", (timeout) => TestRunner_exports.TestRunnerFailed.make({
|
|
5709
5872
|
runnerName,
|
|
5710
5873
|
phase: "init",
|
|
@@ -5727,7 +5890,7 @@ const toRunnerFailure = (runnerName, phase) => (error) => Match.value(error).pip
|
|
|
5727
5890
|
* `Pool.invalidate` and the crash-retry combinator can only act on a failure they
|
|
5728
5891
|
* can see.
|
|
5729
5892
|
*/
|
|
5730
|
-
const
|
|
5893
|
+
const scopedOf = (params) => Effect$1.gen(function* () {
|
|
5731
5894
|
const runnerName = Match.value(params.options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
5732
5895
|
const execArgv = Match.value(params.options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => Match.value(runner.nodeArgs).pipe(Match.when(Match.undefined, () => params.options.testRunnerNodeArgs), Match.orElse((args) => args))), Match.orElse(() => params.options.testRunnerNodeArgs));
|
|
5733
5896
|
const client = yield* makeWorkerClient({
|
|
@@ -5750,6 +5913,11 @@ const makeChildProcessTestRunner = (params) => Effect$1.gen(function* () {
|
|
|
5750
5913
|
mutantRun: (options) => client.mutantRun({ options }).pipe(Effect$1.mapError(toRunnerFailure(runnerName, "mutantRun")))
|
|
5751
5914
|
});
|
|
5752
5915
|
});
|
|
5916
|
+
const TestRunners = Blueprint.make()(TypeId$2).steps({
|
|
5917
|
+
steps: {},
|
|
5918
|
+
targets: { scoped: scopedOf }
|
|
5919
|
+
});
|
|
5920
|
+
const makeChildProcessTestRunner = (params) => TestRunners.of(params).scoped;
|
|
5753
5921
|
const commandRunnerEffect = (context) => ChildProcessSpawner.ChildProcessSpawner.pipe(Effect$1.map((spawner) => commandRunner(context, spawner).pipe(withTimeout, withRetry)));
|
|
5754
5922
|
const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option$1.some(commandRunnerEffect(context))), Match.when(isVmRunner, () => Option$1.some(vmTestRunner({
|
|
5755
5923
|
testFiles: context.testFiles,
|
|
@@ -5911,8 +6079,8 @@ const resolveConfiguredPlugin = Workflow.make({
|
|
|
5911
6079
|
decide: decide$4
|
|
5912
6080
|
});
|
|
5913
6081
|
//#endregion
|
|
5914
|
-
//#region src/run/dry-run.
|
|
5915
|
-
const sandboxPathsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) =>
|
|
6082
|
+
//#region src/run/dry-run.parts.ts
|
|
6083
|
+
const sandboxPathsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => sandboxFileFor(sandbox, fileName)));
|
|
5916
6084
|
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 })));
|
|
5917
6085
|
const workerSpawnOf$1 = (stage, loaded, kind, configured) => Effect$1.mapError(Effect$1.fromResult(resolveConfiguredPlugin(WorkerSpawnCommand.make({
|
|
5918
6086
|
sources: loaded.pluginSources,
|
|
@@ -5936,11 +6104,16 @@ const resolveDryRunFiles = (command) => Effect$1.fromResult(buildDryRunFiles(com
|
|
|
5936
6104
|
reason: "Failed to resolve sandbox file",
|
|
5937
6105
|
cause
|
|
5938
6106
|
})));
|
|
6107
|
+
const failedTestSummariesOf = (tests) => tests.filter((test) => test.status === "failed").map((test) => FailedTestSummary.make({
|
|
6108
|
+
name: test.name,
|
|
6109
|
+
failureMessage: test.failureMessage
|
|
6110
|
+
}));
|
|
5939
6111
|
const commandEncodedComplete = (complete, allowEmpty) => ({
|
|
5940
6112
|
_tag: "DryRunCommand",
|
|
5941
6113
|
status: "Complete",
|
|
5942
6114
|
testCount: complete.tests.length,
|
|
5943
6115
|
failedTestCount: complete.tests.filter((test) => test.status === "failed").length,
|
|
6116
|
+
failedTests: failedTestSummariesOf(complete.tests),
|
|
5944
6117
|
allowEmpty
|
|
5945
6118
|
});
|
|
5946
6119
|
const commandEncodedFailed = (failed, allowEmpty) => ({
|
|
@@ -5948,6 +6121,7 @@ const commandEncodedFailed = (failed, allowEmpty) => ({
|
|
|
5948
6121
|
status: "Error",
|
|
5949
6122
|
testCount: 0,
|
|
5950
6123
|
failedTestCount: 0,
|
|
6124
|
+
failedTests: [],
|
|
5951
6125
|
allowEmpty,
|
|
5952
6126
|
errorMessage: failed.errorMessage
|
|
5953
6127
|
});
|
|
@@ -5956,6 +6130,7 @@ const commandEncodedTimedOut = (timedOut, allowEmpty) => ({
|
|
|
5956
6130
|
status: "Timeout",
|
|
5957
6131
|
testCount: 0,
|
|
5958
6132
|
failedTestCount: 0,
|
|
6133
|
+
failedTests: [],
|
|
5959
6134
|
allowEmpty,
|
|
5960
6135
|
...Option$1.match(Option$1.fromNullishOr(timedOut.reason), {
|
|
5961
6136
|
onNone: () => ({}),
|
|
@@ -5987,7 +6162,7 @@ const totalTestTime = (tests) => tests.reduce((total, test) => total + test.time
|
|
|
5987
6162
|
const overheadMillisOf = (grossMillis, tests) => Math.max(0, grossMillis - totalTestTime(tests));
|
|
5988
6163
|
const withOriginalFileName = (test, prev) => Match.value(test.fileName).pipe(Match.when(Predicate$1.isString, (fileName) => ({
|
|
5989
6164
|
...test,
|
|
5990
|
-
fileName: prev.sandbox
|
|
6165
|
+
fileName: originalFileFor(prev.sandbox, fileName)
|
|
5991
6166
|
})), Match.orElse(() => test));
|
|
5992
6167
|
const withOriginalFileNames = (tests, prev) => tests.map((test) => withOriginalFileName(test, prev));
|
|
5993
6168
|
const ZERO = 0;
|
|
@@ -6110,20 +6285,32 @@ const writeDryRunPassed = (raw) => withPhaseSpan("dryRun", {}, () => Effect$1.ge
|
|
|
6110
6285
|
yield* phaseEntered("dry-run");
|
|
6111
6286
|
return yield* completeDryRunPassed(raw);
|
|
6112
6287
|
}));
|
|
6113
|
-
const
|
|
6288
|
+
const FAILED_TESTS_REASON = "There were failed tests in the initial test run.";
|
|
6289
|
+
const failedTestsDetail = (failedTests) => failedTests.map((test) => ` ${test.name}${test.failureMessage.length > 0 ? `: ${test.failureMessage}` : ""}`).join("\n");
|
|
6290
|
+
const reasonWithFailedTests = (detail) => detail.length > 0 ? `${FAILED_TESTS_REASON}\n${detail}` : FAILED_TESTS_REASON;
|
|
6291
|
+
const writeDryRunFailed = ({ testCount, failedTestCount, failedTests }) => withPhaseSpan("dryRun", {}, () => Effect$1.gen(function* () {
|
|
6114
6292
|
yield* phaseEntered("dry-run");
|
|
6293
|
+
const detail = failedTestsDetail(failedTests);
|
|
6294
|
+
yield* Effect$1.logError(`Initial test run failed. ${failedTestCount} of ${testCount} test(s) failed:\n${detail}`);
|
|
6115
6295
|
return yield* StageError.make({
|
|
6116
6296
|
stage: "dryRun",
|
|
6117
|
-
reason:
|
|
6297
|
+
reason: reasonWithFailedTests(detail),
|
|
6118
6298
|
cause: DryRunFailed.make({
|
|
6119
6299
|
testCount,
|
|
6120
|
-
failedTestCount
|
|
6300
|
+
failedTestCount,
|
|
6301
|
+
failedTests
|
|
6121
6302
|
})
|
|
6122
6303
|
});
|
|
6123
6304
|
}));
|
|
6305
|
+
//#endregion
|
|
6306
|
+
//#region src/run/dry-run.cell.ts
|
|
6124
6307
|
const dryRunCell = Sandwich.named("stryker.dry_run")(readDryRun).decide(dryRun).write({
|
|
6125
6308
|
DryRunPassed: (_decision, raw) => writeDryRunPassed(raw),
|
|
6126
|
-
DryRunFailed: ({ testCount, failedTestCount },
|
|
6309
|
+
DryRunFailed: ({ testCount, failedTestCount, failedTests }, _raw) => writeDryRunFailed({
|
|
6310
|
+
testCount,
|
|
6311
|
+
failedTestCount,
|
|
6312
|
+
failedTests
|
|
6313
|
+
}),
|
|
6127
6314
|
DryRunError: ({ stage, reason }) => Effect$1.fail(StageError.make({
|
|
6128
6315
|
stage,
|
|
6129
6316
|
reason,
|
|
@@ -6406,37 +6593,6 @@ function buildErrorMessage({ type, sourceText, position }) {
|
|
|
6406
6593
|
return `Cannot parse JSONC: unexpected token "${token}" in JSONC at position ${position}`;
|
|
6407
6594
|
}
|
|
6408
6595
|
//#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
6596
|
//#region src/Sandbox.schema.ts
|
|
6441
6597
|
/**
|
|
6442
6598
|
* Sandbox.schema — declarations for the Sandbox capability.
|
|
@@ -6463,7 +6619,7 @@ const TsConfigSchema = Schema.StructWithRest(Schema.Struct({
|
|
|
6463
6619
|
/** A tsconfig `extends` entry list: the array form of `extends`. */
|
|
6464
6620
|
const ExtendsArraySchema = Schema.Array(Schema.String);
|
|
6465
6621
|
//#endregion
|
|
6466
|
-
//#region src/Sandbox.
|
|
6622
|
+
//#region src/Sandbox.blueprint.ts
|
|
6467
6623
|
const combinePreprocessors = (preprocessors) => (project) => Effect$1.forEach(preprocessors, (pre) => pre(project), { discard: true });
|
|
6468
6624
|
const mergeUpdatedFile = (project, updated) => {
|
|
6469
6625
|
MutableHashMap.set(project.files, updated.name, updated);
|
|
@@ -6723,13 +6879,13 @@ const symlinkNodeModules = (options, workingDirectory, basePath, pathService) =>
|
|
|
6723
6879
|
onFalse: () => Effect$1.void
|
|
6724
6880
|
});
|
|
6725
6881
|
});
|
|
6726
|
-
const acquireSandbox = (
|
|
6727
|
-
const { options, project, workingDirectory, backupDirectory, basePath } =
|
|
6882
|
+
const acquireSandbox = (spec) => Effect$1.gen(function* () {
|
|
6883
|
+
const { options, project, workingDirectory, backupDirectory, basePath } = spec;
|
|
6728
6884
|
yield* Scope.Scope;
|
|
6729
6885
|
const pathService = yield* Path.Path;
|
|
6730
6886
|
yield* announceSandbox(options, workingDirectory, backupDirectory, basePath, pathService);
|
|
6731
6887
|
yield* Effect$1.when(restoreOriginalFiles(workingDirectory, backupDirectory, basePath), Effect$1.succeed(hasBackupToRestore(options, backupDirectory)));
|
|
6732
|
-
yield* combinePreprocessors([createPreprocessor(options, basePath,
|
|
6888
|
+
yield* combinePreprocessors([createPreprocessor(options, basePath, spec.formatRegistry), ...spec.preprocessors])(project).pipe(Effect$1.mapError((cause) => StrykerError.make({
|
|
6733
6889
|
message: "Sandbox preprocessor failed",
|
|
6734
6890
|
cause
|
|
6735
6891
|
})));
|
|
@@ -6754,31 +6910,22 @@ const acquireSandbox = (state) => Effect$1.gen(function* () {
|
|
|
6754
6910
|
pathService
|
|
6755
6911
|
});
|
|
6756
6912
|
});
|
|
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,
|
|
6913
|
+
const TypeId$1 = Symbol.for("~systemfsoftware/stryker-js/Sandbox");
|
|
6914
|
+
const Sandboxes = Blueprint.make()(TypeId$1).steps({
|
|
6915
|
+
steps: { withPreprocessor: (spec, preprocessor) => ({
|
|
6916
|
+
...spec,
|
|
6917
|
+
preprocessors: [...spec.preprocessors, preprocessor]
|
|
6918
|
+
}) },
|
|
6919
|
+
targets: {
|
|
6920
|
+
scoped: (spec) => acquireSandbox(spec),
|
|
6921
|
+
layer: (spec) => (service) => Layer.effect(service)(acquireSandbox(spec))
|
|
6922
|
+
}
|
|
6923
|
+
});
|
|
6924
|
+
const make = (spec) => Sandboxes.of({
|
|
6925
|
+
...spec,
|
|
6779
6926
|
preprocessors: []
|
|
6780
6927
|
});
|
|
6781
|
-
|
|
6928
|
+
Sandboxes.operations.withPreprocessor;
|
|
6782
6929
|
const makeSandbox = (input) => make(input).scoped;
|
|
6783
6930
|
//#endregion
|
|
6784
6931
|
//#region src/run/explain-file-skip.workflow.ts
|
|
@@ -6847,13 +6994,13 @@ const explainFileSkip = Workflow.make({
|
|
|
6847
6994
|
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
6995
|
});
|
|
6849
6996
|
//#endregion
|
|
6850
|
-
//#region src/run/instrument.
|
|
6851
|
-
const offerSkipsIfAny = (
|
|
6997
|
+
//#region src/run/instrument.parts.ts
|
|
6998
|
+
const offerSkipsIfAny = (input) => Boolean$1.match(input.skipped.length === 0, {
|
|
6852
6999
|
onTrue: () => Effect$1.void,
|
|
6853
7000
|
onFalse: () => Effect$1.gen(function* () {
|
|
6854
|
-
const files = skipped.map((skip) => Result.match(explainFileSkip(ExplainFileSkipCommand.make({
|
|
7001
|
+
const files = input.skipped.map((skip) => Result.match(explainFileSkip(ExplainFileSkipCommand.make({
|
|
6855
7002
|
extension: skip.extension,
|
|
6856
|
-
claimants: [...claimants]
|
|
7003
|
+
claimants: [...input.claimants]
|
|
6857
7004
|
})), {
|
|
6858
7005
|
onFailure: absurd,
|
|
6859
7006
|
onSuccess: (explained) => ({
|
|
@@ -6866,11 +7013,40 @@ const offerSkipsIfAny = (skipped, claimants) => Boolean$1.match(skipped.length =
|
|
|
6866
7013
|
yield* Queue.offer(queue, SkippedReported.make({ files }));
|
|
6867
7014
|
})
|
|
6868
7015
|
});
|
|
7016
|
+
const sandboxDirectoriesOf = (input) => Boolean$1.match(input.command.options.inPlace, {
|
|
7017
|
+
onTrue: () => ({
|
|
7018
|
+
workingDirectory: input.basePath,
|
|
7019
|
+
backupDirectory: input.command.temporaryDirectoryPath
|
|
7020
|
+
}),
|
|
7021
|
+
onFalse: () => ({
|
|
7022
|
+
workingDirectory: input.command.temporaryDirectoryPath,
|
|
7023
|
+
backupDirectory: ""
|
|
7024
|
+
})
|
|
7025
|
+
});
|
|
7026
|
+
const mergeInstrumentedFile = (input) => {
|
|
7027
|
+
const files = MutableHashMap.fromIterable(input.project.files);
|
|
7028
|
+
MutableHashMap.set(files, input.file.name, input.file);
|
|
7029
|
+
const filesToMutate = MutableHashMap.fromIterable(input.project.filesToMutate);
|
|
7030
|
+
Boolean$1.match(input.file.mutate !== false, {
|
|
7031
|
+
onTrue: () => MutableHashMap.set(filesToMutate, input.file.name, input.file),
|
|
7032
|
+
onFalse: () => MutableHashMap.remove(filesToMutate, input.file.name)
|
|
7033
|
+
});
|
|
7034
|
+
return {
|
|
7035
|
+
...input.project,
|
|
7036
|
+
files,
|
|
7037
|
+
filesToMutate
|
|
7038
|
+
};
|
|
7039
|
+
};
|
|
7040
|
+
//#endregion
|
|
7041
|
+
//#region src/run/instrument.cell.ts
|
|
6869
7042
|
const enteringInstrumentPhase = (raw, body) => withPhaseSpan("instrument", { fileCount: raw.filesToMutate.length }, () => Effect$1.gen(function* () {
|
|
6870
7043
|
yield* phaseEntered("instrument");
|
|
6871
7044
|
return yield* body;
|
|
6872
7045
|
}));
|
|
6873
|
-
const writeInstrument = (raw) => enteringInstrumentPhase(raw, Effect$1.as(offerSkipsIfAny(
|
|
7046
|
+
const writeInstrument = (raw) => enteringInstrumentPhase(raw, Effect$1.as(offerSkipsIfAny({
|
|
7047
|
+
skipped: raw.instrumentResult.skipped,
|
|
7048
|
+
claimants: raw.prev.frameworkClaimants
|
|
7049
|
+
}), {
|
|
6874
7050
|
...raw.prev,
|
|
6875
7051
|
project: raw.instrumentedProject,
|
|
6876
7052
|
mutants: raw.instrumentResult.mutants,
|
|
@@ -6880,37 +7056,13 @@ const writeInstrument = (raw) => enteringInstrumentPhase(raw, Effect$1.as(offerS
|
|
|
6880
7056
|
checkers: raw.concurrency.checkers
|
|
6881
7057
|
}
|
|
6882
7058
|
}));
|
|
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, {
|
|
7059
|
+
const withInstrumentedFiles = (project, instrumented) => Arr.reduce([...instrumented], project, (current, { name, content }) => Option$1.getOrElse(Option$1.map(MutableHashMap.get(current.files, name), (existing) => mergeInstrumentedFile({
|
|
7060
|
+
project: current,
|
|
7061
|
+
file: {
|
|
6910
7062
|
...existing,
|
|
6911
7063
|
content
|
|
6912
|
-
}
|
|
6913
|
-
}));
|
|
7064
|
+
}
|
|
7065
|
+
})), () => current));
|
|
6914
7066
|
const instrumentCell = Sandwich.named("stryker.instrument")((command) => Effect$1.gen(function* () {
|
|
6915
7067
|
yield* Scope.Scope;
|
|
6916
7068
|
const env = yield* RunEnvironment;
|
|
@@ -6934,7 +7086,10 @@ const instrumentCell = Sandwich.named("stryker.instrument")((command) => Effect$
|
|
|
6934
7086
|
cause
|
|
6935
7087
|
})));
|
|
6936
7088
|
const instrumentedProject = withInstrumentedFiles(command.project, instrumentResult.files);
|
|
6937
|
-
const directories = sandboxDirectoriesOf(
|
|
7089
|
+
const directories = sandboxDirectoriesOf({
|
|
7090
|
+
command,
|
|
7091
|
+
basePath: env.basePath
|
|
7092
|
+
});
|
|
6938
7093
|
const sandbox = yield* makeSandbox({
|
|
6939
7094
|
options: command.options,
|
|
6940
7095
|
project: instrumentedProject,
|
|
@@ -7028,13 +7183,18 @@ const admitMutationTest = Workflow.make({
|
|
|
7028
7183
|
decide: decide$2
|
|
7029
7184
|
});
|
|
7030
7185
|
//#endregion
|
|
7031
|
-
//#region src/Checker/Checker.
|
|
7186
|
+
//#region src/Checker/Checker.blueprint.ts
|
|
7187
|
+
const TypeId = Symbol.for("~systemfsoftware/stryker-js/CheckerBlueprint");
|
|
7032
7188
|
const checkerProcessCrashes = Metric.counter("stryker.checker.process_crashes", {
|
|
7033
7189
|
description: "Checker worker processes that never became usable",
|
|
7034
7190
|
incremental: true
|
|
7035
7191
|
});
|
|
7036
7192
|
const TEMP_DIR_PREFIX = "stryker-checker-";
|
|
7037
7193
|
const nodeArgsOf = (options) => Match.value(options.checkers[0]?.nodeArgs).pipe(Match.when(Match.undefined, () => options.checkerNodeArgs), Match.orElse((args) => args));
|
|
7194
|
+
const serviceOf = (handle) => ({
|
|
7195
|
+
check: (checkerName, mutants) => check(handle, checkerName, mutants),
|
|
7196
|
+
group: (checkerName, mutants) => group(handle, checkerName, mutants)
|
|
7197
|
+
});
|
|
7038
7198
|
const acquire = (spec) => Effect$1.gen(function* () {
|
|
7039
7199
|
const client = yield* makeWorkerClient({
|
|
7040
7200
|
rpcs: Plugin_exports.CheckerRpcs,
|
|
@@ -7044,9 +7204,13 @@ const acquire = (spec) => Effect$1.gen(function* () {
|
|
|
7044
7204
|
execArgv: [...nodeArgsOf(spec.options)],
|
|
7045
7205
|
tempDirPrefix: TEMP_DIR_PREFIX
|
|
7046
7206
|
}).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);
|
|
7207
|
+
return serviceOf(makeCheckerHandle(client));
|
|
7208
|
+
});
|
|
7209
|
+
const Checkers = Blueprint.make()(TypeId).steps({
|
|
7210
|
+
steps: {},
|
|
7211
|
+
targets: { scoped: acquire }
|
|
7048
7212
|
});
|
|
7049
|
-
const scoped = (spec) =>
|
|
7213
|
+
const scoped = (spec) => Checkers.of(spec).scoped;
|
|
7050
7214
|
//#endregion
|
|
7051
7215
|
//#region src/incremental-diff.workflow.ts
|
|
7052
7216
|
const REMEMBERED_STATUS = /* @__PURE__ */ new Set([
|
|
@@ -7351,7 +7515,7 @@ const planMutantTests = Workflow.make({
|
|
|
7351
7515
|
decide
|
|
7352
7516
|
});
|
|
7353
7517
|
//#endregion
|
|
7354
|
-
//#region src/run/mutation-test.
|
|
7518
|
+
//#region src/run/mutation-test.parts.ts
|
|
7355
7519
|
const relativeFileNameOf = (fileName, basePath) => RelativeNormalizedFileName.fromAbsolute(fileName, basePath).fileName;
|
|
7356
7520
|
const readCurrentRelativeFiles = (project, basePath) => Effect$1.gen(function* () {
|
|
7357
7521
|
const entries = yield* (yield* ProjectFiles).readAllOriginal(MutableHashMap.values(project.files));
|
|
@@ -7368,7 +7532,7 @@ const reportingInputOf = (prev, env, results) => ({
|
|
|
7368
7532
|
reporterStage: prev.reporterStage,
|
|
7369
7533
|
formatRegistry: prev.formatRegistry
|
|
7370
7534
|
});
|
|
7371
|
-
const sandboxFilePairsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => Result.map(
|
|
7535
|
+
const sandboxFilePairsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => Result.map(sandboxFileFor(sandbox, fileName), (sandboxFileName) => [fileName, sandboxFileName])));
|
|
7372
7536
|
const sandboxFilesOf = (sandbox, fileNames) => Effect$1.fromResult(sandboxFilePairsOf(sandbox, fileNames)).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
7373
7537
|
stage: "mutationTest",
|
|
7374
7538
|
reason: "Failed to resolve sandbox file",
|
|
@@ -7676,7 +7840,7 @@ const stopWallClock = (result) => Boolean$1.match(wallClockTimeoutStopsRun(resul
|
|
|
7676
7840
|
})),
|
|
7677
7841
|
onFalse: () => Effect$1.void
|
|
7678
7842
|
});
|
|
7679
|
-
const writeMutationTestNoTests =
|
|
7843
|
+
const writeMutationTestNoTests = Effect$1.gen(function* () {
|
|
7680
7844
|
const env = yield* RunEnvironment;
|
|
7681
7845
|
const now = yield* Clock.currentTimeMillis;
|
|
7682
7846
|
const elapsed = Duration.millis(now - env.runStartedAt);
|
|
@@ -7687,7 +7851,7 @@ const writeMutationTestNoTests = () => Effect$1.gen(function* () {
|
|
|
7687
7851
|
verdict: null
|
|
7688
7852
|
};
|
|
7689
7853
|
});
|
|
7690
|
-
const writeMutationTestDryRunOnly =
|
|
7854
|
+
const writeMutationTestDryRunOnly = Effect$1.gen(function* () {
|
|
7691
7855
|
yield* phaseEntered("mutation-test");
|
|
7692
7856
|
yield* Effect$1.logInfo("The dry-run has been completed successfully. No mutations have been executed.");
|
|
7693
7857
|
return {
|
|
@@ -7879,11 +8043,18 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
|
|
|
7879
8043
|
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
7880
8044
|
return outcomeResult;
|
|
7881
8045
|
}).pipe(Effect$1.mapError((cause) => mapMutationTestCause(cause)));
|
|
7882
|
-
const writeMutationTestOutcome = (raw, outcome) => withPhaseSpan("mutationTest", {
|
|
8046
|
+
const writeMutationTestOutcome = ({ raw, outcome }) => withPhaseSpan("mutationTest", {
|
|
7883
8047
|
mutantCount: raw.prev.mutants.length,
|
|
7884
8048
|
skippedMutantCount: partitionPlannable(raw.prev.mutants).dropped.length,
|
|
7885
8049
|
testCount: raw.prev.dryRunResult.tests.length
|
|
7886
8050
|
}, () => outcome);
|
|
8051
|
+
const mapMutationTestCause = (cause) => Match.value({ cause }).pipe(Match.when({ cause: isStageError }, ({ cause }) => cause), Match.orElse(({ cause }) => StageError.make({
|
|
8052
|
+
stage: "mutationTest",
|
|
8053
|
+
reason: "Mutation testing failed",
|
|
8054
|
+
cause
|
|
8055
|
+
})));
|
|
8056
|
+
//#endregion
|
|
8057
|
+
//#region src/run/mutation-test.cell.ts
|
|
7887
8058
|
const mutationTestCell$1 = Sandwich.named("stryker.mutation_test")((command) => Effect$1.gen(function* () {
|
|
7888
8059
|
yield* Scope.Scope;
|
|
7889
8060
|
const prev = command;
|
|
@@ -7896,9 +8067,18 @@ const mutationTestCell$1 = Sandwich.named("stryker.mutation_test")((command) =>
|
|
|
7896
8067
|
prev
|
|
7897
8068
|
};
|
|
7898
8069
|
})).decide(admitMutationTest).write({
|
|
7899
|
-
MutationTestDryRunOnly: (_decision, raw) => writeMutationTestOutcome(
|
|
7900
|
-
|
|
7901
|
-
|
|
8070
|
+
MutationTestDryRunOnly: (_decision, raw) => writeMutationTestOutcome({
|
|
8071
|
+
raw,
|
|
8072
|
+
outcome: writeMutationTestDryRunOnly
|
|
8073
|
+
}),
|
|
8074
|
+
MutationTestNoTests: (_decision, raw) => writeMutationTestOutcome({
|
|
8075
|
+
raw,
|
|
8076
|
+
outcome: writeMutationTestNoTests
|
|
8077
|
+
}),
|
|
8078
|
+
MutationTestProceed: (_decision, raw) => writeMutationTestOutcome({
|
|
8079
|
+
raw,
|
|
8080
|
+
outcome: writeMutationTestProceed(raw)
|
|
8081
|
+
}),
|
|
7902
8082
|
MutationTestError: ({ stage, reason }) => Effect$1.fail(StageError.make({
|
|
7903
8083
|
stage,
|
|
7904
8084
|
reason,
|
|
@@ -7912,11 +8092,6 @@ const mutationTestCell$1 = Sandwich.named("stryker.mutation_test")((command) =>
|
|
|
7912
8092
|
reason: issue
|
|
7913
8093
|
}))
|
|
7914
8094
|
});
|
|
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
8095
|
//#endregion
|
|
7921
8096
|
//#region src/framework-claimant.service.ts
|
|
7922
8097
|
const dependencyNamesOf = (dependencies) => Object.keys(dependencies ?? {});
|
|
@@ -8463,24 +8638,48 @@ const planPrepare = Workflow.make({
|
|
|
8463
8638
|
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
8639
|
});
|
|
8465
8640
|
//#endregion
|
|
8641
|
+
//#region src/run/prepare.parts.ts
|
|
8642
|
+
const announceSummary = (input) => Match.value(input.env.resolvedMode.mode).pipe(Match.when("human", () => announceHumanSummary({
|
|
8643
|
+
allowConsoleColors: input.env.allowConsoleColors,
|
|
8644
|
+
summary: input.summary
|
|
8645
|
+
})), Match.orElse(() => Effect$1.logInfo(input.summary)));
|
|
8646
|
+
const announceHumanSummary = (input) => Boolean$1.match(input.allowConsoleColors, {
|
|
8647
|
+
onTrue: () => Console.log(`${AnsiCode.fields.green.literal}${input.summary}${AnsiCode.fields.reset.literal}`),
|
|
8648
|
+
onFalse: () => Console.log(input.summary)
|
|
8649
|
+
});
|
|
8650
|
+
const STREAM_REPORTER = "progress-stream";
|
|
8651
|
+
const HUMAN_REPORTER = "clear-text";
|
|
8652
|
+
const STDOUT_REPORTERS = {
|
|
8653
|
+
"clear-text": true,
|
|
8654
|
+
"progress": true
|
|
8655
|
+
};
|
|
8656
|
+
const asHumanReporter = (name) => {
|
|
8657
|
+
if (name === STREAM_REPORTER) return HUMAN_REPORTER;
|
|
8658
|
+
return name;
|
|
8659
|
+
};
|
|
8660
|
+
const selectReporters = dual(2, (configured, mode) => Match.value(mode).pipe(Match.when("human", () => [...new Set(configured.map(asHumanReporter))]), Match.when("machine", () => {
|
|
8661
|
+
const permitted = configured.filter((name) => STDOUT_REPORTERS[name] !== true);
|
|
8662
|
+
return Match.value(permitted.includes(STREAM_REPORTER)).pipe(Match.when(true, () => permitted), Match.when(false, () => [...permitted, STREAM_REPORTER]), Match.exhaustive);
|
|
8663
|
+
}), Match.exhaustive));
|
|
8664
|
+
const failOnEmptyProject = (fileCount) => Match.value(fileCount).pipe(Match.when(0, () => Effect$1.fail(StageError.make({
|
|
8665
|
+
stage: "prepare",
|
|
8666
|
+
reason: "No input files found.",
|
|
8667
|
+
cause: PrepareError.make({
|
|
8668
|
+
stage: "prepare",
|
|
8669
|
+
reason: "No input files found."
|
|
8670
|
+
})
|
|
8671
|
+
}))), Match.orElse(() => Effect$1.void));
|
|
8672
|
+
//#endregion
|
|
8466
8673
|
//#region src/run/prepare.cell.ts
|
|
8467
8674
|
const NO_PLUGIN_DESCRIPTORS = [];
|
|
8468
8675
|
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
|
-
});
|
|
8676
|
+
const buildMergedSchema = (core, contributions) => contributions.reduce((merged, contribution) => ({
|
|
8677
|
+
...merged,
|
|
8678
|
+
properties: {
|
|
8679
|
+
...schemaPropertiesOf(merged),
|
|
8680
|
+
...schemaPropertiesOf(contribution)
|
|
8681
|
+
}
|
|
8682
|
+
}), core);
|
|
8484
8683
|
const readPrepare = (command) => Effect$1.gen(function* () {
|
|
8485
8684
|
yield* Scope.Scope;
|
|
8486
8685
|
const env = yield* RunEnvironment;
|
|
@@ -8531,9 +8730,10 @@ const readPrepare = (command) => Effect$1.gen(function* () {
|
|
|
8531
8730
|
}])]);
|
|
8532
8731
|
const frameworkClaimants = yield* installedFrameworkClaimants(env.basePath);
|
|
8533
8732
|
return {
|
|
8733
|
+
now: yield* Clock.currentTimeMillis,
|
|
8534
8734
|
mode: env.resolvedMode.mode,
|
|
8535
8735
|
reporters: [...options.reporters],
|
|
8536
|
-
fileCount:
|
|
8736
|
+
fileCount: pipe(command.project.files, MutableHashMap.size),
|
|
8537
8737
|
availableReporters: [...HashMap.values(reporterChoicesByName)].map((choice) => choice.name),
|
|
8538
8738
|
env,
|
|
8539
8739
|
queue,
|
|
@@ -8548,22 +8748,17 @@ const readPrepare = (command) => Effect$1.gen(function* () {
|
|
|
8548
8748
|
};
|
|
8549
8749
|
});
|
|
8550
8750
|
const writePrepare = (reporters, raw) => withPhaseSpan("prepare", {}, (span) => Effect$1.gen(function* () {
|
|
8551
|
-
const mutateCount =
|
|
8552
|
-
yield* announceSummary(
|
|
8751
|
+
const mutateCount = pipe(raw.project.filesToMutate, MutableHashMap.size);
|
|
8752
|
+
yield* announceSummary({
|
|
8753
|
+
env: raw.env,
|
|
8754
|
+
summary: `Found ${mutateCount} of ${pipe(raw.project.files, MutableHashMap.size)} file(s) to be mutated.`
|
|
8755
|
+
});
|
|
8553
8756
|
yield* validateReporterNames(raw.options.reporters, [...HashMap.values(raw.reporterChoicesByName)].map((choice) => choice.name)).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
8554
8757
|
stage: "prepare",
|
|
8555
8758
|
reason: cause.message,
|
|
8556
8759
|
cause
|
|
8557
8760
|
})));
|
|
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));
|
|
8761
|
+
yield* failOnEmptyProject(pipe(raw.project.files, MutableHashMap.size));
|
|
8567
8762
|
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
8763
|
stage: "prepare",
|
|
8569
8764
|
reason: "Failed to create temporary directory",
|
|
@@ -8572,7 +8767,7 @@ const writePrepare = (reporters, raw) => withPhaseSpan("prepare", {}, (span) =>
|
|
|
8572
8767
|
const reporterInputs = yield* reporterInputsOf(reporters, raw.reporterChoicesByName, raw.loaded, raw.env.basePath, raw.options);
|
|
8573
8768
|
const reporterInit = yield* currentReporterInit(span);
|
|
8574
8769
|
const reporterStage = yield* attachReporterFactories(reporterInputs, raw.options, reporterInit);
|
|
8575
|
-
const now =
|
|
8770
|
+
const { now } = raw;
|
|
8576
8771
|
yield* Queue.offer(raw.queue, PhaseEntered.make({
|
|
8577
8772
|
phase: "prepare",
|
|
8578
8773
|
elapsedMs: now - raw.env.runStartedAt
|
|
@@ -8588,20 +8783,6 @@ const writePrepare = (reporters, raw) => withPhaseSpan("prepare", {}, (span) =>
|
|
|
8588
8783
|
frameworkClaimants: raw.frameworkClaimants
|
|
8589
8784
|
};
|
|
8590
8785
|
}));
|
|
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
8786
|
const prepareCell = Sandwich.named("stryker.prepare")(readPrepare).decide(planPrepare).write({
|
|
8606
8787
|
HumanReporters: ({ reporters }, raw) => writePrepare(reporters, raw),
|
|
8607
8788
|
MachineReporters: ({ reporters }, raw) => writePrepare(reporters, raw),
|
|
@@ -8636,4 +8817,4 @@ const strykerCell = dual((args) => Predicate$1.isObject(args[0]), (options, targ
|
|
|
8636
8817
|
})
|
|
8637
8818
|
})), Effect$1.scoped));
|
|
8638
8819
|
//#endregion
|
|
8639
|
-
export {
|
|
8820
|
+
export { ExtendsStepResolve as $, VerdictMutant as A, FileMatcher as B, mergeConfigs as C, RunEvents as D, IdGenerator as E, makeWorkerClient as F, ConfigFileUnsupportedError as G, ConfigFileInvalidError as H, WorkerLauncher as I, ConfigDocumentSchema as J, createDefaultOptions as K, make$2 as L, MetricsResultFromReport as M, reporterWorkerFactory as N, RunIdentity as O, spawnReporterWorker as P, ExtendsStepRefused as Q, StrykerError as R, initialExtendsStepState as S, RunEnvironment as T, ConfigFileNotFoundError as U, ConfigError as V, ConfigFileUnreadableError as W, ExtendsStepDone as X, ExtendsStepDocumentSchema as Y, ExtendsStepRead as Z, readConfig as _, RunEventDrainLive as a, extendsPropertySchema as at, forkCoreSchema as b, isVmRunner as c, checkGroupedPlans as ct, nodePlatformLayer as d, WorkerBootTimeoutError as dt, ExtendsStepStateSchema as et, layerWorkerProtocol as f, CheckerAnsweredUnrequested as ft, loadConfigCell as g, classifyWorkerExit as h, RunEventDrain as i, ReadConfigCommand as it, VerdictThresholds as j, VerdictEnvelope as k, vmTestRunner as l, ChildProcessCrashedError as lt, ClassifyWorkerExitDecision as m, strykerCell as n, MergeCommand as nt, makeRunEventStream as o, forkOptionsSchema as ot, ClassifyWorkerExitCommand as p, CheckerSkippedRequested as pt, defaultOptions as q, buildTestRunner as r, MergeResult as rt, RunEventWireLine as s, survivorsPriorReport as st, mutationTestCell as t, ImportedModuleSchema as tt, IncrementalReportSchema as u, OutOfMemoryError as ut, decideExtendsStep as v, validateOptions as w, importModule as x, describeErrors as y, isCommandRunner as z };
|