@systemfsoftware/stryker-js 17.0.1 → 22.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.
@@ -1,17 +1,18 @@
1
1
  import * as S from "effect/Schema";
2
+ import { Effect, Schema, SchemaGetter, SchemaIssue, SchemaTransformation } from "effect";
3
+ import * as Arr from "effect/Array";
4
+ import * as Effect$1 from "effect/Effect";
2
5
  import * as Option$1 from "effect/Option";
3
- import * as Order from "effect/Order";
6
+ import * as Order$1 from "effect/Order";
4
7
  import * as SchemaGetter$1 from "effect/SchemaGetter";
5
8
  import * as SchemaTransformation$1 from "effect/SchemaTransformation";
9
+ import { dual } from "effect/Function";
6
10
  import * as Context from "effect/Context";
7
- import { Effect, Schema, SchemaGetter, SchemaIssue, SchemaTransformation } from "effect";
8
- import * as Effect$1 from "effect/Effect";
9
11
  import * as Boolean$1 from "effect/Boolean";
10
12
  import * as Rpc from "effect/rpc/Rpc";
11
13
  import * as RpcGroup from "effect/rpc/RpcGroup";
12
14
  import * as RpcMiddleware from "effect/rpc/RpcMiddleware";
13
15
  import * as Match$1 from "effect/Match";
14
- import { dual } from "effect/Function";
15
16
  import * as Record$1 from "effect/Record";
16
17
  import * as Predicate$1 from "effect/Predicate";
17
18
  //#region ../stryker-js-plugin-interface/dist/rolldown-runtime-D7D4PA-g.mjs
@@ -27,6 +28,155 @@ var __exportAll = (all, no_symbols) => {
27
28
  };
28
29
  //#endregion
29
30
  //#region ../stryker-js-plugin-interface/dist/index.mjs
31
+ const RULE_IDS = [
32
+ "arid-logging",
33
+ "arid-telemetry",
34
+ "arid-time",
35
+ "arid-config-default",
36
+ "arid-memoization",
37
+ "redundant-relational",
38
+ "equivalent-to-original",
39
+ "duplicate-at-site",
40
+ "ignore-static",
41
+ "directive",
42
+ "excluded-mutator",
43
+ "ignorer",
44
+ "checker"
45
+ ];
46
+ const KEEP_ALL = "To keep these mutants, set `mutator.mutantSetPolicy: 'full'`.";
47
+ const ARID_CALLEE = "The callee must come from an `effect` import under any local name, or be `console` when nothing in scope rebinds or imports it. A call around a function never covers a mutant inside it; a call inside that function still does. The detail names the canonical callee, such as `Effect.logInfo`.";
48
+ const RULE_DOCUMENTATION = {
49
+ "arid-logging": `The mutant sits in a logging call (console.*, Logger, Effect.log*). ${ARID_CALLEE} ${KEEP_ALL}`,
50
+ "arid-telemetry": `The mutant sits in a telemetry span, annotation or metric (Effect.withSpan, annotate*, withLogSpan, Metric), or in a non-function argument of \`Effect.fn\` such as the span name and options. ${ARID_CALLEE} ${KEEP_ALL}`,
51
+ "arid-time": `The mutant sits in a time or schedule value (Duration, Schedule, Effect.sleep). ${ARID_CALLEE} ${KEEP_ALL}`,
52
+ "arid-config-default": `The mutant sits in a config default (Config.withDefault). ${ARID_CALLEE} ${KEEP_ALL}`,
53
+ "arid-memoization": `The mutant sits in a memoization wrapper (Effect.cached*). ${ARID_CALLEE} ${KEEP_ALL}`,
54
+ "redundant-relational": `Another mutant at the same relational operator already covers this one. ${KEEP_ALL}`,
55
+ "equivalent-to-original": `The mutant behaves exactly like the original code, so no test can kill it. ${KEEP_ALL} With detail \`tce\`, the TypeScript checker compiled it to the original's output; remove that checker from \`checkers\` to keep it.`,
56
+ "duplicate-at-site": `Another mutant at the same site produces the same code. ${KEEP_ALL} With detail \`tce\`, the TypeScript checker compiled both to the same output; remove that checker from \`checkers\` to keep it.`,
57
+ "ignore-static": "The mutant is static (it runs once at module load). To keep it, set `ignoreStatic: false`.",
58
+ directive: "A `// Stryker disable` comment covers the mutant. To keep it, remove or narrow the comment.",
59
+ "excluded-mutator": "Its mutator is listed in `mutator.excludedMutations`. To keep it, remove it from that list.",
60
+ ignorer: "An ignorer plugin from `ignorers` removed it; the detail is the plugin's reason, which a plugin with codes of its own starts with `<plugin>/<code>: `. To keep it, remove that plugin or change its rule.",
61
+ checker: "A checker plugin from `checkers` ignored it. To keep it, remove that plugin or change its rule."
62
+ };
63
+ const SETTLED_CODES_BY_STATUS = {
64
+ Killed: ["killed", "remembered"],
65
+ Survived: [
66
+ "covered-not-killed",
67
+ "coverage-not-measured",
68
+ "remembered"
69
+ ],
70
+ NoCoverage: ["not-covered", "remembered"],
71
+ Timeout: ["timed-out", "remembered"],
72
+ RuntimeError: ["runtime-error"],
73
+ CompileError: ["compile-error", "remembered"]
74
+ };
75
+ const SETTLED_CODES = Arr.dedupe(Object.values(SETTLED_CODES_BY_STATUS).flat());
76
+ const SETTLED_DOCUMENTATION = {
77
+ "covered-not-killed": "Survived: the tests that cover the mutant ran and none failed. Strengthen an assertion in one of its covering tests.",
78
+ "coverage-not-measured": "Survived: coverage analysis was off, so every test ran, none failed, and the run cannot name the covering tests. Set `coverageAnalysis: perTest` to learn them.",
79
+ "not-covered": "NoCoverage: no test executes the mutant's location. Add a test that reaches it.",
80
+ "timed-out": "Timeout: a test run with the mutant active exceeded its limit; the detail keeps the wall-clock or hit-limit text. A timeout counts as detected.",
81
+ "runtime-error": "RuntimeError: the test run crashed with the mutant active; the detail is the error message. It is left out of the score.",
82
+ "compile-error": "CompileError: the mutant does not compile; the detail is the checker's or runner's message. It is left out of the score.",
83
+ killed: "Killed: a test failed with the mutant active; the detail is the failure message.",
84
+ remembered: "The status comes from the previous run's report, and the mutant did not run again; the detail names that run's code when it had one. Run with `--full` to run it again. A reused Ignored mutant keeps its rule code instead."
85
+ };
86
+ const RUN_FAILURE_CODES = [
87
+ "initial-test-run-failed",
88
+ "config-invalid",
89
+ "plugin-load-failed",
90
+ "shard-reports-missing",
91
+ "shard-reports-overlap",
92
+ "score-below-break",
93
+ "new-survivors",
94
+ "budget-exceeded",
95
+ "mutation-runs-on-main-ci"
96
+ ];
97
+ const RUN_FAILURE_DOCUMENTATION = {
98
+ "initial-test-run-failed": "The test suite failed before any mutant ran, so no mutant was judged. Fix the failing tests the detail names.",
99
+ "config-invalid": "The Stryker configuration does not decode; the detail names the option. Fix that option.",
100
+ "plugin-load-failed": "A plugin did not load; the detail begins with its plugin-load failure reason (a missing, unsupported or unrecognised peer). Install or fix what it names.",
101
+ "shard-reports-missing": "`stryker merge` lacks a report for a planned shard; the detail names the missing mutants. Re-run the shards that hold them.",
102
+ "shard-reports-overlap": "`stryker merge` found one mutant in two shard reports; the detail names it. Re-run the shards from one plan.",
103
+ "score-below-break": "The mutation score fell below `thresholds.break`; the detail gives the score and the threshold. Kill survivors or lower the threshold.",
104
+ "new-survivors": "`stryker gate` found survivors absent from the committed baseline; the detail lists them. Kill them, or update the baseline when they are accepted.",
105
+ "budget-exceeded": "The run took longer than the budget baseline allows; the detail gives the actual and allowed seconds. Speed the run up or update the baseline.",
106
+ "mutation-runs-on-main-ci": "A local mutation run was refused: mutation runs only on main CI. Read its CI report."
107
+ };
108
+ const TOOL_REFUSAL_CODES = [
109
+ "report-missing",
110
+ "report-unreadable",
111
+ "unknown-mutant-id",
112
+ "cursor-stale",
113
+ "rerun-refused"
114
+ ];
115
+ const TOOL_REFUSAL_DOCUMENTATION = {
116
+ "report-missing": "The finished mutation report the tool reads does not exist. Run `stryker run` first.",
117
+ "report-unreadable": "The mutation report does not decode; the detail names the problem. Run `stryker run` to write it again.",
118
+ "unknown-mutant-id": "No mutant in the report has the id asked for; the detail names it. Ask for an id the report lists.",
119
+ "cursor-stale": "The page cursor belongs to a different report or filter. Restart paging without a cursor.",
120
+ "rerun-refused": "The rerun was refused; the detail says why. Fix what it names, then rerun."
121
+ };
122
+ const STABLE_CODE = "A stable code shared by every consumer: renaming or removing one is a breaking change.";
123
+ const IgnoreRuleId = S.Literals(RULE_IDS).mapMembers((members) => members.map((member) => member.annotate({ description: RULE_DOCUMENTATION[member.literal] }))).annotate({ description: `Why an Ignored mutant was removed. ${STABLE_CODE}` });
124
+ const SettledReasonCode = S.Literals(SETTLED_CODES).mapMembers((members) => members.map((member) => member.annotate({ description: SETTLED_DOCUMENTATION[member.literal] }))).annotate({ description: `Why a mutant that was judged has its status. ${STABLE_CODE}` });
125
+ const RunFailureCode = S.Literals(RUN_FAILURE_CODES).mapMembers((members) => members.map((member) => member.annotate({ description: RUN_FAILURE_DOCUMENTATION[member.literal] }))).annotate({ description: `Why a run failed or was refused. ${STABLE_CODE}` });
126
+ const ToolRefusalCode = S.Literals(TOOL_REFUSAL_CODES).mapMembers((members) => members.map((member) => member.annotate({ description: TOOL_REFUSAL_DOCUMENTATION[member.literal] }))).annotate({ description: `Why a CLI or MCP query was refused. ${STABLE_CODE}` });
127
+ const SEPARATOR = ": ";
128
+ const asLiteralPattern = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
129
+ const reasonPatternOf = (codes) => {
130
+ const source = `^(?:${codes.map(asLiteralPattern).join("|")})${SEPARATOR}[\\s\\S]*$`;
131
+ return S.isPattern(new RegExp(source, "u"), { arbitraryConstraint: { patterns: [{
132
+ source,
133
+ flags: "u"
134
+ }] } });
135
+ };
136
+ const malformedReason = (text) => new SchemaIssue.InvalidValue({ message: `expected "<code>${SEPARATOR}<detail>"` }, text);
137
+ const reasonPartsOf = (codes) => {
138
+ const Parts = S.Struct({
139
+ code: S.Literals(codes),
140
+ detail: S.String
141
+ });
142
+ const partsOf = (text) => Option$1.map(Option$1.fromNullishOr(codes.find((code) => text.startsWith(code) && text.startsWith(SEPARATOR, code.length))), (code) => ({
143
+ code,
144
+ detail: text.slice(code.length + 2)
145
+ }));
146
+ return {
147
+ Parts,
148
+ transformation: SchemaTransformation.makeTransformation({
149
+ decode: SchemaGetter.transformEffect((text) => Effect$1.fromOption(partsOf(text), () => malformedReason(text))),
150
+ encode: SchemaGetter.transform((parts) => `${parts.code}${SEPARATOR}${parts.detail}`)
151
+ })
152
+ };
153
+ };
154
+ const IgnoreStatusReasonText = S.String.check(reasonPatternOf(RULE_IDS));
155
+ const IgnoreStatusReason = IgnoreStatusReasonText.pipe(S.decodeTo(S.Struct({
156
+ code: IgnoreRuleId,
157
+ detail: S.String
158
+ }), reasonPartsOf(RULE_IDS).transformation));
159
+ const ignoreStatusReasonText = (parts) => `${parts.code}${SEPARATOR}${parts.detail}`;
160
+ const settledVariantOf = (status, codes) => {
161
+ const admitted = codes;
162
+ const { Parts, transformation } = reasonPartsOf(admitted);
163
+ return S.Struct({
164
+ status: S.Literal(status),
165
+ statusReason: S.String.check(reasonPatternOf(admitted)).pipe(S.decodeTo(Parts, transformation))
166
+ });
167
+ };
168
+ const StatusReason = S.Union([
169
+ S.Struct({
170
+ status: S.Literal("Ignored"),
171
+ statusReason: IgnoreStatusReason
172
+ }),
173
+ settledVariantOf("Killed", SETTLED_CODES_BY_STATUS.Killed),
174
+ settledVariantOf("Survived", SETTLED_CODES_BY_STATUS.Survived),
175
+ settledVariantOf("NoCoverage", SETTLED_CODES_BY_STATUS.NoCoverage),
176
+ settledVariantOf("Timeout", SETTLED_CODES_BY_STATUS.Timeout),
177
+ settledVariantOf("RuntimeError", SETTLED_CODES_BY_STATUS.RuntimeError),
178
+ settledVariantOf("CompileError", SETTLED_CODES_BY_STATUS.CompileError)
179
+ ]).pipe(S.toTaggedUnion("status")).annotate({ description: "A mutant status with its reason, `<code>: <detail>` decoded to `{ code, detail }`. Each status admits only its own codes; a Pending mutant has no reason." });
30
180
  /** A 1-based line: the first line of a file is line 1. */
31
181
  const Line = S.Int.check(S.isGreaterThanOrEqualTo(1));
32
182
  /** A 1-based column: the first character of a line is column 1. */
@@ -35,12 +185,12 @@ const Position$1 = S.Struct({
35
185
  line: Line,
36
186
  column: Column
37
187
  });
38
- const positionOrder = Order.combine(Order.mapInput(Order.Number, (position) => position.line), Order.mapInput(Order.Number, (position) => position.column));
188
+ const positionOrder = Order$1.combine(Order$1.mapInput(Order$1.Number, (position) => position.line), Order$1.mapInput(Order$1.Number, (position) => position.column));
39
189
  const inOrder = (order) => (ends) => ({
40
- start: Order.min(order)(ends.start, ends.end),
41
- end: Order.max(order)(ends.start, ends.end)
190
+ start: Order$1.min(order)(ends.start, ends.end),
191
+ end: Order$1.max(order)(ends.start, ends.end)
42
192
  });
43
- const notReversed = (order) => (ends) => Order.isLessThanOrEqualTo(order)(ends.start, ends.end);
193
+ const notReversed = (order) => (ends) => Order$1.isLessThanOrEqualTo(order)(ends.start, ends.end);
44
194
  const PositionEndsSchema = S.Struct({
45
195
  start: Position$1,
46
196
  end: Position$1
@@ -89,7 +239,8 @@ const RememberedStatusSchema = S.Literals([
89
239
  "Killed",
90
240
  "Timeout",
91
241
  "NoCoverage",
92
- "Ignored"
242
+ "Ignored",
243
+ "CompileError"
93
244
  ]);
94
245
  const EphemeralStatusSchema = S.Literals([
95
246
  "CompileError",
@@ -102,6 +253,15 @@ const ActionableStatusSchema = S.Literals([
102
253
  "Timeout",
103
254
  "RuntimeError"
104
255
  ]);
256
+ const SettledStatusSchema = MutantStatusSchema.pick([
257
+ "Killed",
258
+ "Survived",
259
+ "NoCoverage",
260
+ "CompileError",
261
+ "RuntimeError",
262
+ "Timeout",
263
+ "Pending"
264
+ ]);
105
265
  const MutantId = S.String.check(S.isPattern(/^[0-9a-f]{16}$/u, { expected: "a 16-character lowercase hexadecimal mutant id" })).pipe(S.brand("MutantId"));
106
266
  const MutatorNameGrammar = S.String.check(S.isPattern(/^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*\/)?[A-Z][A-Za-z0-9]*$/u, { expected: "a PascalCase mutator name, optionally prefixed by a lowercase kebab-case namespace and a slash" }));
107
267
  const MutatorName = MutatorNameGrammar.pipe(S.brand("MutatorName"));
@@ -109,6 +269,67 @@ const CanonicalFileName = S.String.pipe(S.decodeTo(S.String.pipe(S.check(S.isPat
109
269
  decode: SchemaGetter$1.transform((fileName) => fileName.replace(/\\/g, "/")),
110
270
  encode: SchemaGetter$1.transform((canonical) => canonical)
111
271
  }));
272
+ const Subsumed = S.TaggedStruct("Subsumed", {
273
+ rule: S.Literals(["complement"]),
274
+ dominators: S.NonEmptyArray(MutantId)
275
+ });
276
+ const subsumedStatusReason = (subsumed) => ignoreStatusReasonText({
277
+ code: "redundant-relational",
278
+ detail: `subsumed by ${subsumed.dominators[0]} (${subsumed.rule}): every test that kills ${subsumed.dominators[0]} kills this mutant, so act on ${subsumed.dominators[0]}, or set mutator.mutantSetPolicy 'full' to run it`
279
+ });
280
+ /**
281
+ * Why a subsumed mutant ran after all: none of its dominators ran, and each
282
+ * cause names one dominator and why it did not run, in `dominators` order.
283
+ */
284
+ const ReadmitCauseCode = S.Literals([
285
+ "dominator-ignored-at-check",
286
+ "dominator-compile-error",
287
+ "dominator-ignored-at-plan",
288
+ "dominator-remembered-without-running",
289
+ "dominator-unsettled"
290
+ ]);
291
+ const Readmitted = S.TaggedStruct("Readmitted", {
292
+ rule: Subsumed.fields.rule,
293
+ causes: S.NonEmptyArray(S.Struct({
294
+ dominator: MutantId,
295
+ code: ReadmitCauseCode,
296
+ detail: S.String
297
+ }))
298
+ });
299
+ const Subsumption = S.Union([Subsumed, Readmitted]);
300
+ const ProbeKind = S.Literals([
301
+ "arithmetic",
302
+ "relational",
303
+ "unary",
304
+ "constant"
305
+ ]);
306
+ const Probed = S.TaggedStruct("Probed", { kind: ProbeKind });
307
+ /**
308
+ * Why a mutant carries no probe and runs exactly as it would without one:
309
+ * - `mutator-not-probed`: its mutator is outside the probed set.
310
+ * - `operator-not-probed`: its mutator is probed, but not for this original operator.
311
+ * - `every-reach-infects`: an `==`/`!=`/`===`/`!==` swap changes the value on every evaluation.
312
+ * - `not-a-comparison`: a constant replacement of an expression that is not a comparison.
313
+ * - `operand-not-proven-local`: a constant replacement of a comparison whose operand may run user code.
314
+ * - `shape-not-recognized`: the original and replacement nodes do not have the probed form.
315
+ * - `not-decided`: the mutant was built or decoded without an eligibility decision.
316
+ */
317
+ const UnprobedReason = S.Literals([
318
+ "mutator-not-probed",
319
+ "operator-not-probed",
320
+ "every-reach-infects",
321
+ "not-a-comparison",
322
+ "operand-not-proven-local",
323
+ "shape-not-recognized",
324
+ "not-decided"
325
+ ]);
326
+ const Unprobed = S.TaggedStruct("Unprobed", { reason: UnprobedReason });
327
+ const ProbeEligibility = S.Union([Probed, Unprobed]);
328
+ const NOT_DECIDED = {
329
+ _tag: "Unprobed",
330
+ reason: "not-decided"
331
+ };
332
+ const subsumptionMatchesStatus = dual(2, (subsumption, status) => S.is(Subsumed)(subsumption) ? status === "Ignored" : status !== "Ignored");
112
333
  /**
113
334
  * A mutant's file location in the mutation-testing-report-schema contract:
114
335
  * 1-based line and 1-based column, the same base the JSON report and the
@@ -126,8 +347,10 @@ const Mutant = S.TaggedStruct("Mutant", {
126
347
  coveredBy: S.String.pipe(S.Array, S.optional),
127
348
  static: S.optional(S.Boolean),
128
349
  testsCompleted: S.optional(S.Finite),
129
- description: S.optional(S.String)
130
- }).check(S.makeFilter((mutant) => mutant.statusReason === void 0 || mutant.status !== void 0, { message: "a mutant carries a status reason only together with a status" }));
350
+ description: S.optional(S.String),
351
+ subsumption: S.optional(Subsumption),
352
+ probeEligibility: ProbeEligibility.pipe(S.withConstructorDefault(Effect$1.succeed(NOT_DECIDED)), S.withDecodingDefaultKey(Effect$1.succeed(NOT_DECIDED)))
353
+ }).check(S.makeFilter((mutant) => mutant.statusReason === void 0 || mutant.status !== void 0, { message: "a mutant carries a status reason only together with a status" }), S.makeFilter((mutant) => mutant.subsumption === void 0 || subsumptionMatchesStatus(mutant.subsumption, mutant.status), { message: "a Subsumed mutant is Ignored, and a Readmitted mutant is not Ignored" }));
131
354
  const MutantFromUnknown = S.Unknown.pipe(S.decodeTo(Mutant));
132
355
  const RunOptionsFields = {
133
356
  timeout: S.Finite.pipe(S.check(S.isGreaterThanOrEqualTo(0))),
@@ -172,6 +395,14 @@ const CheckerMutantWire = S.Struct({
172
395
  replacement: S.String,
173
396
  location: Location$1
174
397
  });
398
+ /**
399
+ * The digest of the TypeScript program a checker loaded: SHA-256 over the sorted
400
+ * hashes of every source file in the program (lib and node_modules declarations
401
+ * included), every tsconfig in its chain, the TypeScript version, the checker
402
+ * plugin version, and the checker's options. A `CompileError` verdict is reusable
403
+ * only when two runs' digests are byte-equal, so a missing digest is never a match.
404
+ */
405
+ const ProgramDigest = S.String.check(S.isPattern(/^[0-9a-f]{64}$/u, { expected: "a 64-character lowercase hexadecimal program digest" })).pipe(S.brand("ProgramDigest"));
175
406
  const CheckResultSchema = S.Union([
176
407
  S.Struct({ status: S.Literal("passed") }),
177
408
  S.Struct({
@@ -180,7 +411,18 @@ const CheckResultSchema = S.Union([
180
411
  }),
181
412
  S.Struct({
182
413
  status: S.Literal("ignored"),
414
+ reason: IgnoreStatusReasonText
415
+ })
416
+ ]).pipe(S.toTaggedUnion("status"));
417
+ const CheckAnswerSchema = S.Union([
418
+ S.Struct({ status: S.Literal("passed") }),
419
+ S.Struct({
420
+ status: S.Literal("compileError"),
183
421
  reason: S.String
422
+ }),
423
+ S.Struct({
424
+ status: S.Literal("ignored"),
425
+ reason: S.optional(S.Unknown)
184
426
  })
185
427
  ]).pipe(S.toTaggedUnion("status"));
186
428
  const CheckStatus = S.Literals(CheckResultSchema.discriminants);
@@ -196,51 +438,16 @@ var CheckerFailed = class extends S.TaggedError()("CheckerFailed", {
196
438
  };
197
439
  var Checker = class extends Context.Service()("@systemfsoftware/stryker-js-plugin-interface/Checker.service/Checker") {};
198
440
  var Checker_exports = /* @__PURE__ */ __exportAll({
441
+ CheckAnswerSchema: () => CheckAnswerSchema,
199
442
  CheckResultSchema: () => CheckResultSchema,
200
443
  CheckStatus: () => CheckStatus,
201
444
  Checker: () => Checker,
202
445
  CheckerFailed: () => CheckerFailed,
203
- CheckerMutantWire: () => CheckerMutantWire
446
+ CheckerMutantWire: () => CheckerMutantWire,
447
+ ProgramDigest: () => ProgramDigest
204
448
  });
205
449
  S.TaggedError()("EvaluatorFailed", { cause: S.Unknown });
206
450
  Context.Service()("@systemfsoftware/stryker-js-plugin-interface/Evaluator.service/Evaluator");
207
- const RULE_IDS = [
208
- "arid-logging",
209
- "arid-telemetry",
210
- "arid-time",
211
- "arid-config-default",
212
- "arid-memoization",
213
- "redundant-relational",
214
- "equivalent-to-original",
215
- "duplicate-at-site",
216
- "ignore-static",
217
- "directive",
218
- "excluded-mutator",
219
- "ignorer"
220
- ];
221
- const IgnoreRuleId = S.Literals(RULE_IDS);
222
- const SEPARATOR = ": ";
223
- const asLiteralPattern = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
224
- const REASON_SOURCE = `^(?:${RULE_IDS.map(asLiteralPattern).join("|")})${SEPARATOR}[\\s\\S]*$`;
225
- const IgnoreStatusReasonText = S.String.check(S.isPattern(new RegExp(REASON_SOURCE, "u"), { arbitraryConstraint: { patterns: [{
226
- source: REASON_SOURCE,
227
- flags: "u"
228
- }] } }));
229
- const ReasonPartsSchema = S.Struct({
230
- ruleId: IgnoreRuleId,
231
- detail: S.String
232
- });
233
- const reasonPartsOf = (text) => Option$1.map(Option$1.fromNullishOr(RULE_IDS.find((ruleId) => text.startsWith(`${ruleId}${SEPARATOR}`))), (ruleId) => ({
234
- ruleId,
235
- detail: text.slice(ruleId.length + 2)
236
- }));
237
- const malformedReason = (text) => new SchemaIssue.InvalidValue({ message: `expected "<rule-id>${SEPARATOR}<detail>"` }, text);
238
- const partsOf$1 = SchemaGetter.transformEffect((text) => Effect$1.fromOption(reasonPartsOf(text), () => malformedReason(text)));
239
- const textOf$1 = SchemaGetter.transform((parts) => `${parts.ruleId}${SEPARATOR}${parts.detail}`);
240
- const IgnoreStatusReason = IgnoreStatusReasonText.pipe(S.decodeTo(ReasonPartsSchema, SchemaTransformation.makeTransformation({
241
- decode: partsOf$1,
242
- encode: textOf$1
243
- })));
244
451
  const Id = S.String.check(S.isPattern(/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u, { expected: "a lowercase kebab-case catalog entry id" })).pipe(S.brand("MutatorCatalogId"));
245
452
  const Tier = S.Literals(["default", "optIn"]);
246
453
  const Definition = S.NonEmptyString;
@@ -312,12 +519,28 @@ var Mutant_exports = /* @__PURE__ */ __exportAll({
312
519
  MutatorName: () => MutatorName,
313
520
  OpenEndLocation: () => OpenEndLocation$1,
314
521
  Position: () => Position$1,
522
+ ProbeEligibility: () => ProbeEligibility,
523
+ ProbeKind: () => ProbeKind,
524
+ Probed: () => Probed,
525
+ ReadmitCauseCode: () => ReadmitCauseCode,
526
+ Readmitted: () => Readmitted,
315
527
  RememberedStatusSchema: () => RememberedStatusSchema,
528
+ RunFailureCode: () => RunFailureCode,
316
529
  RunOptionsFields: () => RunOptionsFields,
530
+ SettledReasonCode: () => SettledReasonCode,
531
+ SettledStatusSchema: () => SettledStatusSchema,
532
+ StatusReason: () => StatusReason,
533
+ Subsumed: () => Subsumed,
534
+ Subsumption: () => Subsumption,
317
535
  SurvivorStatusSchema: () => SurvivorStatusSchema,
536
+ ToolRefusalCode: () => ToolRefusalCode,
537
+ Unprobed: () => Unprobed,
538
+ UnprobedReason: () => UnprobedReason,
318
539
  duplicatedValue: () => duplicatedValue,
319
540
  inOrder: () => inOrder,
320
- notReversed: () => notReversed
541
+ notReversed: () => notReversed,
542
+ subsumedStatusReason: () => subsumedStatusReason,
543
+ subsumptionMatchesStatus: () => subsumptionMatchesStatus
321
544
  });
322
545
  var MutatorCatalog_exports = /* @__PURE__ */ __exportAll({
323
546
  Catalog: () => Catalog,
@@ -728,7 +951,7 @@ const Thresholds = S.StructWithRest(S.Struct({
728
951
  "description": "Lower bound threshold.",
729
952
  "examples": [60]
730
953
  }).check(S.isInt().annotate({ "expected": "an integer" })).check(S.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" })).check(S.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" })),
731
- "break": S.optionalKey(S.Union([S.Finite.check(S.isFinite().annotate({ "expected": "a finite number" })).check(S.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" })).check(S.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" })), S.Null]).annotate({ "description": "The mutation score below which the run breaks. Null disables the break." }))
954
+ "break": S.optionalKey(S.Union([S.Finite.check(S.isGreaterThanOrEqualTo(0).annotate({ "expected": "a value greater than or equal to 0" })).check(S.isLessThanOrEqualTo(100).annotate({ "expected": "a value less than or equal to 100" })), S.Null]).annotate({ "description": "The mutation score below which the run breaks. Null disables the break." }))
732
955
  }), [S.Record(S.String, S.Json.annotate({ "expected": "JSON value" }))]).annotate({
733
956
  "title": "Thresholds",
734
957
  "description": "Thresholds for the status of the reported application.",
@@ -782,7 +1005,7 @@ const OSInformation = S.StructWithRest(S.Struct({
782
1005
  });
783
1006
  const CpuInformation = S.StructWithRest(S.Struct({
784
1007
  "baseClock": S.optionalKey(S.Finite.annotate({ "description": "Clock speed in MHz" }).check(S.isFinite().annotate({ "expected": "a finite number" }))),
785
- "logicalCores": S.Finite.check(S.isFinite().annotate({ "expected": "a finite number" })),
1008
+ "logicalCores": S.Finite,
786
1009
  "model": S.optionalKey(S.String.annotate({ "examples": ["Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz"] }))
787
1010
  }), [S.Record(S.String, S.Json.annotate({ "expected": "JSON value" }))]).annotate({
788
1011
  "title": "CpuInformation",
@@ -936,7 +1159,7 @@ const MutationTestResult = S.StructWithRest(S.Struct({
936
1159
  "2.0",
937
1160
  "2.0.0"
938
1161
  ]
939
- }).check(S.isPattern(/* @__PURE__ */ new RegExp("^([1-2])(\\.(([1-9]\\d*)|0)){0,2}$", "u")).annotate({ "expected": "a string matching the RegExp ^([1-2])(\\.(([1-9]\\d*)|0)){0,2}$" })),
1162
+ }).check(S.isPattern(new globalThis.RegExp("^([1-2])(\\.(([1-9]\\d*)|0)){0,2}$", "u")).annotate({ "expected": "a string matching the RegExp ^([1-2])(\\.(([1-9]\\d*)|0)){0,2}$" })),
940
1163
  "files": FileResultDictionary,
941
1164
  "testFiles": S.optionalKey(TestFileDefinitionDictionary),
942
1165
  "thresholds": Thresholds,
@@ -995,7 +1218,8 @@ const DryRunResultSchema = S.Union([
995
1218
  status: S.Literal("complete"),
996
1219
  tests: S.Array(TestResultSchema),
997
1220
  mutantCoverage: S.optionalKey(MutantCoverageSchema),
998
- globalTestInputs: S.String.pipe(S.Array, S.optionalKey)
1221
+ globalTestInputs: S.String.pipe(S.Array, S.optionalKey),
1222
+ testFileModules: S.optionalKey(S.Record(S.String, S.String.pipe(S.Array)))
999
1223
  }),
1000
1224
  S.Struct({
1001
1225
  status: S.Literal("timeout"),
@@ -1198,8 +1422,9 @@ const CheckerRequest = S.Struct({
1198
1422
  checkerName: S.String,
1199
1423
  mutants: S.Array(CheckerMutantWire)
1200
1424
  });
1201
- const CheckerCheckResult = S.Record(S.String, CheckResultSchema);
1425
+ const CheckerCheckResult = S.Record(S.String, CheckAnswerSchema);
1202
1426
  const CheckerGroupResult = S.String.pipe(S.Array, S.Array);
1427
+ const CheckerDigestRequest = S.Struct({ checkerName: S.String });
1203
1428
  const ReporterInitOptions = S.Struct({
1204
1429
  traceparent: S.optionalKey(Traceparent),
1205
1430
  tracestate: S.optionalKey(Tracestate)
@@ -1239,6 +1464,112 @@ const WorkerPluginSpawnSchema = S.Struct({
1239
1464
  });
1240
1465
  var PropagatedTrace = class extends Context.Service()("@systemfsoftware/stryker-js-plugin-interface/TraceContextRpc.service/PropagatedTrace") {};
1241
1466
  var TraceContextMiddleware = class extends RpcMiddleware.Service()("@systemfsoftware/stryker-js-plugin-interface/TraceContextMiddleware", { requiredForClient: true }) {};
1467
+ const TypeQueryVersion = S.Literals([1, 2]);
1468
+ const TypeQueryCandidate = S.Struct({
1469
+ candidateId: S.String,
1470
+ text: S.String
1471
+ });
1472
+ const TypeQuerySiteKind = S.Literals(["expression", "function-body"]);
1473
+ const TypeQuerySite = S.Struct({
1474
+ siteId: S.String,
1475
+ kind: TypeQuerySiteKind,
1476
+ location: Location$1,
1477
+ candidates: S.Array(TypeQueryCandidate)
1478
+ });
1479
+ const TypeQueryFile = S.Struct({
1480
+ fileName: S.String,
1481
+ content: S.String,
1482
+ sites: S.Array(TypeQuerySite)
1483
+ });
1484
+ const TypeQueryRequest = S.Struct({
1485
+ version: S.Int,
1486
+ tsconfigFile: S.String,
1487
+ files: S.NonEmptyArray(TypeQueryFile)
1488
+ });
1489
+ const UnknownReason = S.Literals([
1490
+ "candidate-not-context-free",
1491
+ "candidate-not-found",
1492
+ "site-not-found",
1493
+ "site-not-expression",
1494
+ "no-contextual-type",
1495
+ "error-type",
1496
+ "instantiable-target",
1497
+ "overloaded-or-generic-call",
1498
+ "context-not-enforced",
1499
+ "site-not-function-body",
1500
+ "candidate-not-empty-body",
1501
+ "return-type-not-declared",
1502
+ "generator-body",
1503
+ "constructor-body",
1504
+ "getter-requires-return",
1505
+ "implicit-return-rejected",
1506
+ "async-return-not-promise"
1507
+ ]);
1508
+ const TypeAnswerTypeId = Symbol.for("@systemfsoftware/stryker-js-plugin-interface/TypeAnswer");
1509
+ var Assignable = class extends S.TaggedClass()("Assignable", { candidateType: S.String }) {
1510
+ [TypeAnswerTypeId] = TypeAnswerTypeId;
1511
+ };
1512
+ var NotAssignable = class extends S.TaggedClass()("NotAssignable", {
1513
+ candidateType: S.String,
1514
+ contextualType: S.String
1515
+ }) {
1516
+ [TypeAnswerTypeId] = TypeAnswerTypeId;
1517
+ };
1518
+ var Unknown = class extends S.TaggedClass()("Unknown", { reason: UnknownReason }) {
1519
+ [TypeAnswerTypeId] = TypeAnswerTypeId;
1520
+ };
1521
+ const TypeAnswer = S.Union([
1522
+ Assignable,
1523
+ NotAssignable,
1524
+ Unknown
1525
+ ]);
1526
+ const CandidateAnswer = S.Struct({
1527
+ candidateId: S.String,
1528
+ answer: TypeAnswer
1529
+ });
1530
+ const SiteAnswer = S.Struct({
1531
+ siteId: S.String,
1532
+ siteType: S.OptionFromNullOr(S.String),
1533
+ contextualType: S.OptionFromNullOr(S.String),
1534
+ candidates: S.Array(CandidateAnswer)
1535
+ });
1536
+ const FileAnswered = S.TaggedStruct("FileAnswered", {
1537
+ fileName: S.String,
1538
+ sites: S.Array(SiteAnswer)
1539
+ });
1540
+ const FileRefusedReason = S.Literals([
1541
+ "not-in-project",
1542
+ "server-crashed",
1543
+ "query-timed-out"
1544
+ ]);
1545
+ const FileRefused = S.TaggedStruct("FileRefused", {
1546
+ fileName: S.String,
1547
+ reason: FileRefusedReason,
1548
+ nextAction: S.String
1549
+ });
1550
+ const FileOutcome = S.Union([FileAnswered, FileRefused]);
1551
+ const TypeQueryResponse = S.Struct({
1552
+ version: TypeQueryVersion,
1553
+ files: S.Array(FileOutcome)
1554
+ });
1555
+ const TypeQueryRefusedReason = S.Literals(["unsupported-version", "project-open-failed"]);
1556
+ var TypeQueryRefused = class extends S.TaggedError()("TypeQueryRefused", {
1557
+ version: S.Int,
1558
+ reason: TypeQueryRefusedReason,
1559
+ nextAction: S.String
1560
+ }) {
1561
+ get message() {
1562
+ return `${this.reason}: ${this.nextAction}`;
1563
+ }
1564
+ };
1565
+ const CheckerCapabilities = S.Struct({ typeQuery: S.Array(S.Int) });
1566
+ const TypeQueryServed = S.TaggedStruct("TypeQueryServed", { version: TypeQueryVersion });
1567
+ const TypeQueryNotServed = S.TaggedStruct("TypeQueryNotServed", {
1568
+ version: TypeQueryVersion,
1569
+ declared: S.Array(S.Int),
1570
+ nextAction: S.String
1571
+ });
1572
+ S.Union([TypeQueryServed, TypeQueryNotServed]);
1242
1573
  const capabilities = Rpc.make("capabilities", {
1243
1574
  success: TestRunnerCapabilitiesSchema,
1244
1575
  error: TestRunnerFailed
@@ -1264,6 +1595,21 @@ const group = Rpc.make("group", {
1264
1595
  success: CheckerGroupResult,
1265
1596
  error: CheckerFailed
1266
1597
  }).middleware(TraceContextMiddleware);
1598
+ const digest = Rpc.make("digest", {
1599
+ payload: CheckerDigestRequest,
1600
+ success: ProgramDigest,
1601
+ error: CheckerFailed
1602
+ }).middleware(TraceContextMiddleware);
1603
+ const checkerCapabilities = Rpc.make("capabilities", {
1604
+ payload: CheckerDigestRequest,
1605
+ success: CheckerCapabilities,
1606
+ error: CheckerFailed
1607
+ }).middleware(TraceContextMiddleware);
1608
+ const typeQuery = Rpc.make("typeQuery", {
1609
+ payload: TypeQueryRequest,
1610
+ success: TypeQueryResponse,
1611
+ error: TypeQueryRefused
1612
+ }).middleware(TraceContextMiddleware);
1267
1613
  const init = Rpc.make("init", {
1268
1614
  payload: ReporterInitOptions,
1269
1615
  success: ReporterAck,
@@ -1279,13 +1625,14 @@ const flush = Rpc.make("flush", {
1279
1625
  error: ReporterFailed
1280
1626
  }).middleware(TraceContextMiddleware);
1281
1627
  const TestRunnerRpcs = RpcGroup.make(capabilities, dryRun, mutantRun);
1282
- const CheckerRpcs = RpcGroup.make(check, group);
1628
+ const CheckerRpcs = RpcGroup.make(check, group, digest, checkerCapabilities, typeQuery);
1283
1629
  const ReporterRpcs = RpcGroup.make(init, onEventBatch, flush);
1284
1630
  var Plugin_exports = /* @__PURE__ */ __exportAll({
1285
1631
  BoundaryErrorSchema: () => BoundaryErrorSchema,
1286
1632
  BoundaryPayloadRejected: () => BoundaryPayloadRejected,
1287
1633
  BoundaryUnrecognizedSignal: () => BoundaryUnrecognizedSignal,
1288
1634
  CheckerCheckResult: () => CheckerCheckResult,
1635
+ CheckerDigestRequest: () => CheckerDigestRequest,
1289
1636
  CheckerGroupResult: () => CheckerGroupResult,
1290
1637
  CheckerRequest: () => CheckerRequest,
1291
1638
  CheckerRpcs: () => CheckerRpcs,
@@ -1427,6 +1774,16 @@ var Trace_exports = /* @__PURE__ */ __exportAll({
1427
1774
  Tracestate: () => Tracestate,
1428
1775
  TracestateHeader: () => TracestateHeader
1429
1776
  });
1777
+ const notServed = (capabilities, version) => TypeQueryNotServed.make({
1778
+ version,
1779
+ declared: capabilities.typeQuery,
1780
+ nextAction: `Keep every mutant: this checker declares type-query versions [${capabilities.typeQuery.join(", ")}], not ${version}. Use a checker that declares version ${version}, or send a version it declares.`
1781
+ });
1782
+ dual(2, (capabilities, version) => Boolean$1.match(Arr.contains(capabilities.typeQuery, version), {
1783
+ onTrue: () => TypeQueryServed.make({ version }),
1784
+ onFalse: () => notServed(capabilities, version)
1785
+ }));
1786
+ Context.Service()("@systemfsoftware/stryker-js-plugin-interface/TypeQuery.service/TypeQuery");
1430
1787
  //#endregion
1431
1788
  //#region src/config/merge-config.ts
1432
1789
  /**
@@ -1,4 +1,4 @@
1
- import { i as mod_d_exports$5 } from "./index-y-Pg3XgT.mjs";
1
+ import { i as mod_d_exports$5 } from "./index-ClWSuUog.mjs";
2
2
  import * as S from "effect/Schema";
3
3
  //#region src/config/stryker-config.schema.d.ts
4
4
  type StrykerConfig = mod_d_exports$5.PartialStrykerOptions;
@@ -1,5 +1,5 @@
1
- import { i as mod_d_exports$5 } from "./index-y-Pg3XgT.mjs";
2
- import { l as MutationTestDone } from "./RunEnvironment.service-Cluh-Bxt.mjs";
3
- //#region src/drivers/promise.d.ts
1
+ import { i as mod_d_exports$5 } from "./index-ClWSuUog.mjs";
2
+ import { d as MutationTestDone } from "./RunEnvironment.service-D4so1HnE.mjs";
3
+ //#region src/promises/run.d.ts
4
4
  export declare const run: ((targetMutatePatterns?: readonly string[]) => (options: mod_d_exports$5.PartialStrykerOptions) => Promise<MutationTestDone>) & ((options: mod_d_exports$5.PartialStrykerOptions, targetMutatePatterns?: readonly string[]) => Promise<MutationTestDone>);
5
5
  //#endregion
package/dist/promises.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { C as nodePlatformLayer, t as strykerCell } from "./run-stages-CpYiJ2Mz.mjs";
1
+ import { B as nodePlatformLayer, t as strykerCell } from "./run-stages-BnFibYAg.mjs";
2
2
  import * as Effect from "effect/Effect";
3
3
  import { dual } from "effect/Function";
4
- //#region src/drivers/promise.ts
4
+ //#region src/promises/run.ts
5
5
  const run = dual((args) => args.length === 2 || Array.isArray(args[0]) === false, (options, targetMutatePatterns) => Effect.runPromise(strykerCell(options, targetMutatePatterns).pipe(Effect.provide(nodePlatformLayer))));
6
6
  //#endregion
7
7
  export { run };