@systemfsoftware/stryker-js 10.0.0 → 10.0.1
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 +6 -0
- package/dist/{Run.schema-C0Cxsfe9.mjs → Run.schema-CgVfoOfk.mjs} +71 -61
- package/dist/{Run.schema-BBKIZ81u.d.mts → Run.schema-t292QQGe.d.mts} +13 -5
- package/dist/config.d.mts +1 -1
- package/dist/events.d.mts +1 -1
- package/dist/events.mjs +1 -1
- package/dist/{index-DnAm4mSL.d.mts → index-D_mcApox.d.mts} +44 -10
- package/dist/index.d.mts +48 -12
- package/dist/index.mjs +2 -2
- package/dist/main.mjs +6525 -9089
- package/dist/{mutation-test.cell-m9T-X2Qx.d.mts → mutation-test.cell-Dp6QiuRg.d.mts} +14 -6
- package/dist/parser.wasm32-wasi.wasm +0 -0
- package/dist/promises.d.mts +2 -2
- package/dist/promises.mjs +1 -1
- package/dist/{src-Bu4i-Lt2.mjs → src-CMHnl87m.mjs} +465 -613
- package/dist/{src-js-DRK8boNV.mjs → src-js-CvBdbRpe.mjs} +129 -56
- package/dist/{wasm-Dg4JcQ2d.mjs → wasm-klkEDrvQ.mjs} +4545 -4335
- package/package.json +22 -22
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as WorkerPluginKind, F as MutationTestingPlanReady, G as TRACEPARENT_HEADER, I as NonNegativeInt, J as TestRunnerFailed, K as TRACESTATE_HEADER, L as PropagatedTrace, M as MutantTested, N as MutationTestReportReady, O as Metrics, P as MutationTestResultSchema$1, Q as WorkerEntryUrl, S as CheckerMutantWire, T as DryRunCompleted, U as ReporterRpcs, V as ReporterFailed, W as StrykerOptionsSchema, X as TraceContextMiddleware, Y as TestRunnerRpcs, Z as TraceContextReference, _ as RunStarted, c as PhaseEntered, dt as errorToString, et as formatTraceparent, f as RunEvent, ft as instrument, it as INSTRUMENTER_CONSTANTS, k as MetricsResultSchema, l as PlanKnown, m as RunMutantTested, n as StageError, nt as parseTraceparent, ot as Mutant, pt as normalizeFileName$4, r as Heartbeat, rt as toMutantRunResult, t as PrepareError, tt as isCustomTestRunner, ut as disableTypeChecks, v as VerdictReached, w as CheckerRpcs } from "./Run.schema-
|
|
1
|
+
import { $ as WorkerPluginKind, F as MutationTestingPlanReady, G as TRACEPARENT_HEADER, I as NonNegativeInt, J as TestRunnerFailed, K as TRACESTATE_HEADER, L as PropagatedTrace, M as MutantTested, N as MutationTestReportReady, O as Metrics, P as MutationTestResultSchema$1, Q as WorkerEntryUrl, S as CheckerMutantWire, T as DryRunCompleted, U as ReporterRpcs, V as ReporterFailed, W as StrykerOptionsSchema, X as TraceContextMiddleware, Y as TestRunnerRpcs, Z as TraceContextReference, _ as RunStarted, c as PhaseEntered, dt as errorToString, et as formatTraceparent, f as RunEvent, ft as instrument, it as INSTRUMENTER_CONSTANTS, k as MetricsResultSchema, l as PlanKnown, m as RunMutantTested, n as StageError, nt as parseTraceparent, ot as Mutant, pt as normalizeFileName$4, r as Heartbeat, rt as toMutantRunResult, t as PrepareError, tt as isCustomTestRunner, ut as disableTypeChecks, v as VerdictReached, w as CheckerRpcs } from "./Run.schema-CgVfoOfk.mjs";
|
|
2
2
|
import { t as mergeConfig } from "./merge-config-BrrNQWje.mjs";
|
|
3
3
|
import * as Effect$1 from "effect/Effect";
|
|
4
4
|
import * as FileSystem from "effect/FileSystem";
|
|
@@ -16,12 +16,12 @@ import * as Ref from "effect/Ref";
|
|
|
16
16
|
import * as Result from "effect/Result";
|
|
17
17
|
import * as S from "effect/Schema";
|
|
18
18
|
import * as Stream from "effect/Stream";
|
|
19
|
-
import { Cell, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
19
|
+
import { Cell, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
20
20
|
import * as Predicate from "effect/Predicate";
|
|
21
21
|
import * as Array$1 from "effect/Array";
|
|
22
|
-
import { Schema } from "effect";
|
|
22
|
+
import { Schema, SchemaGetter } from "effect";
|
|
23
23
|
import * as RpcMiddleware from "effect/unstable/rpc/RpcMiddleware";
|
|
24
|
-
import * as SchemaGetter from "effect/SchemaGetter";
|
|
24
|
+
import * as SchemaGetter$1 from "effect/SchemaGetter";
|
|
25
25
|
import * as Exit from "effect/Exit";
|
|
26
26
|
import * as Scope from "effect/Scope";
|
|
27
27
|
import * as Duration from "effect/Duration";
|
|
@@ -52,7 +52,7 @@ import * as Equivalence from "effect/Equivalence";
|
|
|
52
52
|
import * as Metric from "effect/Metric";
|
|
53
53
|
import * as Pool from "effect/Pool";
|
|
54
54
|
import * as Semaphore from "effect/Semaphore";
|
|
55
|
-
import * as SchemaTransformation from "effect/SchemaTransformation";
|
|
55
|
+
import * as SchemaTransformation$1 from "effect/SchemaTransformation";
|
|
56
56
|
import { randomBytes } from "@noble/hashes/utils.js";
|
|
57
57
|
import * as Console from "effect/Console";
|
|
58
58
|
import "effect/Sink";
|
|
@@ -142,8 +142,8 @@ const frameRunEvent = Workflow.total(FrameRunEventCommand, decideFrame);
|
|
|
142
142
|
//#endregion
|
|
143
143
|
//#region src/run-event-wire.schema.ts
|
|
144
144
|
const RunEventWireLine = S.String.pipe(S.decodeTo(S.fromJsonString(RunEvent), {
|
|
145
|
-
decode: SchemaGetter.transform((line) => line.replace(/\n$/, "")),
|
|
146
|
-
encode: SchemaGetter.transform((json) => `${json}\n`)
|
|
145
|
+
decode: SchemaGetter$1.transform((line) => line.replace(/\n$/, "")),
|
|
146
|
+
encode: SchemaGetter$1.transform((json) => `${json}\n`)
|
|
147
147
|
}));
|
|
148
148
|
//#endregion
|
|
149
149
|
//#region src/RunEvents.ts
|
|
@@ -915,9 +915,9 @@ Layer.succeed(TraceContextMiddleware, serverMiddleware);
|
|
|
915
915
|
let wire;
|
|
916
916
|
const workerOptionsWire = () => wire ??= S.fromJsonString(S.toCodecJson(StrykerOptionsSchema));
|
|
917
917
|
const encodeWorkerOptions = (options) => S.encodeEffect(workerOptionsWire())(options).pipe(Effect$1.orDie);
|
|
918
|
-
const decodeWorkerOptions = (raw) => S.
|
|
918
|
+
const decodeWorkerOptions = (raw) => S.decodeEffect(workerOptionsWire())(raw);
|
|
919
919
|
Effect$1.gen(function* () {
|
|
920
|
-
const workerDir = yield* Config.
|
|
920
|
+
const workerDir = yield* Config.String("STRYKER_WORKER_DIR");
|
|
921
921
|
const fs = yield* FileSystem.FileSystem;
|
|
922
922
|
const path = yield* Path.Path;
|
|
923
923
|
const raw = yield* fs.readFileString(path.join(workerDir, "options.json"));
|
|
@@ -936,9 +936,9 @@ const otlpLayer = (serviceName, endpoint) => NodeSdk.layer(() => ({
|
|
|
936
936
|
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter({ url: tracesUrl(endpoint) }))
|
|
937
937
|
}));
|
|
938
938
|
Layer.unwrap(Effect$1.gen(function* () {
|
|
939
|
-
if (!(yield* Config.
|
|
940
|
-
const serviceName = yield* Config.
|
|
941
|
-
const endpoint = yield* Config.
|
|
939
|
+
if (!(yield* Config.Boolean("OTEL_ENABLED").pipe(Config.withDefault(false)))) return Layer.empty;
|
|
940
|
+
const serviceName = yield* Config.String("OTEL_SERVICE_NAME").pipe(Config.withDefault(WORKER_SERVICE_NAME));
|
|
941
|
+
const endpoint = yield* Config.String("OTEL_EXPORTER_OTLP_ENDPOINT").pipe(Config.withDefault(DEFAULT_ENDPOINT));
|
|
942
942
|
return otlpLayer(serviceName, endpoint);
|
|
943
943
|
}));
|
|
944
944
|
//#endregion
|
|
@@ -1202,7 +1202,7 @@ const makeWorkerClient = (params) => Effect$1.gen(function* () {
|
|
|
1202
1202
|
});
|
|
1203
1203
|
//#endregion
|
|
1204
1204
|
//#region src/platform/node.ts
|
|
1205
|
-
const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.
|
|
1205
|
+
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));
|
|
1206
1206
|
/**
|
|
1207
1207
|
* The Node worker launcher: spawn a worker child with this runtime's
|
|
1208
1208
|
* executable, host the RPC server's address as a `net` `path` endpoint (a
|
|
@@ -1217,12 +1217,12 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(functi
|
|
|
1217
1217
|
return { spawn: (params) => Effect$1.gen(function* () {
|
|
1218
1218
|
const workerDir = yield* fs.makeTempDirectoryScoped({ prefix: params.tempDirPrefix });
|
|
1219
1219
|
const workerId = yield* crypto.randomUUIDv4;
|
|
1220
|
-
const socketPath = Match.value(process.platform).pipe(Match.when("win32", () => `\\\\.\\pipe\\stryker-worker-${workerId}`), Match.orElse(() => path.join(workerDir, "worker.sock")));
|
|
1220
|
+
const socketPath = Match.value(globalThis.process.platform).pipe(Match.when("win32", () => `\\\\.\\pipe\\stryker-worker-${workerId}`), Match.orElse(() => path.join(workerDir, "worker.sock")));
|
|
1221
1221
|
const optionsFile = path.join(workerDir, "options.json");
|
|
1222
1222
|
yield* fs.writeFileString(optionsFile, params.optionsJson);
|
|
1223
1223
|
yield* restrictToOwnerOrWarn(fs, optionsFile);
|
|
1224
1224
|
const entrypointPath = yield* path.fromFileUrl(new URL(params.entrypoint));
|
|
1225
|
-
const handle = yield* ChildProcess.make(process.execPath, [...params.execArgv, entrypointPath], {
|
|
1225
|
+
const handle = yield* ChildProcess.make(globalThis.process.execPath, [...params.execArgv, entrypointPath], {
|
|
1226
1226
|
cwd: params.workingDirectory,
|
|
1227
1227
|
extendEnv: true,
|
|
1228
1228
|
env: {
|
|
@@ -1256,14 +1256,14 @@ const nodePlatformLayer = Layer.mergeAll(nodeWorkerLauncherLayer.pipe(Layer.prov
|
|
|
1256
1256
|
* The in-memory runner's platform: the V8 sandbox module and the module
|
|
1257
1257
|
* builtin that strips TypeScript and resolves a sandbox's `require`.
|
|
1258
1258
|
*
|
|
1259
|
-
* Reached through `process.getBuiltinModule` rather than an `import` because a
|
|
1259
|
+
* Reached through `globalThis.process.getBuiltinModule` rather than an `import` because a
|
|
1260
1260
|
* Node builtin import is forbidden in product code; the call is wrapped in
|
|
1261
1261
|
* `Effect.promise` so a platform without `node:vm` fails as a defect — the
|
|
1262
1262
|
* runner has no fallback to fall back to.
|
|
1263
1263
|
*/
|
|
1264
1264
|
const nodeVmPlatformLayer = Layer.effect(VmRunner, Effect$1.sync(() => ({
|
|
1265
|
-
module: process.getBuiltinModule("node:module"),
|
|
1266
|
-
vm: process.getBuiltinModule("node:vm")
|
|
1265
|
+
module: globalThis.process.getBuiltinModule("node:module"),
|
|
1266
|
+
vm: globalThis.process.getBuiltinModule("node:vm")
|
|
1267
1267
|
})));
|
|
1268
1268
|
S.TaggedError()("CommandRunnerUnsupportedOption", { option: S.String });
|
|
1269
1269
|
S.Struct({
|
|
@@ -2002,7 +2002,7 @@ function findConfigFile(configFileName) {
|
|
|
2002
2002
|
return Match.value(configFileName).pipe(Match.when(Match.string, (fileName) => configFileFor(fileName)), Match.orElse(() => discoverConfigFile()));
|
|
2003
2003
|
}
|
|
2004
2004
|
const resolveChildExtends = (configFile, child, configEnv) => Match.value("extends" in child).pipe(Match.when(true, () => resolveExtends(configFile, child, configEnv)), Match.orElse(() => Effect$1.succeed(child)));
|
|
2005
|
-
const isCiEnvironment = Config.
|
|
2005
|
+
const isCiEnvironment = Config.String("CI").pipe(Effect$1.map((value) => Match.value(value.trim().toLowerCase()).pipe(Match.when("", () => false), Match.when("0", () => false), Match.when("false", () => false), Match.orElse(() => true))), Effect$1.orElseSucceed(() => false));
|
|
2006
2006
|
function loadOptionsFromConfigFile(cliOptions, configEnv) {
|
|
2007
2007
|
return findConfigFile(cliOptions["configFile"]).pipe(Effect$1.flatMap((configFile) => Match.value(configFile).pipe(Match.when(void 0, () => Effect$1.succeed({})), Match.orElse((found) => readConfigModule(found, configEnv).pipe(Effect$1.flatMap((child) => resolveChildExtends(found, child, configEnv)))))));
|
|
2008
2008
|
}
|
|
@@ -2014,7 +2014,7 @@ function readConfig(cliOptions, invocation) {
|
|
|
2014
2014
|
isDryRun: cliOptions["dryRunOnly"] === true,
|
|
2015
2015
|
isCi: yield* isCiEnvironment
|
|
2016
2016
|
};
|
|
2017
|
-
const cliRecord = yield* S.
|
|
2017
|
+
const cliRecord = yield* S.decodeEffect(ConfigDocumentSchema)(cliOptions).pipe(Effect$1.orDie);
|
|
2018
2018
|
const fileRecord = yield* loadOptionsFromConfigFile(cliRecord, configEnv);
|
|
2019
2019
|
const fileOptions = yield* Result.match(S.decodeUnknownResult(ConfigDocumentSchema)(fileRecord), {
|
|
2020
2020
|
onFailure: (cause) => Effect$1.fail(ConfigFileInvalidError.make({
|
|
@@ -2046,9 +2046,13 @@ const PluginDescriptorSchema = Schema.Union([Schema.Struct({
|
|
|
2046
2046
|
const PluginModuleSchema = Schema.Struct({ strykerPlugins: Schema.Array(PluginDescriptorSchema) });
|
|
2047
2047
|
const isShouldIgnore = (value) => typeof value === "function";
|
|
2048
2048
|
const ignoreNothing = () => void 0;
|
|
2049
|
+
const shouldIgnoreArbitrary = Schema.link()(Schema.Null, {
|
|
2050
|
+
decode: SchemaGetter.transform(() => ignoreNothing),
|
|
2051
|
+
encode: SchemaGetter.transform(() => null)
|
|
2052
|
+
});
|
|
2049
2053
|
const IgnorerEntrySchema = Schema.Struct({
|
|
2050
2054
|
name: Schema.String,
|
|
2051
|
-
shouldIgnore: Schema.declare(isShouldIgnore, {
|
|
2055
|
+
shouldIgnore: Schema.declare(isShouldIgnore, { toCodecArbitrary: () => shouldIgnoreArbitrary })
|
|
2052
2056
|
});
|
|
2053
2057
|
const IgnorerModuleSchema = Schema.Struct({ strykerIgnorers: Schema.Array(IgnorerEntrySchema) });
|
|
2054
2058
|
const SchemaValidationContributionSchema = Schema.Struct({ strykerValidationSchema: Schema.Record(Schema.String, Schema.Unknown) });
|
|
@@ -2436,8 +2440,8 @@ const initFromPhaseSpan = (span) => {
|
|
|
2436
2440
|
};
|
|
2437
2441
|
};
|
|
2438
2442
|
const environmentTraceInit = () => Effect$1.gen(function* () {
|
|
2439
|
-
const traceparent = yield* Config.
|
|
2440
|
-
const tracestate = yield* Config.
|
|
2443
|
+
const traceparent = yield* Config.String("TRACEPARENT").pipe(Effect$1.option);
|
|
2444
|
+
const tracestate = yield* Config.String("TRACESTATE").pipe(Effect$1.option);
|
|
2441
2445
|
return {
|
|
2442
2446
|
...traceparentInit(Option.getOrUndefined(traceparent)),
|
|
2443
2447
|
...tracestateInit(Option.getOrUndefined(tracestate))
|
|
@@ -2532,104 +2536,98 @@ const completeDryRunPassed = (raw) => Effect$1.gen(function* () {
|
|
|
2532
2536
|
timeOverhead: Duration.millis(overheadMillis)
|
|
2533
2537
|
};
|
|
2534
2538
|
});
|
|
2535
|
-
const dryRunCell =
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
const
|
|
2543
|
-
const
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
}).pipe(Effect$1.mapError(missingWorkerEntry("dryRun", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
2551
|
-
options: command.options,
|
|
2552
|
-
fileDescriptions: command.project.fileDescriptions,
|
|
2553
|
-
sandboxWorkingDirectory: command.sandbox.workingDirectory,
|
|
2554
|
-
workerEntrypoint: spawn.entrypoint,
|
|
2555
|
-
idGenerator
|
|
2556
|
-
})));
|
|
2557
|
-
});
|
|
2558
|
-
const runner = yield* buildTestRunner({
|
|
2539
|
+
const dryRunCell = Sandwich.read((command) => Effect$1.gen(function* () {
|
|
2540
|
+
yield* Scope.Scope;
|
|
2541
|
+
const idGenerator = yield* IdGenerator;
|
|
2542
|
+
const { files, testFiles } = buildDryRunFiles(command);
|
|
2543
|
+
const dryRunTimeout = command.options.dryRunTimeoutMinutes * 60 * 1e3;
|
|
2544
|
+
yield* Effect$1.logInfo("Starting dry run");
|
|
2545
|
+
const { rawResult, capabilities, gross } = yield* Effect$1.scoped(Effect$1.gen(function* () {
|
|
2546
|
+
const childRunnerEffect = Effect$1.suspend(() => {
|
|
2547
|
+
const runnerConfigured = command.options.testRunner;
|
|
2548
|
+
const runnerLabel = Match.value(runnerConfigured).pipe(Match.when(isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
2549
|
+
return resolveConfiguredWorkerSpawn({
|
|
2550
|
+
loaded: command.loadedPlugins,
|
|
2551
|
+
kind: "TestRunner",
|
|
2552
|
+
configured: runnerConfigured
|
|
2553
|
+
}).pipe(Effect$1.mapError(missingWorkerEntry("dryRun", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
2559
2554
|
options: command.options,
|
|
2560
2555
|
fileDescriptions: command.project.fileDescriptions,
|
|
2561
2556
|
sandboxWorkingDirectory: command.sandbox.workingDirectory,
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
return StageError.make({
|
|
2557
|
+
workerEntrypoint: spawn.entrypoint,
|
|
2558
|
+
idGenerator
|
|
2559
|
+
})));
|
|
2560
|
+
});
|
|
2561
|
+
const runner = yield* buildTestRunner({
|
|
2562
|
+
options: command.options,
|
|
2563
|
+
fileDescriptions: command.project.fileDescriptions,
|
|
2564
|
+
sandboxWorkingDirectory: command.sandbox.workingDirectory,
|
|
2565
|
+
idGenerator,
|
|
2566
|
+
retire: Effect$1.void,
|
|
2567
|
+
testFiles: testFiles ?? []
|
|
2568
|
+
}, childRunnerEffect);
|
|
2569
|
+
const extra = Option.match(Option.fromUndefinedOr(testFiles), {
|
|
2570
|
+
onNone: () => ({}),
|
|
2571
|
+
onSome: (files) => ({ testFiles: files })
|
|
2572
|
+
});
|
|
2573
|
+
const timed = yield* Effect$1.timed(runner.dryRun({
|
|
2574
|
+
timeout: dryRunTimeout,
|
|
2575
|
+
coverageAnalysis: command.options.coverageAnalysis,
|
|
2576
|
+
disableBail: command.options.disableBail,
|
|
2577
|
+
files,
|
|
2578
|
+
...extra
|
|
2579
|
+
}).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
2580
|
+
stage: "dryRun",
|
|
2581
|
+
reason: "Dry run failed",
|
|
2582
|
+
cause
|
|
2583
|
+
}))));
|
|
2584
|
+
const gross = timed[0];
|
|
2585
|
+
return {
|
|
2586
|
+
rawResult: timed[1],
|
|
2587
|
+
capabilities: yield* runner.capabilities.pipe(Effect$1.mapError((cause) => StageError.make({
|
|
2594
2588
|
stage: "dryRun",
|
|
2595
|
-
reason: "
|
|
2589
|
+
reason: "Failed to get test runner capabilities",
|
|
2596
2590
|
cause
|
|
2597
|
-
})
|
|
2598
|
-
}));
|
|
2599
|
-
return {
|
|
2600
|
-
prev: command,
|
|
2601
|
-
rawResult,
|
|
2602
|
-
capabilities,
|
|
2591
|
+
}))),
|
|
2603
2592
|
gross
|
|
2604
2593
|
};
|
|
2605
|
-
})
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
encode: (outcome) => outcome,
|
|
2609
|
-
write: (outcome, raw) => withPhaseSpan("dryRun", {}, () => Effect$1.gen(function* () {
|
|
2610
|
-
const env = yield* RunEnvironment;
|
|
2611
|
-
const now = yield* Clock.currentTimeMillis;
|
|
2612
|
-
const queue = yield* RunEvents;
|
|
2613
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
2614
|
-
phase: "dry-run",
|
|
2615
|
-
elapsedMs: now - env.runStartedAt
|
|
2616
|
-
}));
|
|
2617
|
-
const out = outcome;
|
|
2618
|
-
if (Result.isFailure(out)) {
|
|
2619
|
-
const err = out.failure;
|
|
2620
|
-
return yield* StageError.make({
|
|
2621
|
-
stage: err.stage,
|
|
2622
|
-
reason: err.reason,
|
|
2623
|
-
cause: err
|
|
2624
|
-
});
|
|
2625
|
-
}
|
|
2626
|
-
return yield* Match.value(out.success).pipe(Match.tag("DryRunFailed", (decision) => Effect$1.fail(StageError.make({
|
|
2594
|
+
})).pipe(Effect$1.mapError((cause) => {
|
|
2595
|
+
if (S.is(StageError)(cause)) return cause;
|
|
2596
|
+
return StageError.make({
|
|
2627
2597
|
stage: "dryRun",
|
|
2628
|
-
reason: "
|
|
2629
|
-
cause
|
|
2630
|
-
})
|
|
2631
|
-
}))
|
|
2632
|
-
|
|
2598
|
+
reason: "Dry run failed to start test runner",
|
|
2599
|
+
cause
|
|
2600
|
+
});
|
|
2601
|
+
}));
|
|
2602
|
+
return {
|
|
2603
|
+
prev: command,
|
|
2604
|
+
rawResult,
|
|
2605
|
+
capabilities,
|
|
2606
|
+
gross
|
|
2607
|
+
};
|
|
2608
|
+
})).decode(Sandwich.pure((raw) => Match.value(raw.rawResult).pipe(Match.when(isCompleteDryRun, (complete) => decodeCompleteDryRun(complete, raw.prev.options.allowEmpty)), Match.when(isFailedDryRun, (failed) => decodeFailedDryRun(failed, raw.prev.options.allowEmpty)), Match.orElse((timedOut) => decodeTimedOutDryRun(timedOut, raw.prev.options.allowEmpty))))).decide(dryRun).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => withPhaseSpan("dryRun", {}, () => Effect$1.gen(function* () {
|
|
2609
|
+
const env = yield* RunEnvironment;
|
|
2610
|
+
const now = yield* Clock.currentTimeMillis;
|
|
2611
|
+
const queue = yield* RunEvents;
|
|
2612
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
2613
|
+
phase: "dry-run",
|
|
2614
|
+
elapsedMs: now - env.runStartedAt
|
|
2615
|
+
}));
|
|
2616
|
+
const out = outcome;
|
|
2617
|
+
if (Result.isFailure(out)) {
|
|
2618
|
+
const err = out.failure;
|
|
2619
|
+
return yield* StageError.make({
|
|
2620
|
+
stage: err.stage,
|
|
2621
|
+
reason: err.reason,
|
|
2622
|
+
cause: err
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
return yield* Match.value(out.success).pipe(Match.tag("DryRunFailed", (decision) => Effect$1.fail(StageError.make({
|
|
2626
|
+
stage: "dryRun",
|
|
2627
|
+
reason: "There were failed tests in the initial test run.",
|
|
2628
|
+
cause: decision
|
|
2629
|
+
}))), Match.tag("DryRunPassed", () => completeDryRunPassed(raw)), Match.exhaustive);
|
|
2630
|
+
})));
|
|
2633
2631
|
//#endregion
|
|
2634
2632
|
//#region src/plan-instrumentation.workflow.ts
|
|
2635
2633
|
var InstrumentError = class extends S.TaggedError()("InstrumentError", {
|
|
@@ -2846,118 +2844,8 @@ const decide = (command) => Option.match(Option.fromUndefinedOr(command.report),
|
|
|
2846
2844
|
});
|
|
2847
2845
|
const admitIncrementalReport = Workflow.total(AdmitIncrementalReportCommand, (command) => Result.succeed(decide(command)));
|
|
2848
2846
|
//#endregion
|
|
2849
|
-
//#region package.json
|
|
2850
|
-
var package_default = {
|
|
2851
|
-
name: "@systemfsoftware/stryker-js",
|
|
2852
|
-
version: "10.0.0",
|
|
2853
|
-
repository: {
|
|
2854
|
-
"type": "git",
|
|
2855
|
-
"url": "git+https://github.com/systemfsoftware/stryker-js-effect.git",
|
|
2856
|
-
"directory": "packages/stryker-js"
|
|
2857
|
-
},
|
|
2858
|
-
homepage: "https://github.com/systemfsoftware/stryker-js-effect",
|
|
2859
|
-
bugs: { "url": "https://github.com/systemfsoftware/stryker-js-effect/issues" },
|
|
2860
|
-
description: "The Stryker mutation testing tool — the stryker executable, the run engine, and the configuration surface.",
|
|
2861
|
-
type: "module",
|
|
2862
|
-
files: ["dist"],
|
|
2863
|
-
bin: { "stryker": "./dist/main.mjs" },
|
|
2864
|
-
scripts: {
|
|
2865
|
-
"clean": "rimraf dist",
|
|
2866
|
-
"build": "pnpm run typecheck && rimraf dist && tsdown --config tsdown.bin.config.ts && tsdown --config tsdown.config.ts",
|
|
2867
|
-
"typecheck": "tsc --noEmit --incremental && tsc -p tsconfig.node.json --noEmit",
|
|
2868
|
-
"test": "vitest run",
|
|
2869
|
-
"mutation": "stryker run",
|
|
2870
|
-
"attw": "attw --pack .",
|
|
2871
|
-
"lint": "f=${OXLINT_FORMAT:-${AGENT:+agent}}; oxlint . --format=${f:-default}",
|
|
2872
|
-
"api:check": "api-extractor run",
|
|
2873
|
-
"api:update": "api-extractor run --local",
|
|
2874
|
-
"lint:tsgo": "effect-tsgo diagnostics --project tsconfig.json --format ${TSGO_FORMAT:-text}"
|
|
2875
|
-
},
|
|
2876
|
-
license: "Apache-2.0",
|
|
2877
|
-
engines: { "node": ">=22.18.0" },
|
|
2878
|
-
dependencies: {
|
|
2879
|
-
"@effect/opentelemetry": "4.0.0-rc.112",
|
|
2880
|
-
"@effect/platform-node": "catalog:",
|
|
2881
|
-
"@effect/platform-node-shared": "catalog:",
|
|
2882
|
-
"@noble/hashes": "catalog:",
|
|
2883
|
-
"@opentelemetry/api": "^1.9.0",
|
|
2884
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.208.0",
|
|
2885
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
|
|
2886
|
-
"@opentelemetry/sdk-metrics": "^2.2.0",
|
|
2887
|
-
"@opentelemetry/sdk-trace-base": "^2.2.0",
|
|
2888
|
-
"@systemfsoftware/effect-cell-types": "catalog:"
|
|
2889
|
-
},
|
|
2890
|
-
peerDependencies: { "effect": "catalog:" },
|
|
2891
|
-
devDependencies: {
|
|
2892
|
-
"@effect/tsgo": "catalog:",
|
|
2893
|
-
"@effect/vitest": "catalog:",
|
|
2894
|
-
"@microsoft/api-extractor": "catalog:",
|
|
2895
|
-
"@oxc-parser/binding-wasm32-wasi": "catalog:",
|
|
2896
|
-
"@std/jsonc": "catalog:",
|
|
2897
|
-
"@systemfsoftware/all": "catalog:",
|
|
2898
|
-
"@systemfsoftware/arethetypeswrong-cli": "catalog:",
|
|
2899
|
-
"@systemfsoftware/effect-gherkin-spec": "catalog:",
|
|
2900
|
-
"@systemfsoftware/effect-schema-law": "catalog:",
|
|
2901
|
-
"@systemfsoftware/effect-schema-vite": "catalog:",
|
|
2902
|
-
"@systemfsoftware/stryker-config": "workspace:^",
|
|
2903
|
-
"@systemfsoftware/stryker-ignorer-effect-schema-declarations": "catalog:stryker",
|
|
2904
|
-
"@systemfsoftware/stryker-ignorer-in-source-vitest-block": "catalog:stryker",
|
|
2905
|
-
"@systemfsoftware/stryker-ignorer-interface": "workspace:^",
|
|
2906
|
-
"@systemfsoftware/stryker-js": "catalog:stryker",
|
|
2907
|
-
"@systemfsoftware/stryker-js-html-reporter": "workspace:^",
|
|
2908
|
-
"@systemfsoftware/stryker-js-instrumenter": "workspace:^",
|
|
2909
|
-
"@systemfsoftware/stryker-js-plugin-interface": "workspace:^",
|
|
2910
|
-
"@systemfsoftware/stryker-js-plugin-runtime": "workspace:^",
|
|
2911
|
-
"@systemfsoftware/stryker-js-typescript-checker": "catalog:stryker",
|
|
2912
|
-
"@systemfsoftware/stryker-js-vitest-runner": "catalog:stryker",
|
|
2913
|
-
"@systemfsoftware/stryker-test-contribution": "catalog:stryker",
|
|
2914
|
-
"@systemfsoftware/tsconfig": "catalog:",
|
|
2915
|
-
"@systemfsoftware/tsdown-config": "workspace:^",
|
|
2916
|
-
"@systemfsoftware/vitest-config": "workspace:^",
|
|
2917
|
-
"@types/node": "catalog:",
|
|
2918
|
-
"@vitest/coverage-v8": "catalog:",
|
|
2919
|
-
"concurrently": "catalog:",
|
|
2920
|
-
"mutation-testing-elements": "catalog:stryker",
|
|
2921
|
-
"oxc-parser": "catalog:",
|
|
2922
|
-
"oxlint": "catalog:",
|
|
2923
|
-
"oxlint-tsgolint": "catalog:",
|
|
2924
|
-
"rimraf": "catalog:",
|
|
2925
|
-
"tsdown": "catalog:",
|
|
2926
|
-
"typescript": "catalog:",
|
|
2927
|
-
"vitest": "catalog:"
|
|
2928
|
-
},
|
|
2929
|
-
publishConfig: {
|
|
2930
|
-
"access": "public",
|
|
2931
|
-
"provenance": true,
|
|
2932
|
-
"exports": {
|
|
2933
|
-
".": {
|
|
2934
|
-
"types": "./dist/index.d.mts",
|
|
2935
|
-
"default": "./dist/index.mjs"
|
|
2936
|
-
},
|
|
2937
|
-
"./config": {
|
|
2938
|
-
"types": "./dist/config.d.mts",
|
|
2939
|
-
"default": "./dist/config.mjs"
|
|
2940
|
-
},
|
|
2941
|
-
"./events": {
|
|
2942
|
-
"types": "./dist/events.d.mts",
|
|
2943
|
-
"default": "./dist/events.mjs"
|
|
2944
|
-
},
|
|
2945
|
-
"./promises": {
|
|
2946
|
-
"types": "./dist/promises.d.mts",
|
|
2947
|
-
"default": "./dist/promises.mjs"
|
|
2948
|
-
},
|
|
2949
|
-
"./package.json": "./package.json"
|
|
2950
|
-
}
|
|
2951
|
-
},
|
|
2952
|
-
exports: { "./package.json": "./package.json" }
|
|
2953
|
-
};
|
|
2954
|
-
//#endregion
|
|
2955
|
-
//#region src/stryker-package.schema.ts
|
|
2956
|
-
const PackageJsonSchema = Schema.Struct({ version: Schema.String });
|
|
2957
|
-
//#endregion
|
|
2958
2847
|
//#region src/stryker-package.ts
|
|
2959
|
-
const
|
|
2960
|
-
const strykerVersion = Schema.decodeUnknownSync(PackageJsonSchema)(rawPackageJson).version;
|
|
2848
|
+
const strykerVersion = "10.0.1";
|
|
2961
2849
|
//#endregion
|
|
2962
2850
|
//#region src/incremental-report.cell.ts
|
|
2963
2851
|
const parseAndDecodeIncrementalReport = S.decodeUnknownResult(S.fromJsonString(IncrementalReportSchema));
|
|
@@ -2968,7 +2856,7 @@ const readIncrementalReportRaw = (input) => {
|
|
|
2968
2856
|
contents: void 0
|
|
2969
2857
|
});
|
|
2970
2858
|
return Effect$1.gen(function* () {
|
|
2971
|
-
const contents = yield* (yield* FileSystem.FileSystem).readFileString(input.incrementalFile).pipe(Effect$1.
|
|
2859
|
+
const contents = yield* (yield* FileSystem.FileSystem).readFileString(input.incrementalFile).pipe(Effect$1.tapError((error) => Match.value(error.reason).pipe(Match.tag("NotFound", () => Effect$1.logInfo(`No incremental result file found at ${input.incrementalFile}, a full mutation testing run will be performed.`)), Match.orElse(() => Effect$1.void))), Effect$1.catchTag("PlatformError", (error) => Match.value(error.reason).pipe(Match.tag("NotFound", () => Effect$1.undefined), Match.orElse(() => Effect$1.fail(error)))));
|
|
2972
2860
|
return {
|
|
2973
2861
|
incremental: true,
|
|
2974
2862
|
incrementalFile: input.incrementalFile,
|
|
@@ -2996,13 +2884,7 @@ const writeIncrementalReportOutcome = (outcome, raw) => Result.match(outcome, {
|
|
|
2996
2884
|
});
|
|
2997
2885
|
}), Match.exhaustive)
|
|
2998
2886
|
});
|
|
2999
|
-
const incrementalReportCell =
|
|
3000
|
-
read: readIncrementalReportRaw,
|
|
3001
|
-
decode: decodeIncrementalReportRaw,
|
|
3002
|
-
decide: admitIncrementalReport,
|
|
3003
|
-
encode: (outcome) => outcome,
|
|
3004
|
-
write: writeIncrementalReportOutcome
|
|
3005
|
-
});
|
|
2887
|
+
const incrementalReportCell = Sandwich.read(readIncrementalReportRaw).decode(Sandwich.pure(decodeIncrementalReportRaw)).decide(admitIncrementalReport).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write(writeIncrementalReportOutcome);
|
|
3006
2888
|
//#endregion
|
|
3007
2889
|
//#region src/Project.ts
|
|
3008
2890
|
const DEFAULT_GLOB$1 = "**/*.{js,ts,jsx,tsx,html,vue,mjs,mts,cts,cjs}";
|
|
@@ -3736,9 +3618,9 @@ const makeDisableTypeChecksPreprocessor = (options, impl) => (project) => Effect
|
|
|
3736
3618
|
const content = yield* Effect$1.map(impl(instrumenterFile), (instrumented) => instrumented.content).pipe(Effect$1.mapError((cause) => StrykerError.make({
|
|
3737
3619
|
message: "disableTypeChecks failed",
|
|
3738
3620
|
cause
|
|
3739
|
-
})), Effect$1.
|
|
3621
|
+
})), Effect$1.tapError(() => Effect$1.gen(function* () {
|
|
3740
3622
|
if (isWarningEnabled("preprocessorErrors", options.warnings)) yield* Effect$1.logWarning(`Unable to disable type checking for file "${name}". Shouldn't type checking be disabled for this file? Consider configuring a more restrictive "${optionsPath("disableTypeChecks")}" settings (or turn it completely off with \`false\`)`);
|
|
3741
|
-
})));
|
|
3623
|
+
})), Effect$1.orElseSucceed(() => void 0));
|
|
3742
3624
|
if (content !== void 0) return withContent(file, content);
|
|
3743
3625
|
})), Match.orElse(() => Effect$1.succeedNone)), { concurrency: 24 })).forEach(mergeUpdatedInto(project));
|
|
3744
3626
|
});
|
|
@@ -3885,7 +3767,7 @@ const directoryChain = (from, pathService) => {
|
|
|
3885
3767
|
return [from, ...directoryChain(parent, pathService)];
|
|
3886
3768
|
};
|
|
3887
3769
|
const binDirectoriesFrom = (from, pathService) => directoryChain(pathService.resolve(from), pathService).map((directory) => pathService.join(directory, "node_modules", ".bin"));
|
|
3888
|
-
const inheritedPath = () => Config.
|
|
3770
|
+
const inheritedPath = () => Config.String("PATH").pipe(Effect$1.option, Effect$1.map((value) => Option.getOrUndefined(value) ?? ""));
|
|
3889
3771
|
const failOnBuildFailure = (command, result) => Match.value(result.exitCode).pipe(Match.when((exitCode) => exitCode !== 0, (exitCode) => Effect$1.fail(StrykerError.make({ message: `Build command "${command}" failed with exit code ${String(exitCode)}.\n${result.stderr}` }))), Match.orElse(() => Effect$1.void));
|
|
3890
3772
|
const runBuildCommandIn = (command, workingDirectory) => Effect$1.gen(function* () {
|
|
3891
3773
|
const pathService = yield* Path.Path;
|
|
@@ -4012,7 +3894,7 @@ const linkNodeModules = (nodeModules, workingDirectory, basePath, pathService) =
|
|
|
4012
3894
|
const resolvedTo = pathService.resolve(pathService.join(basePath, nodeModules));
|
|
4013
3895
|
const resolvedFrom = pathService.join(workingDirectory, nodeModules);
|
|
4014
3896
|
yield* Effect$1.logDebug(`Create symlink from ${resolvedTo} to ${resolvedFrom}`);
|
|
4015
|
-
yield* symlinkJunction(resolvedTo, resolvedFrom).pipe(Effect$1.
|
|
3897
|
+
yield* symlinkJunction(resolvedTo, resolvedFrom).pipe(Effect$1.tapError(() => Effect$1.logWarning(`Unexpected error while trying to symlink "${nodeModules}" in sandbox directory.`)), Effect$1.catchTag("PlatformError", () => Effect$1.void));
|
|
4016
3898
|
});
|
|
4017
3899
|
const linkFoundNodeModules = (options, workingDirectory, basePath, pathService) => Effect$1.gen(function* () {
|
|
4018
3900
|
const nodeModulesList = yield* findNodeModulesList(basePath, options.tempDirName);
|
|
@@ -4050,90 +3932,84 @@ const makeSandbox = (input) => Effect$1.gen(function* () {
|
|
|
4050
3932
|
});
|
|
4051
3933
|
//#endregion
|
|
4052
3934
|
//#region src/run/instrument.cell.ts
|
|
4053
|
-
const instrumentCell =
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
3935
|
+
const instrumentCell = Sandwich.read((command) => Effect$1.gen(function* () {
|
|
3936
|
+
yield* Scope.Scope;
|
|
3937
|
+
const env = yield* RunEnvironment;
|
|
3938
|
+
const filesToMutate = yield* Effect$1.forEach([...MutableHashMap.values(command.project.filesToMutate)], (file) => toInstrumenterFile(file), { concurrency: 24 }).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
3939
|
+
stage: "instrument",
|
|
3940
|
+
reason: "Failed to read files to mutate",
|
|
3941
|
+
cause
|
|
3942
|
+
})));
|
|
3943
|
+
const instrumentResult = yield* instrument(filesToMutate, {
|
|
3944
|
+
ignorers: [...command.ignorers],
|
|
3945
|
+
excludedMutations: [...command.options.mutator.excludedMutations]
|
|
3946
|
+
}, env.basePath).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
3947
|
+
stage: "instrument",
|
|
3948
|
+
reason: "Instrumenter failed",
|
|
3949
|
+
cause
|
|
3950
|
+
})));
|
|
3951
|
+
const instrumentedProject = withInstrumentedFiles(command.project, instrumentResult.files);
|
|
3952
|
+
const basePath = env.basePath;
|
|
3953
|
+
let workingDirectory = command.temporaryDirectoryPath;
|
|
3954
|
+
let backupDirectory = "";
|
|
3955
|
+
if (command.options.inPlace) {
|
|
3956
|
+
workingDirectory = basePath;
|
|
3957
|
+
backupDirectory = command.temporaryDirectoryPath;
|
|
3958
|
+
}
|
|
3959
|
+
return {
|
|
3960
|
+
prev: command,
|
|
3961
|
+
filesToMutate,
|
|
3962
|
+
instrumentResult,
|
|
3963
|
+
instrumentedProject,
|
|
3964
|
+
sandbox: yield* makeSandbox({
|
|
3965
|
+
options: command.options,
|
|
3966
|
+
project: instrumentedProject,
|
|
3967
|
+
workingDirectory,
|
|
3968
|
+
backupDirectory,
|
|
3969
|
+
basePath
|
|
3970
|
+
}).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
4058
3971
|
stage: "instrument",
|
|
4059
|
-
reason: "
|
|
3972
|
+
reason: "Sandbox initialization failed",
|
|
4060
3973
|
cause
|
|
4061
|
-
})))
|
|
4062
|
-
|
|
4063
|
-
ignorers: [...command.ignorers],
|
|
4064
|
-
excludedMutations: [...command.options.mutator.excludedMutations]
|
|
4065
|
-
}, env.basePath).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
3974
|
+
}))),
|
|
3975
|
+
concurrency: yield* makeConcurrency(command.options).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
4066
3976
|
stage: "instrument",
|
|
4067
|
-
reason: "
|
|
3977
|
+
reason: "Failed to compute concurrency",
|
|
4068
3978
|
cause
|
|
4069
|
-
})))
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
}),
|
|
4101
|
-
decode: (raw) => Result.succeed(InstrumentCommand.make({
|
|
4102
|
-
fileCount: raw.filesToMutate.length,
|
|
4103
|
-
inPlace: raw.prev.options.inPlace,
|
|
4104
|
-
pluginCount: raw.prev.loadedPlugins.pluginModulePaths.length
|
|
4105
|
-
})),
|
|
4106
|
-
decide: planInstrumentation,
|
|
4107
|
-
encode: (outcome) => outcome,
|
|
4108
|
-
write: (output, raw) => withPhaseSpan("instrument", { fileCount: raw.filesToMutate.length }, () => Effect$1.gen(function* () {
|
|
4109
|
-
const env = yield* RunEnvironment;
|
|
4110
|
-
const now = yield* Clock.currentTimeMillis;
|
|
4111
|
-
const queue = yield* RunEvents;
|
|
4112
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
4113
|
-
phase: "instrument",
|
|
4114
|
-
elapsedMs: now - env.runStartedAt
|
|
4115
|
-
}));
|
|
4116
|
-
const out = output;
|
|
4117
|
-
if (Result.isFailure(out)) {
|
|
4118
|
-
const err = out.failure;
|
|
4119
|
-
return yield* StageError.make({
|
|
4120
|
-
stage: err.stage,
|
|
4121
|
-
reason: err.reason,
|
|
4122
|
-
cause: err
|
|
4123
|
-
});
|
|
3979
|
+
})))
|
|
3980
|
+
};
|
|
3981
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(InstrumentCommand.make({
|
|
3982
|
+
fileCount: raw.filesToMutate.length,
|
|
3983
|
+
inPlace: raw.prev.options.inPlace,
|
|
3984
|
+
pluginCount: raw.prev.loadedPlugins.pluginModulePaths.length
|
|
3985
|
+
})))).decide(planInstrumentation).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((output, raw) => withPhaseSpan("instrument", { fileCount: raw.filesToMutate.length }, () => Effect$1.gen(function* () {
|
|
3986
|
+
const env = yield* RunEnvironment;
|
|
3987
|
+
const now = yield* Clock.currentTimeMillis;
|
|
3988
|
+
const queue = yield* RunEvents;
|
|
3989
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
3990
|
+
phase: "instrument",
|
|
3991
|
+
elapsedMs: now - env.runStartedAt
|
|
3992
|
+
}));
|
|
3993
|
+
const out = output;
|
|
3994
|
+
if (Result.isFailure(out)) {
|
|
3995
|
+
const err = out.failure;
|
|
3996
|
+
return yield* StageError.make({
|
|
3997
|
+
stage: err.stage,
|
|
3998
|
+
reason: err.reason,
|
|
3999
|
+
cause: err
|
|
4000
|
+
});
|
|
4001
|
+
}
|
|
4002
|
+
return {
|
|
4003
|
+
...raw.prev,
|
|
4004
|
+
project: raw.instrumentedProject,
|
|
4005
|
+
mutants: raw.instrumentResult.mutants,
|
|
4006
|
+
sandbox: raw.sandbox,
|
|
4007
|
+
concurrency: {
|
|
4008
|
+
testRunners: raw.concurrency.testRunners,
|
|
4009
|
+
checkers: raw.concurrency.checkers
|
|
4124
4010
|
}
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
project: raw.instrumentedProject,
|
|
4128
|
-
mutants: raw.instrumentResult.mutants,
|
|
4129
|
-
sandbox: raw.sandbox,
|
|
4130
|
-
concurrency: {
|
|
4131
|
-
testRunners: raw.concurrency.testRunners,
|
|
4132
|
-
checkers: raw.concurrency.checkers
|
|
4133
|
-
}
|
|
4134
|
-
};
|
|
4135
|
-
}))
|
|
4136
|
-
});
|
|
4011
|
+
};
|
|
4012
|
+
})));
|
|
4137
4013
|
//#endregion
|
|
4138
4014
|
//#region src/MutationTest.schema.ts
|
|
4139
4015
|
var MutationTestCommand = class extends S.TaggedClass()("MutationTestCommand", {
|
|
@@ -4168,7 +4044,7 @@ const admitMutationTest = Workflow.make(MutationTestCommand, (command) => Match.
|
|
|
4168
4044
|
}, () => Result.succeed(MutationTestNoTests.make({}))), Match.orElse(() => Result.succeed(MutationTestProceed.make({})))));
|
|
4169
4045
|
//#endregion
|
|
4170
4046
|
//#region src/checker-mutant-wire.ts
|
|
4171
|
-
const CheckerMutantFromMutant = Mutant.pipe(S.decodeTo(CheckerMutantWire, SchemaTransformation.transform({
|
|
4047
|
+
const CheckerMutantFromMutant = Mutant.pipe(S.decodeTo(CheckerMutantWire, SchemaTransformation$1.transform({
|
|
4172
4048
|
decode: (m) => ({
|
|
4173
4049
|
id: m.id,
|
|
4174
4050
|
fileName: m.fileName,
|
|
@@ -4184,7 +4060,7 @@ const CheckerMutantFromMutant = Mutant.pipe(S.decodeTo(CheckerMutantWire, Schema
|
|
|
4184
4060
|
location: w.location
|
|
4185
4061
|
})
|
|
4186
4062
|
})));
|
|
4187
|
-
const wireRecordOf = (mutant) => Result.mapError(S.
|
|
4063
|
+
const wireRecordOf = (mutant) => Result.mapError(S.decodeResult(CheckerMutantFromMutant)(mutant), (error) => ({
|
|
4188
4064
|
id: mutant.id,
|
|
4189
4065
|
fileName: mutant.fileName,
|
|
4190
4066
|
reason: error.message
|
|
@@ -4501,35 +4377,29 @@ const logSkippedMutants = (checkerName, undescribable) => Match.value(undescriba
|
|
|
4501
4377
|
* that joins them back. The join is where the work is, and it is pure.
|
|
4502
4378
|
*/
|
|
4503
4379
|
const checkPlans = (checker, checkerName, plans, lookup) => {
|
|
4504
|
-
return
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
answers: { ...raw.answers }
|
|
4528
|
-
})),
|
|
4529
|
-
decide: admitCheckerAnswer,
|
|
4530
|
-
encode: (outcome) => outcome,
|
|
4531
|
-
write: (outcome, raw) => writeCheckerOutcome(plans, raw.checkerName, outcome)
|
|
4532
|
-
}).run({
|
|
4380
|
+
return Sandwich.read((command) => Effect$1.gen(function* () {
|
|
4381
|
+
const partitioned = Option.match(Option.fromUndefinedOr(command.lookup), {
|
|
4382
|
+
onSome: (known) => selectedFromLookup(command.plans, known),
|
|
4383
|
+
onNone: () => partitionMutantsForWire(command.plans)
|
|
4384
|
+
});
|
|
4385
|
+
yield* logSkippedMutants(command.checkerName, partitioned.undescribable);
|
|
4386
|
+
if (partitioned.undescribable.length > 0) yield* Metric.update(checkerMutantsSkipped, partitioned.undescribable.length);
|
|
4387
|
+
yield* Effect$1.annotateCurrentSpan({ "stryker.checker.skipped_mutants_count": partitioned.undescribable.length });
|
|
4388
|
+
const answers = yield* command.checker.check(command.checkerName, partitioned.wire);
|
|
4389
|
+
return {
|
|
4390
|
+
checkerName: command.checkerName,
|
|
4391
|
+
requestedIds: command.plans.map((plan) => plan.mutant.id),
|
|
4392
|
+
answers: {
|
|
4393
|
+
...compileErrorAnswersOf(partitioned.undescribable),
|
|
4394
|
+
...answers
|
|
4395
|
+
}
|
|
4396
|
+
};
|
|
4397
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(CheckerCommand.make({
|
|
4398
|
+
checkerName: raw.checkerName,
|
|
4399
|
+
requestedIds: [...raw.requestedIds],
|
|
4400
|
+
phase: "check",
|
|
4401
|
+
answers: { ...raw.answers }
|
|
4402
|
+
})))).decide(admitCheckerAnswer).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => writeCheckerOutcome(plans, raw.checkerName, outcome)).run({
|
|
4533
4403
|
checker,
|
|
4534
4404
|
checkerName,
|
|
4535
4405
|
plans,
|
|
@@ -4540,31 +4410,25 @@ const checkPlans = (checker, checkerName, plans, lookup) => {
|
|
|
4540
4410
|
* Ask a checker how to group run plans, and get groups of run plans back.
|
|
4541
4411
|
*/
|
|
4542
4412
|
const groupPlans = (checker, checkerName, plans, lookup) => {
|
|
4543
|
-
return
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
idGroups: raw.idGroups.map((group) => [...group])
|
|
4563
|
-
})),
|
|
4564
|
-
decide: admitCheckerAnswer,
|
|
4565
|
-
encode: (outcome) => outcome,
|
|
4566
|
-
write: (outcome, raw) => writeGroupOutcome(plans, raw.checkerName, outcome)
|
|
4567
|
-
}).run({
|
|
4413
|
+
return Sandwich.read((command) => Effect$1.gen(function* () {
|
|
4414
|
+
const partitioned = Option.match(Option.fromUndefinedOr(command.lookup), {
|
|
4415
|
+
onSome: (known) => selectedFromLookup(command.plans, known),
|
|
4416
|
+
onNone: () => partitionMutantsForWire(command.plans)
|
|
4417
|
+
});
|
|
4418
|
+
yield* Effect$1.annotateCurrentSpan({ "stryker.checker.skipped_mutants_count": partitioned.undescribable.length });
|
|
4419
|
+
const undescribableIds = undescribableIdsOf(partitioned.undescribable);
|
|
4420
|
+
const withoutSkipped = (yield* command.checker.group(command.checkerName, partitioned.wire)).map((group) => group.filter((id) => !undescribableIds.has(id))).filter((group) => group.length > 0);
|
|
4421
|
+
return {
|
|
4422
|
+
checkerName: command.checkerName,
|
|
4423
|
+
requestedIds: command.plans.map((plan) => plan.mutant.id),
|
|
4424
|
+
idGroups: [...singletonGroupsOf(partitioned.undescribable), ...withoutSkipped]
|
|
4425
|
+
};
|
|
4426
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(CheckerCommand.make({
|
|
4427
|
+
checkerName: raw.checkerName,
|
|
4428
|
+
requestedIds: [...raw.requestedIds],
|
|
4429
|
+
phase: "group",
|
|
4430
|
+
idGroups: raw.idGroups.map((group) => [...group])
|
|
4431
|
+
})))).decide(admitCheckerAnswer).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => writeGroupOutcome(plans, raw.checkerName, outcome)).run({
|
|
4568
4432
|
checker,
|
|
4569
4433
|
checkerName,
|
|
4570
4434
|
plans,
|
|
@@ -4800,7 +4664,7 @@ function embeddedConfig(report) {
|
|
|
4800
4664
|
}
|
|
4801
4665
|
function breakThreshold(thresholds) {
|
|
4802
4666
|
const ThresholdsBreakSchema = S.StructWithRest(S.Struct({ break: S.optional(S.Union([S.Finite, S.Null])) }), [S.Record(S.String, S.Unknown)]);
|
|
4803
|
-
const decoded = S.
|
|
4667
|
+
const decoded = S.decodeOption(ThresholdsBreakSchema)(thresholds);
|
|
4804
4668
|
return Option.getOrNull(Option.flatMap(decoded, (value) => Option.fromNullishOr(value.break)));
|
|
4805
4669
|
}
|
|
4806
4670
|
const actionableMutants = (files) => Object.entries(files).flatMap(([file, fileResult]) => fileResult.mutants.filter((mutant) => isActionableStatus(mutant.status)).map((mutant) => ({
|
|
@@ -4965,7 +4829,7 @@ const makeMutationReportingService = (input) => {
|
|
|
4965
4829
|
const resolved = yield* Effect$1.try(() => new URL(import.meta.resolve(`${specifier}/package.json`)));
|
|
4966
4830
|
const manifestPath = yield* pathService.fromFileUrl(resolved);
|
|
4967
4831
|
const text = yield* fs.readFileString(manifestPath);
|
|
4968
|
-
return Result.match(S.
|
|
4832
|
+
return Result.match(S.decodeResult(S.fromJsonString(ManifestSchema))(text), {
|
|
4969
4833
|
onFailure: () => Option.none(),
|
|
4970
4834
|
onSuccess: (manifest) => Option.some(manifest.version ?? "")
|
|
4971
4835
|
});
|
|
@@ -5215,160 +5079,168 @@ const reportDroppedMutants = (dropped) => Match.value(dropped.length).pipe(Match
|
|
|
5215
5079
|
yield* Metric.update(checkerMutantsSkipped, dropped.length);
|
|
5216
5080
|
yield* Effect$1.logWarning(`${dropped.length} mutant(s) cannot be described to a checker and were left out of the run (${droppedIdsOf(dropped)})`);
|
|
5217
5081
|
})));
|
|
5218
|
-
const mutationTestCell$1 =
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5082
|
+
const mutationTestCell$1 = Sandwich.read((command) => Effect$1.gen(function* () {
|
|
5083
|
+
yield* Scope.Scope;
|
|
5084
|
+
return { prev: command };
|
|
5085
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(MutationTestCommand.make({
|
|
5086
|
+
dryRunOnly: raw.prev.options.dryRunOnly,
|
|
5087
|
+
allowEmpty: raw.prev.options.allowEmpty,
|
|
5088
|
+
testCount: raw.prev.dryRunResult.tests.length,
|
|
5089
|
+
isZero: raw.prev.dryRunResult.tests.length === 0
|
|
5090
|
+
})))).decide(admitMutationTest).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => {
|
|
5091
|
+
const { dropped, plannable: plannableMutants } = partitionPlannable(raw.prev.mutants);
|
|
5092
|
+
return withPhaseSpan("mutationTest", {
|
|
5093
|
+
mutantCount: raw.prev.mutants.length,
|
|
5094
|
+
skippedMutantCount: dropped.length,
|
|
5095
|
+
testCount: raw.prev.dryRunResult.tests.length
|
|
5096
|
+
}, () => Effect$1.gen(function* () {
|
|
5097
|
+
yield* reportDroppedMutants(dropped);
|
|
5098
|
+
const decision = yield* Result.match(outcome, {
|
|
5099
|
+
onFailure: (err) => Effect$1.fail(StageError.make({
|
|
5100
|
+
stage: err.stage,
|
|
5101
|
+
reason: err.reason,
|
|
5102
|
+
cause: err
|
|
5103
|
+
})),
|
|
5104
|
+
onSuccess: (d) => Effect$1.succeed(d)
|
|
5105
|
+
});
|
|
5106
|
+
return yield* Match.value(decision).pipe(Match.tag("MutationTestDryRunOnly", () => Effect$1.gen(function* () {
|
|
5107
|
+
const env = yield* RunEnvironment;
|
|
5108
|
+
const queue = yield* RunEvents;
|
|
5109
|
+
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5110
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5111
|
+
phase: "mutation-test",
|
|
5112
|
+
elapsedMs: nowEmit - env.runStartedAt
|
|
5113
|
+
}));
|
|
5114
|
+
yield* Effect$1.logInfo("The dry-run has been completed successfully. No mutations have been executed.");
|
|
5115
|
+
return {
|
|
5116
|
+
results: [],
|
|
5117
|
+
verdict: null
|
|
5118
|
+
};
|
|
5119
|
+
})), Match.tag("MutationTestNoTests", () => Effect$1.gen(function* () {
|
|
5120
|
+
const env = yield* RunEnvironment;
|
|
5121
|
+
const queue = yield* RunEvents;
|
|
5122
|
+
const now = yield* Clock.currentTimeMillis;
|
|
5123
|
+
const elapsed = Duration.millis(now - env.runStartedAt);
|
|
5124
|
+
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
5125
|
+
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5126
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5127
|
+
phase: "mutation-test",
|
|
5128
|
+
elapsedMs: nowEmit - env.runStartedAt
|
|
5129
|
+
}));
|
|
5130
|
+
return {
|
|
5131
|
+
results: [],
|
|
5132
|
+
verdict: null
|
|
5133
|
+
};
|
|
5134
|
+
})), Match.tag("MutationTestProceed", () => Effect$1.gen(function* () {
|
|
5135
|
+
const prev = raw.prev;
|
|
5136
|
+
const env = yield* RunEnvironment;
|
|
5137
|
+
yield* Effect$1.gen(function* () {
|
|
5250
5138
|
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5251
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5252
|
-
phase: "mutation-test",
|
|
5253
|
-
elapsedMs: nowEmit - env.runStartedAt
|
|
5254
|
-
}));
|
|
5255
|
-
yield* Effect$1.logInfo("The dry-run has been completed successfully. No mutations have been executed.");
|
|
5256
|
-
return {
|
|
5257
|
-
results: [],
|
|
5258
|
-
verdict: null
|
|
5259
|
-
};
|
|
5260
|
-
})), Match.tag("MutationTestNoTests", () => Effect$1.gen(function* () {
|
|
5261
|
-
const env = yield* RunEnvironment;
|
|
5262
5139
|
const queue = yield* RunEvents;
|
|
5263
|
-
const now = yield* Clock.currentTimeMillis;
|
|
5264
|
-
const elapsed = Duration.millis(now - env.runStartedAt);
|
|
5265
|
-
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
5266
|
-
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5267
5140
|
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5268
5141
|
phase: "mutation-test",
|
|
5269
5142
|
elapsedMs: nowEmit - env.runStartedAt
|
|
5270
5143
|
}));
|
|
5144
|
+
});
|
|
5145
|
+
const idGenerator = yield* IdGenerator;
|
|
5146
|
+
const checkerPool = yield* makeCheckerPool(prev, idGenerator, env.basePath);
|
|
5147
|
+
const testRunnerContext = {
|
|
5148
|
+
options: prev.options,
|
|
5149
|
+
fileDescriptions: prev.project.fileDescriptions,
|
|
5150
|
+
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5151
|
+
idGenerator,
|
|
5152
|
+
retire: Effect$1.void,
|
|
5153
|
+
testFiles: prev.project.testFiles.map((file) => prev.sandbox.sandboxFileFor(file))
|
|
5154
|
+
};
|
|
5155
|
+
const testRunnerPool = yield* Pool.make({
|
|
5156
|
+
acquire: buildTestRunner(testRunnerContext, Effect$1.suspend(() => {
|
|
5157
|
+
const runnerConfigured = prev.options.testRunner;
|
|
5158
|
+
const runnerLabel = Match.value(runnerConfigured).pipe(Match.when(isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
5159
|
+
return resolveConfiguredWorkerSpawn({
|
|
5160
|
+
loaded: prev.loadedPlugins,
|
|
5161
|
+
kind: "TestRunner",
|
|
5162
|
+
configured: runnerConfigured
|
|
5163
|
+
}).pipe(Effect$1.mapError(missingWorkerEntry("mutationTest", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
5164
|
+
options: prev.options,
|
|
5165
|
+
fileDescriptions: prev.project.fileDescriptions,
|
|
5166
|
+
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5167
|
+
workerEntrypoint: spawn.entrypoint,
|
|
5168
|
+
idGenerator
|
|
5169
|
+
})));
|
|
5170
|
+
})),
|
|
5171
|
+
size: prev.concurrency.testRunners
|
|
5172
|
+
});
|
|
5173
|
+
const reporting = makeMutationReportingService({
|
|
5174
|
+
reporterStage: prev.reporterStage,
|
|
5175
|
+
options: prev.options,
|
|
5176
|
+
project: prev.project,
|
|
5177
|
+
testCoverage: prev.testCoverage,
|
|
5178
|
+
runId: env.runId,
|
|
5179
|
+
resolvedMode: env.resolvedMode,
|
|
5180
|
+
sandboxDirectory: prev.sandbox.workingDirectory,
|
|
5181
|
+
basePath: env.basePath
|
|
5182
|
+
});
|
|
5183
|
+
const sandboxFileByName = Object.fromEntries([...MutableHashMap.keys(prev.project.filesToMutate)].map((name) => [name, prev.sandbox.sandboxFileFor(name)]));
|
|
5184
|
+
const currentRelativeFiles = yield* readCurrentRelativeFiles(prev.project, env.basePath);
|
|
5185
|
+
const incremental = incrementalDiff({
|
|
5186
|
+
currentMutants: plannableMutants,
|
|
5187
|
+
testCoverage: prev.testCoverage,
|
|
5188
|
+
incrementalReport: prev.project.incrementalReport,
|
|
5189
|
+
currentRelativeFiles,
|
|
5190
|
+
basePath: env.basePath,
|
|
5191
|
+
force: prev.options.force
|
|
5192
|
+
});
|
|
5193
|
+
const rememberedResults = rememberedResultsOf(plannableMutants, incremental.remembered);
|
|
5194
|
+
yield* Effect$1.when(Effect$1.logInfo(`Incremental mode: reusing ${rememberedResults.length} mutant result(s), running ${incremental.mutants.length} mutant(s).`), Effect$1.succeed(rememberedResults.length > 0));
|
|
5195
|
+
const { runPlans, earlyResults: noCoverageResults } = partitionRunPlans(yield* decidePlans(incremental.mutants, prev.testCoverage, {
|
|
5196
|
+
disableBail: prev.options.disableBail,
|
|
5197
|
+
timeoutMS: prev.options.timeoutMS,
|
|
5198
|
+
timeoutFactor: prev.options.timeoutFactor,
|
|
5199
|
+
ignoreStatic: prev.options.ignoreStatic
|
|
5200
|
+
}, Duration.toMillis(prev.timeOverhead), void 0, sandboxFileByName));
|
|
5201
|
+
const sortedPlans = sortRunPlans(runPlans);
|
|
5202
|
+
const allPlansForReporter = [...sortedPlans];
|
|
5203
|
+
yield* offerReporterEvent(prev.reporterStage, MutationTestingPlanReady.make({
|
|
5204
|
+
total: allPlansForReporter.length + noCoverageResults.length + rememberedResults.length,
|
|
5205
|
+
plans: allPlansForReporter.map((plan) => ({
|
|
5206
|
+
mutantId: plan.mutant.id,
|
|
5207
|
+
plan: plan.plan,
|
|
5208
|
+
netTime: plan.netTime,
|
|
5209
|
+
reloadEnvironment: plan.runOptions.reloadEnvironment
|
|
5210
|
+
}))
|
|
5211
|
+
})).pipe(Effect$1.ignoreCause);
|
|
5212
|
+
{
|
|
5213
|
+
const queue2 = yield* RunEvents;
|
|
5214
|
+
yield* Queue.offer(queue2, PlanKnown.make({ total: allPlansForReporter.length + noCoverageResults.length }));
|
|
5215
|
+
}
|
|
5216
|
+
const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(checkerPool, sortedPlans, reporting);
|
|
5217
|
+
const testRunnerStream = Stream.fromIterable(passedPlans);
|
|
5218
|
+
const plannedTotal = allPlansForReporter.length + noCoverageResults.length + rememberedResults.length;
|
|
5219
|
+
const pathService = yield* Path.Path;
|
|
5220
|
+
const progressQueue = yield* RunEvents;
|
|
5221
|
+
const completedRef = yield* Ref.make(0);
|
|
5222
|
+
const preparedStreamableOf = (result) => {
|
|
5223
|
+
if (!isMutantStatus(result.status)) return;
|
|
5271
5224
|
return {
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
})), Match.tag("MutationTestProceed", () => Effect$1.gen(function* () {
|
|
5276
|
-
const prev = raw.prev;
|
|
5277
|
-
const env = yield* RunEnvironment;
|
|
5278
|
-
yield* Effect$1.gen(function* () {
|
|
5279
|
-
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5280
|
-
const queue = yield* RunEvents;
|
|
5281
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5282
|
-
phase: "mutation-test",
|
|
5283
|
-
elapsedMs: nowEmit - env.runStartedAt
|
|
5284
|
-
}));
|
|
5285
|
-
});
|
|
5286
|
-
const idGenerator = yield* IdGenerator;
|
|
5287
|
-
const checkerPool = yield* makeCheckerPool(prev, idGenerator, env.basePath);
|
|
5288
|
-
const testRunnerContext = {
|
|
5289
|
-
options: prev.options,
|
|
5290
|
-
fileDescriptions: prev.project.fileDescriptions,
|
|
5291
|
-
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5292
|
-
idGenerator,
|
|
5293
|
-
retire: Effect$1.void,
|
|
5294
|
-
testFiles: prev.project.testFiles.map((file) => prev.sandbox.sandboxFileFor(file))
|
|
5225
|
+
status: result.status,
|
|
5226
|
+
file: reportFileName(pathService.relative(env.basePath, result.fileName)),
|
|
5227
|
+
location: toSchemaLocation(result.location)
|
|
5295
5228
|
};
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
})),
|
|
5312
|
-
size: prev.concurrency.testRunners
|
|
5313
|
-
});
|
|
5314
|
-
const reporting = makeMutationReportingService({
|
|
5315
|
-
reporterStage: prev.reporterStage,
|
|
5316
|
-
options: prev.options,
|
|
5317
|
-
project: prev.project,
|
|
5318
|
-
testCoverage: prev.testCoverage,
|
|
5319
|
-
runId: env.runId,
|
|
5320
|
-
resolvedMode: env.resolvedMode,
|
|
5321
|
-
sandboxDirectory: prev.sandbox.workingDirectory,
|
|
5322
|
-
basePath: env.basePath
|
|
5323
|
-
});
|
|
5324
|
-
const sandboxFileByName = Object.fromEntries([...MutableHashMap.keys(prev.project.filesToMutate)].map((name) => [name, prev.sandbox.sandboxFileFor(name)]));
|
|
5325
|
-
const currentRelativeFiles = yield* readCurrentRelativeFiles(prev.project, env.basePath);
|
|
5326
|
-
const incremental = incrementalDiff({
|
|
5327
|
-
currentMutants: plannableMutants,
|
|
5328
|
-
testCoverage: prev.testCoverage,
|
|
5329
|
-
incrementalReport: prev.project.incrementalReport,
|
|
5330
|
-
currentRelativeFiles,
|
|
5331
|
-
basePath: env.basePath,
|
|
5332
|
-
force: prev.options.force
|
|
5333
|
-
});
|
|
5334
|
-
const rememberedResults = rememberedResultsOf(plannableMutants, incremental.remembered);
|
|
5335
|
-
yield* Effect$1.when(Effect$1.logInfo(`Incremental mode: reusing ${rememberedResults.length} mutant result(s), running ${incremental.mutants.length} mutant(s).`), Effect$1.succeed(rememberedResults.length > 0));
|
|
5336
|
-
const { runPlans, earlyResults: noCoverageResults } = partitionRunPlans(yield* decidePlans(incremental.mutants, prev.testCoverage, {
|
|
5337
|
-
disableBail: prev.options.disableBail,
|
|
5338
|
-
timeoutMS: prev.options.timeoutMS,
|
|
5339
|
-
timeoutFactor: prev.options.timeoutFactor,
|
|
5340
|
-
ignoreStatic: prev.options.ignoreStatic
|
|
5341
|
-
}, Duration.toMillis(prev.timeOverhead), void 0, sandboxFileByName));
|
|
5342
|
-
const sortedPlans = sortRunPlans(runPlans);
|
|
5343
|
-
const allPlansForReporter = [...sortedPlans];
|
|
5344
|
-
yield* offerReporterEvent(prev.reporterStage, MutationTestingPlanReady.make({
|
|
5345
|
-
total: allPlansForReporter.length + noCoverageResults.length + rememberedResults.length,
|
|
5346
|
-
plans: allPlansForReporter.map((plan) => ({
|
|
5347
|
-
mutantId: plan.mutant.id,
|
|
5348
|
-
plan: plan.plan,
|
|
5349
|
-
netTime: plan.netTime,
|
|
5350
|
-
reloadEnvironment: plan.runOptions.reloadEnvironment
|
|
5351
|
-
}))
|
|
5352
|
-
})).pipe(Effect$1.ignoreCause);
|
|
5353
|
-
{
|
|
5354
|
-
const queue2 = yield* RunEvents;
|
|
5355
|
-
yield* Queue.offer(queue2, PlanKnown.make({ total: allPlansForReporter.length + noCoverageResults.length }));
|
|
5356
|
-
}
|
|
5357
|
-
const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(checkerPool, sortedPlans, reporting);
|
|
5358
|
-
const testRunnerStream = Stream.fromIterable(passedPlans);
|
|
5359
|
-
const plannedTotal = allPlansForReporter.length + noCoverageResults.length + rememberedResults.length;
|
|
5360
|
-
const pathService = yield* Path.Path;
|
|
5361
|
-
const progressQueue = yield* RunEvents;
|
|
5362
|
-
const completedRef = yield* Ref.make(0);
|
|
5363
|
-
const preparedStreamableOf = (result) => {
|
|
5364
|
-
if (!isMutantStatus(result.status)) return;
|
|
5365
|
-
return {
|
|
5366
|
-
status: result.status,
|
|
5367
|
-
file: reportFileName(pathService.relative(env.basePath, result.fileName)),
|
|
5368
|
-
location: toSchemaLocation(result.location)
|
|
5369
|
-
};
|
|
5370
|
-
};
|
|
5371
|
-
const toStreamEvent = (result, completed, prepared) => MutantTested.make({
|
|
5229
|
+
};
|
|
5230
|
+
const toStreamEvent = (result, completed, prepared) => MutantTested.make({
|
|
5231
|
+
id: result.id,
|
|
5232
|
+
status: prepared.status,
|
|
5233
|
+
file: prepared.file,
|
|
5234
|
+
location: prepared.location,
|
|
5235
|
+
mutator: result.mutatorName,
|
|
5236
|
+
replacement: result.replacement,
|
|
5237
|
+
completed,
|
|
5238
|
+
total: plannedTotal
|
|
5239
|
+
});
|
|
5240
|
+
const offerFinished = (result, prepared) => Effect$1.gen(function* () {
|
|
5241
|
+
if (prepared === void 0) return;
|
|
5242
|
+
const completed = yield* Ref.updateAndGet(completedRef, (n) => n + 1);
|
|
5243
|
+
yield* Queue.offer(progressQueue, RunMutantTested.make({
|
|
5372
5244
|
id: result.id,
|
|
5373
5245
|
status: prepared.status,
|
|
5374
5246
|
file: prepared.file,
|
|
@@ -5377,90 +5249,76 @@ const mutationTestCell$1 = Cell.layer({
|
|
|
5377
5249
|
replacement: result.replacement,
|
|
5378
5250
|
completed,
|
|
5379
5251
|
total: plannedTotal
|
|
5380
|
-
});
|
|
5381
|
-
const offerFinished = (result, prepared) => Effect$1.gen(function* () {
|
|
5382
|
-
if (prepared === void 0) return;
|
|
5383
|
-
const completed = yield* Ref.updateAndGet(completedRef, (n) => n + 1);
|
|
5384
|
-
yield* Queue.offer(progressQueue, RunMutantTested.make({
|
|
5385
|
-
id: result.id,
|
|
5386
|
-
status: prepared.status,
|
|
5387
|
-
file: prepared.file,
|
|
5388
|
-
location: prepared.location,
|
|
5389
|
-
mutator: result.mutatorName,
|
|
5390
|
-
replacement: result.replacement,
|
|
5391
|
-
completed,
|
|
5392
|
-
total: plannedTotal
|
|
5393
|
-
}));
|
|
5394
|
-
return completed;
|
|
5395
|
-
});
|
|
5396
|
-
const reportStreamTested = (result, completed, prepared) => offerReporterEvent(prev.reporterStage, toStreamEvent(result, completed, prepared)).pipe(Effect$1.catchCause((cause) => Effect$1.logWarning("Reporter stream failed handling mutantTested", cause)));
|
|
5397
|
-
const offerStreamTested = (result, completed, prepared) => Option.match(Option.all([Option.fromNullishOr(completed), Option.fromNullishOr(prepared)]), {
|
|
5398
|
-
onNone: () => Effect$1.void,
|
|
5399
|
-
onSome: ([done, streamable]) => reportStreamTested(result, done, streamable)
|
|
5400
|
-
});
|
|
5401
|
-
const announceSettledMutant = (result) => Effect$1.gen(function* () {
|
|
5402
|
-
const prepared = preparedStreamableOf(result);
|
|
5403
|
-
const completed = yield* offerFinished(result, prepared);
|
|
5404
|
-
yield* offerStreamTested(result, completed, prepared);
|
|
5405
|
-
});
|
|
5406
|
-
yield* Effect$1.forEach([
|
|
5407
|
-
...rememberedResults,
|
|
5408
|
-
...noCoverageResults,
|
|
5409
|
-
...checkerResults
|
|
5410
|
-
], announceSettledMutant, {
|
|
5411
|
-
concurrency: 1,
|
|
5412
|
-
discard: true
|
|
5413
|
-
});
|
|
5414
|
-
const completedMutants = yield* Ref.make([
|
|
5415
|
-
...rememberedResults,
|
|
5416
|
-
...noCoverageResults,
|
|
5417
|
-
...checkerResults
|
|
5418
|
-
]);
|
|
5419
|
-
const checkpointGate = yield* Semaphore.make(1);
|
|
5420
|
-
yield* reporting.checkpoint(yield* Ref.get(completedMutants)).pipe(Effect$1.catchCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)));
|
|
5421
|
-
const persist = (result) => checkpointGate.withPermits(1)(Effect$1.gen(function* () {
|
|
5422
|
-
const next = yield* Ref.updateAndGet(completedMutants, (prev) => [...prev, result]);
|
|
5423
|
-
yield* reporting.checkpoint(next).pipe(Effect$1.catchCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)));
|
|
5424
5252
|
}));
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
const
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5253
|
+
return completed;
|
|
5254
|
+
});
|
|
5255
|
+
const reportStreamTested = (result, completed, prepared) => offerReporterEvent(prev.reporterStage, toStreamEvent(result, completed, prepared)).pipe(Effect$1.tapCause((cause) => Effect$1.logWarning("Reporter stream failed handling mutantTested", cause)), Effect$1.ignoreCause);
|
|
5256
|
+
const offerStreamTested = (result, completed, prepared) => Option.match(Option.all([Option.fromNullishOr(completed), Option.fromNullishOr(prepared)]), {
|
|
5257
|
+
onNone: () => Effect$1.void,
|
|
5258
|
+
onSome: ([done, streamable]) => reportStreamTested(result, done, streamable)
|
|
5259
|
+
});
|
|
5260
|
+
const announceSettledMutant = (result) => Effect$1.gen(function* () {
|
|
5261
|
+
const prepared = preparedStreamableOf(result);
|
|
5262
|
+
const completed = yield* offerFinished(result, prepared);
|
|
5263
|
+
yield* offerStreamTested(result, completed, prepared);
|
|
5264
|
+
});
|
|
5265
|
+
yield* Effect$1.forEach([
|
|
5266
|
+
...rememberedResults,
|
|
5267
|
+
...noCoverageResults,
|
|
5268
|
+
...checkerResults
|
|
5269
|
+
], announceSettledMutant, {
|
|
5270
|
+
concurrency: 1,
|
|
5271
|
+
discard: true
|
|
5272
|
+
});
|
|
5273
|
+
const completedMutants = yield* Ref.make([
|
|
5274
|
+
...rememberedResults,
|
|
5275
|
+
...noCoverageResults,
|
|
5276
|
+
...checkerResults
|
|
5277
|
+
]);
|
|
5278
|
+
const checkpointGate = yield* Semaphore.make(1);
|
|
5279
|
+
yield* reporting.checkpoint(yield* Ref.get(completedMutants)).pipe(Effect$1.tapCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)), Effect$1.ignoreCause);
|
|
5280
|
+
const persist = (result) => checkpointGate.withPermits(1)(Effect$1.gen(function* () {
|
|
5281
|
+
const next = yield* Ref.updateAndGet(completedMutants, (prev) => [...prev, result]);
|
|
5282
|
+
yield* reporting.checkpoint(next).pipe(Effect$1.tapCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)), Effect$1.ignoreCause);
|
|
5283
|
+
}));
|
|
5284
|
+
const runResults = yield* withPhaseSpan("mutationTest.batch", {
|
|
5285
|
+
total: plannedTotal,
|
|
5286
|
+
testRunners: prev.concurrency.testRunners
|
|
5287
|
+
}, () => Stream.mapEffect(testRunnerStream, (plan) => Effect$1.scoped(Effect$1.gen(function* () {
|
|
5288
|
+
const pool = testRunnerPool;
|
|
5289
|
+
const runner = yield* Pool.get(pool);
|
|
5290
|
+
const result = yield* runner.mutantRun(plan.runOptions).pipe(Effect$1.withSpan("stryker.testRunner.mutantRun", { attributes: {
|
|
5291
|
+
"stryker.mutant.id": plan.mutant.id,
|
|
5292
|
+
"stryker.mutant.mutator": plan.mutant.mutatorName,
|
|
5293
|
+
"stryker.mutant.file": plan.mutant.fileName
|
|
5294
|
+
} }), Effect$1.tap((runResult) => Effect$1.annotateCurrentSpan({ "stryker.mutant.status": runResult.status })), Effect$1.catchTags({
|
|
5295
|
+
OutOfMemoryError: (error) => invalidateSlot(pool, runner, error),
|
|
5296
|
+
ChildProcessCrashedError: (error) => invalidateSlot(pool, runner, error)
|
|
5297
|
+
}));
|
|
5298
|
+
const reported = yield* reporting.reportMutantRunResult(toReportedMutant(plan.mutant), result);
|
|
5299
|
+
const prepared = preparedStreamableOf(reported);
|
|
5300
|
+
const finished = yield* offerFinished(reported, prepared);
|
|
5301
|
+
yield* offerStreamTested(reported, finished, prepared);
|
|
5302
|
+
yield* persist(reported);
|
|
5303
|
+
return reported;
|
|
5304
|
+
})), { concurrency: Math.max(1, prev.concurrency.testRunners) }).pipe(Stream.runCollect, Effect$1.map((chunk) => [...chunk])));
|
|
5305
|
+
const allResults = [
|
|
5306
|
+
...rememberedResults,
|
|
5307
|
+
...noCoverageResults,
|
|
5308
|
+
...checkerResults,
|
|
5309
|
+
...runResults
|
|
5310
|
+
];
|
|
5311
|
+
const outcomeResult = yield* reporting.reportAll(allResults);
|
|
5312
|
+
const doneNow = yield* Clock.currentTimeMillis;
|
|
5313
|
+
const elapsed = Duration.millis(doneNow - env.runStartedAt);
|
|
5314
|
+
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
5315
|
+
return outcomeResult;
|
|
5316
|
+
})), Match.exhaustive);
|
|
5317
|
+
})).pipe(Effect$1.mapError((cause) => Match.value(cause).pipe(Match.tag("StageError", (stage) => stage), Match.tag("ChildProcessCrashedError", "OutOfMemoryError", "PlatformError", "TestRunnerFailed", () => StageError.make({
|
|
5318
|
+
stage: "mutationTest",
|
|
5319
|
+
reason: "Mutation testing failed",
|
|
5320
|
+
cause
|
|
5321
|
+
})), Match.exhaustive)));
|
|
5464
5322
|
});
|
|
5465
5323
|
//#endregion
|
|
5466
5324
|
//#region src/reporter-output.ts
|
|
@@ -5475,7 +5333,7 @@ const write = (stdio, channel, chunks) => Stream.run(Stream.fromIterable(chunks)
|
|
|
5475
5333
|
* that cannot compose Effects — its writes fire inside a synchronous for-await).
|
|
5476
5334
|
* Write errors are ignored like a broken pipe on a stream handle.
|
|
5477
5335
|
*
|
|
5478
|
-
* Note: effect 4.0.0-rc.
|
|
5336
|
+
* Note: effect 4.0.0-rc.116 exports the runner as `Effect.runPromise`; there is no
|
|
5479
5337
|
* `Runtime.runPromise` in this version (verified against the installed source) —
|
|
5480
5338
|
* do not invent that import.
|
|
5481
5339
|
*/
|
|
@@ -5887,7 +5745,7 @@ const rememberTerminalReport = (seen, event) => {
|
|
|
5887
5745
|
};
|
|
5888
5746
|
}), Match.orElse(() => void 0));
|
|
5889
5747
|
};
|
|
5890
|
-
const decodeClearTextReport = (terminal) => S.
|
|
5748
|
+
const decodeClearTextReport = (terminal) => S.decodeEffect(ClearTextReportCommand)({
|
|
5891
5749
|
_tag: "ClearTextReportCommand",
|
|
5892
5750
|
report: terminal.report,
|
|
5893
5751
|
metrics: terminal.metrics
|
|
@@ -6329,13 +6187,7 @@ const writePrepare = (outcome, raw) => withPhaseSpan("prepare", {}, (span) => Ef
|
|
|
6329
6187
|
reporterStage
|
|
6330
6188
|
};
|
|
6331
6189
|
}));
|
|
6332
|
-
const prepareCell =
|
|
6333
|
-
read: readPrepare,
|
|
6334
|
-
decode: decodePrepare,
|
|
6335
|
-
decide: planPrepare,
|
|
6336
|
-
encode: encodePrepareDecision,
|
|
6337
|
-
write: writePrepare
|
|
6338
|
-
});
|
|
6190
|
+
const prepareCell = Sandwich.read(readPrepare).decode(Sandwich.pure(decodePrepare)).decide(planPrepare).encode(Sandwich.pure((outcome) => Result.succeed(encodePrepareDecision(outcome)))).write(writePrepare);
|
|
6339
6191
|
//#endregion
|
|
6340
6192
|
//#region src/Run.ts
|
|
6341
6193
|
const RUN_EVENTS_QUEUE_BOUND = 256;
|
|
@@ -6385,7 +6237,7 @@ const framedEventOf = (decision) => Option.match(decision, {
|
|
|
6385
6237
|
onSome: (d) => Match.value(d).pipe(Match.tag("EventFramed", (framed) => Result.succeed(framed.event)), Match.tag("EventSuppressed", () => Result.fail(void 0)), Match.exhaustive)
|
|
6386
6238
|
});
|
|
6387
6239
|
var RunEventDrain = class extends Context.Service()("@systemfsoftware/stryker-js/run-event-stream/RunEventDrain") {};
|
|
6388
|
-
const drainOf = (stdio, framed) => Stream.run(framed, stdio.stdout({ endOnDone: true })).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.
|
|
6240
|
+
const drainOf = (stdio, framed) => Stream.run(framed, stdio.stdout({ endOnDone: true })).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_failed", cause)), Effect$1.ignoreCause);
|
|
6389
6241
|
const RunEventDrainLive = Layer.effect(RunEventDrain, Effect$1.gen(function* () {
|
|
6390
6242
|
const stdio = yield* Stdio.Stdio;
|
|
6391
6243
|
return RunEventDrain.of({
|
|
@@ -6552,7 +6404,7 @@ const RunEventDrainFileLive = Layer.effect(RunEventDrain, Effect$1.gen(function*
|
|
|
6552
6404
|
drainFramed: (framed) => Effect$1.gen(function* () {
|
|
6553
6405
|
const fileName = yield* Ref.get(fileNameRef);
|
|
6554
6406
|
yield* drainStdoutAndFile(fs, path, stdio, fileName, framed);
|
|
6555
|
-
}).pipe(Effect$1.
|
|
6407
|
+
}).pipe(Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_file_failed", cause)), Effect$1.ignoreCause),
|
|
6556
6408
|
setProgressStreamFile: (fileName) => Ref.set(fileNameRef, fileName)
|
|
6557
6409
|
});
|
|
6558
6410
|
}));
|