@systemfsoftware/stryker-js-instrumenter 10.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +3 -1
- package/dist/index.d.mts +172 -295
- package/dist/index.mjs +591 -308
- package/package.json +10 -7
package/dist/index.mjs
CHANGED
|
@@ -8,10 +8,14 @@ import * as S from "effect/Schema";
|
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
9
|
import { dual } from "effect/Function";
|
|
10
10
|
import { Handle, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
11
|
-
import
|
|
12
|
-
import * as SchemaGetter from "effect/SchemaGetter";
|
|
11
|
+
import { Mutant, Options } from "@systemfsoftware/stryker-js-plugin-interface";
|
|
13
12
|
import { RegExpParser, visitRegExpAST } from "@eslint-community/regexpp";
|
|
14
13
|
import * as Arr from "effect/Array";
|
|
14
|
+
import * as Order from "effect/Order";
|
|
15
|
+
import * as SchemaGetter from "effect/SchemaGetter";
|
|
16
|
+
import { SpanTaxonomy } from "@systemfsoftware/stryker-js-cli-contract";
|
|
17
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
18
|
+
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
15
19
|
//#region src/ErrorText.schema.ts
|
|
16
20
|
var ErrorText = class extends S.Class("ErrorText")({ text: S.NonEmptyString }) {};
|
|
17
21
|
var CauseText = class extends S.Class("CauseText")({ text: S.NonEmptyString }) {};
|
|
@@ -106,70 +110,8 @@ var ErrorText_exports = /* @__PURE__ */ __exportAll({
|
|
|
106
110
|
errorTextOf: () => errorTextOf$2
|
|
107
111
|
});
|
|
108
112
|
//#endregion
|
|
109
|
-
//#region src/Location.schema.ts
|
|
110
|
-
const Offset = S.Int.check(S.isGreaterThanOrEqualTo(0));
|
|
111
|
-
/** A 1-based line: the first line of a file is line 1. */
|
|
112
|
-
const Line = S.Int.check(S.isGreaterThanOrEqualTo(1));
|
|
113
|
-
/** A 1-based column: the first character of a line is column 1. */
|
|
114
|
-
const Column = S.Int.check(S.isGreaterThanOrEqualTo(1));
|
|
115
|
-
const Position = S.Struct({
|
|
116
|
-
line: Line,
|
|
117
|
-
column: Column
|
|
118
|
-
});
|
|
119
|
-
const positionOrder = Order.combine(Order.mapInput(Order.Number, (position) => position.line), Order.mapInput(Order.Number, (position) => position.column));
|
|
120
|
-
const inOrder = (order) => (ends) => ({
|
|
121
|
-
start: Order.min(order)(ends.start, ends.end),
|
|
122
|
-
end: Order.max(order)(ends.start, ends.end)
|
|
123
|
-
});
|
|
124
|
-
const notReversed = (order) => (ends) => Order.isLessThanOrEqualTo(order)(ends.start, ends.end);
|
|
125
|
-
const PositionEnds = S.Struct({
|
|
126
|
-
start: Position,
|
|
127
|
-
end: Position
|
|
128
|
-
});
|
|
129
|
-
const Location = S.declare((value) => S.is(PositionEnds)(value) && notReversed(positionOrder)(value), {
|
|
130
|
-
expected: "a location whose end is not before its start",
|
|
131
|
-
toCodecArbitrary: () => S.link()(PositionEnds, {
|
|
132
|
-
decode: SchemaGetter.transform(inOrder(positionOrder)),
|
|
133
|
-
encode: SchemaGetter.transform((ends) => ends)
|
|
134
|
-
})
|
|
135
|
-
});
|
|
136
|
-
const OpenEnds = S.Struct({
|
|
137
|
-
start: Position,
|
|
138
|
-
end: S.optional(Position)
|
|
139
|
-
});
|
|
140
|
-
const closedEnds = (ends) => Option.map(Option.fromUndefinedOr(ends.end), (end) => ({
|
|
141
|
-
start: ends.start,
|
|
142
|
-
end
|
|
143
|
-
}));
|
|
144
|
-
const OpenEndLocation = S.declare((value) => S.is(OpenEnds)(value) && Option.match(closedEnds(value), {
|
|
145
|
-
onNone: () => true,
|
|
146
|
-
onSome: notReversed(positionOrder)
|
|
147
|
-
}), {
|
|
148
|
-
expected: "a location whose end, when present, is not before its start",
|
|
149
|
-
toCodecArbitrary: () => S.link()(OpenEnds, {
|
|
150
|
-
decode: SchemaGetter.transform((ends) => Option.getOrElse(Option.map(closedEnds(ends), inOrder(positionOrder)), () => ends)),
|
|
151
|
-
encode: SchemaGetter.transform((ends) => ends)
|
|
152
|
-
})
|
|
153
|
-
});
|
|
154
|
-
const OffsetEnds = S.Struct({
|
|
155
|
-
start: Offset,
|
|
156
|
-
end: Offset
|
|
157
|
-
});
|
|
158
|
-
const Span = S.declare((value) => S.is(OffsetEnds)(value) && notReversed(Order.Number)(value), {
|
|
159
|
-
expected: "a span whose end is not before its start",
|
|
160
|
-
toCodecArbitrary: () => S.link()(OffsetEnds, {
|
|
161
|
-
decode: SchemaGetter.transform(inOrder(Order.Number)),
|
|
162
|
-
encode: SchemaGetter.transform((ends) => ends)
|
|
163
|
-
})
|
|
164
|
-
});
|
|
165
|
-
const ScriptOrigin = S.Struct({
|
|
166
|
-
line: Line,
|
|
167
|
-
columnShift: Offset
|
|
168
|
-
});
|
|
169
|
-
S.is(Offset), S.is(Line), S.is(Column), S.is(Location), S.is(Span);
|
|
170
|
-
//#endregion
|
|
171
113
|
//#region src/directives/directive.schema.ts
|
|
172
|
-
const MutatorNameSchema = S.String.pipe(S.check(S.isPattern(/^[a-zA-Z]
|
|
114
|
+
const MutatorNameSchema = S.String.pipe(S.check(S.isPattern(/^(?:[a-z][a-z0-9]*(?:-[a-z0-9]+)*\/)?[a-zA-Z][a-zA-Z0-9]*(?: [a-zA-Z][a-zA-Z0-9]*)*$/)));
|
|
173
115
|
const DirectiveReasonSchema = S.String.pipe(S.check(S.isPattern(/^\S(?:[^\r\n\u2028\u2029]*\S)?$/)));
|
|
174
116
|
const DirectiveSchema = S.Struct({
|
|
175
117
|
action: S.Literals(["disable", "restore"]),
|
|
@@ -179,106 +121,15 @@ const DirectiveSchema = S.Struct({
|
|
|
179
121
|
});
|
|
180
122
|
const LocatedDirectiveSchema = S.Struct({
|
|
181
123
|
directive: DirectiveSchema,
|
|
182
|
-
at: Position,
|
|
183
|
-
governedLine: Line
|
|
124
|
+
at: Mutant.Position,
|
|
125
|
+
governedLine: Mutant.Line
|
|
184
126
|
});
|
|
185
127
|
S.Struct({
|
|
186
128
|
directive: DirectiveSchema,
|
|
187
|
-
at: Position,
|
|
129
|
+
at: Mutant.Position,
|
|
188
130
|
mutatorName: MutatorNameSchema
|
|
189
131
|
});
|
|
190
132
|
//#endregion
|
|
191
|
-
//#region src/Mutant.schema.ts
|
|
192
|
-
const MutantStatusSchema = S.Literals([
|
|
193
|
-
"Killed",
|
|
194
|
-
"Survived",
|
|
195
|
-
"NoCoverage",
|
|
196
|
-
"CompileError",
|
|
197
|
-
"RuntimeError",
|
|
198
|
-
"Timeout",
|
|
199
|
-
"Ignored",
|
|
200
|
-
"Pending"
|
|
201
|
-
]);
|
|
202
|
-
const SurvivorStatusSchema = S.Literals(["Survived", "NoCoverage"]);
|
|
203
|
-
const RememberedStatusSchema = S.Literals([
|
|
204
|
-
"Survived",
|
|
205
|
-
"Killed",
|
|
206
|
-
"Timeout",
|
|
207
|
-
"NoCoverage",
|
|
208
|
-
"Ignored"
|
|
209
|
-
]);
|
|
210
|
-
const EphemeralStatusSchema = S.Literals([
|
|
211
|
-
"CompileError",
|
|
212
|
-
"RuntimeError",
|
|
213
|
-
"Pending"
|
|
214
|
-
]);
|
|
215
|
-
const ActionableStatusSchema = S.Literals([
|
|
216
|
-
"Survived",
|
|
217
|
-
"NoCoverage",
|
|
218
|
-
"Timeout",
|
|
219
|
-
"RuntimeError"
|
|
220
|
-
]);
|
|
221
|
-
const MutantId = S.String.check(S.isPattern(/^(0|[1-9][0-9]*)$/)).pipe(S.brand("MutantId"));
|
|
222
|
-
const MutatorName = S.NonEmptyString.pipe(S.brand("MutatorName"));
|
|
223
|
-
const CanonicalFileName = S.String.pipe(S.decodeTo(S.String.pipe(S.check(S.isPattern(/^[^\\]+$/)), S.brand("CanonicalFileName")), {
|
|
224
|
-
decode: SchemaGetter.transform((fileName) => fileName.replace(/\\/g, "/")),
|
|
225
|
-
encode: SchemaGetter.transform((canonical) => canonical)
|
|
226
|
-
}));
|
|
227
|
-
/**
|
|
228
|
-
* A mutant's file location in the mutation-testing-report-schema contract:
|
|
229
|
-
* 1-based line and 1-based column, the same base the JSON report and the
|
|
230
|
-
* machine stream emit. Every producer on the instrument path (node spans,
|
|
231
|
-
* embedded-region shifts) targets this base; no downstream layer converts.
|
|
232
|
-
*/
|
|
233
|
-
const Mutant = S.TaggedStruct("Mutant", {
|
|
234
|
-
id: MutantId,
|
|
235
|
-
fileName: CanonicalFileName,
|
|
236
|
-
mutatorName: MutatorName,
|
|
237
|
-
replacement: S.String,
|
|
238
|
-
location: Location,
|
|
239
|
-
status: S.optional(MutantStatusSchema),
|
|
240
|
-
statusReason: S.optional(S.String),
|
|
241
|
-
coveredBy: S.String.pipe(S.Array, S.optional),
|
|
242
|
-
static: S.optional(S.Boolean),
|
|
243
|
-
testsCompleted: S.optional(S.Finite),
|
|
244
|
-
description: S.optional(S.String)
|
|
245
|
-
}).check(S.makeFilter((mutant) => mutant.statusReason === void 0 || mutant.status !== void 0, { message: "a mutant carries a status reason only together with a status" }));
|
|
246
|
-
const MutantFromUnknown = S.Unknown.pipe(S.decodeTo(Mutant));
|
|
247
|
-
const RunOptionsFields = {
|
|
248
|
-
timeout: S.Finite.pipe(S.check(S.isGreaterThanOrEqualTo(0))),
|
|
249
|
-
disableBail: S.Boolean
|
|
250
|
-
};
|
|
251
|
-
const MutantActivationSchema = S.Literals(["runtime", "static"]);
|
|
252
|
-
const HitCount = S.Int.pipe(S.check(S.isGreaterThanOrEqualTo(0)));
|
|
253
|
-
const MutantRunOptionsSchema = S.Struct({
|
|
254
|
-
...RunOptionsFields,
|
|
255
|
-
activeMutant: Mutant,
|
|
256
|
-
sandboxFileName: S.String,
|
|
257
|
-
mutantActivation: MutantActivationSchema,
|
|
258
|
-
reloadEnvironment: S.Boolean,
|
|
259
|
-
testFilter: S.String.pipe(S.Array, S.optionalKey),
|
|
260
|
-
hitLimit: S.optionalKey(HitCount)
|
|
261
|
-
});
|
|
262
|
-
const MutantCoverageSchema = S.Struct({
|
|
263
|
-
perTest: S.Record(S.String, S.Record(MutantId, HitCount)),
|
|
264
|
-
static: S.Record(MutantId, HitCount)
|
|
265
|
-
});
|
|
266
|
-
var InstrumenterContext = class extends S.Class("InstrumenterContext")({
|
|
267
|
-
activeMutant: S.optional(S.String),
|
|
268
|
-
currentTestId: S.optional(S.String),
|
|
269
|
-
mutantCoverage: S.optional(MutantCoverageSchema),
|
|
270
|
-
hitCount: S.optional(HitCount),
|
|
271
|
-
hitLimit: S.optional(HitCount)
|
|
272
|
-
}) {
|
|
273
|
-
static NAMESPACE = "__stryker__";
|
|
274
|
-
static MUTATION_COVERAGE_OBJECT = "mutantCoverage";
|
|
275
|
-
static ACTIVE_MUTANT = "activeMutant";
|
|
276
|
-
static CURRENT_TEST_ID = "currentTestId";
|
|
277
|
-
static HIT_COUNT = "hitCount";
|
|
278
|
-
static HIT_LIMIT = "hitLimit";
|
|
279
|
-
static ACTIVE_MUTANT_ENV_VARIABLE = "__STRYKER_ACTIVE_MUTANT__";
|
|
280
|
-
};
|
|
281
|
-
//#endregion
|
|
282
133
|
//#region src/Instrument.schema.ts
|
|
283
134
|
var InstrumentError = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Instrument.schema/InstrumentError")("InstrumentError", {
|
|
284
135
|
message: S.String,
|
|
@@ -291,9 +142,9 @@ var InstrumentError = class extends S.TaggedError("@systemfsoftware/stryker-js-i
|
|
|
291
142
|
});
|
|
292
143
|
}
|
|
293
144
|
};
|
|
294
|
-
const MutateDescriptionSchema = S.Union([S.Boolean, S.Array(Location)]);
|
|
145
|
+
const MutateDescriptionSchema = S.Union([S.Boolean, S.Array(Mutant.Location)]);
|
|
295
146
|
const FileSchema = S.Struct({
|
|
296
|
-
name: CanonicalFileName,
|
|
147
|
+
name: Mutant.CanonicalFileName,
|
|
297
148
|
content: S.String,
|
|
298
149
|
mutate: MutateDescriptionSchema
|
|
299
150
|
});
|
|
@@ -301,8 +152,9 @@ const IgnorerSchema = S.Unknown;
|
|
|
301
152
|
S.Struct({
|
|
302
153
|
excludedMutations: S.Array(MutatorNameSchema),
|
|
303
154
|
ignorers: S.Array(IgnorerSchema),
|
|
304
|
-
|
|
305
|
-
|
|
155
|
+
mutators: S.Unknown,
|
|
156
|
+
mutantSetPolicy: Options.MutantSetPolicy,
|
|
157
|
+
noHeader: S.optional(S.Boolean)
|
|
306
158
|
});
|
|
307
159
|
var InstrumentFileSkip = class extends S.TaggedClass()("InstrumentFileSkip", {
|
|
308
160
|
file: S.String,
|
|
@@ -318,7 +170,7 @@ var InstrumentFilesCommand = class extends S.TaggedClass()("InstrumentFilesComma
|
|
|
318
170
|
};
|
|
319
171
|
var InstrumentResult = class extends S.TaggedClass()("InstrumentResult", {
|
|
320
172
|
files: S.Array(FileSchema),
|
|
321
|
-
mutants: S.Array(Mutant),
|
|
173
|
+
mutants: S.Array(Mutant.Mutant),
|
|
322
174
|
skipped: S.Array(InstrumentFileSkip)
|
|
323
175
|
}) {};
|
|
324
176
|
const PlacerNameSchema = S.Literals([
|
|
@@ -331,18 +183,96 @@ var MutantsUnapplied = class extends S.TaggedError()("MutantsUnapplied", {
|
|
|
331
183
|
placer: PlacerNameSchema,
|
|
332
184
|
mutatorNames: S.Array(MutatorNameSchema),
|
|
333
185
|
cause: S.Defect()
|
|
334
|
-
}) {
|
|
186
|
+
}) {
|
|
187
|
+
get message() {
|
|
188
|
+
return `Failed to apply ${this.mutatorNames.join(", ")} in ${this.fileName}`;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
335
191
|
var MutantNotApplied = class extends S.TaggedError()("MutantNotApplied", {
|
|
336
192
|
fileName: S.String,
|
|
337
193
|
mutatorName: MutatorNameSchema
|
|
338
|
-
}) {
|
|
339
|
-
|
|
194
|
+
}) {
|
|
195
|
+
get message() {
|
|
196
|
+
return `Could not apply the ${this.mutatorName} mutant in ${this.fileName}`;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
var NodeWithoutSpan = class extends S.TaggedError()("NodeWithoutSpan", { fileName: S.String }) {
|
|
200
|
+
get message() {
|
|
201
|
+
return `Node without a span in ${this.fileName}`;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
340
204
|
var MutantsUnplaced = class extends S.TaggedError()("MutantsUnplaced", {
|
|
341
205
|
fileName: S.String,
|
|
342
206
|
detail: S.String
|
|
343
|
-
}) {
|
|
207
|
+
}) {
|
|
208
|
+
get message() {
|
|
209
|
+
return `Mutants cannot be placed. This shouldn't happen! Unplaced mutants: ${this.detail}`;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
344
212
|
var PlacementRefused = class extends S.TaggedError()("PlacementRefused", { message: S.String }) {};
|
|
345
213
|
//#endregion
|
|
214
|
+
//#region src/relational-sufficient-sets.ts
|
|
215
|
+
/**
|
|
216
|
+
* The sufficient sets of non-redundant relational-operator mutations.
|
|
217
|
+
*
|
|
218
|
+
* Source: René Just and Franz Schweiggert, "Higher Accuracy and Lower Run Time:
|
|
219
|
+
* Efficient Mutation Analysis Using Non-Redundant Mutation Operators", Journal
|
|
220
|
+
* of Software Testing, Verification and Reliability 24(5), 2014, Table III
|
|
221
|
+
* (https://homes.cs.washington.edu/~rjust/publ/non_redundant_mutants_jstvr_2014.pdf).
|
|
222
|
+
*
|
|
223
|
+
* The paper groups every input tuple into the three intervals `a < b`,
|
|
224
|
+
* `a == b`, and `a > b`. For each relational operator exactly one
|
|
225
|
+
* minimal-distance mutation covers each interval, and those three mutations
|
|
226
|
+
* subsume every other relational replacement. Each row below lists the two
|
|
227
|
+
* replacement operators and the boolean the whole comparison collapses to. The
|
|
228
|
+
* sets assume numeric operands without `NaN`; `mutantSetPolicy: 'full'`
|
|
229
|
+
* restores every variant.
|
|
230
|
+
*/
|
|
231
|
+
const RELATIONAL_OPERATORS = [
|
|
232
|
+
"<",
|
|
233
|
+
"<=",
|
|
234
|
+
">",
|
|
235
|
+
">="
|
|
236
|
+
];
|
|
237
|
+
const isRelationalOperator = (operator) => RELATIONAL_OPERATORS.some((relational) => relational === operator);
|
|
238
|
+
const SUFFICIENT_RELATIONAL_SETS = {
|
|
239
|
+
"<": {
|
|
240
|
+
replacements: ["<=", "!="],
|
|
241
|
+
literal: false
|
|
242
|
+
},
|
|
243
|
+
"<=": {
|
|
244
|
+
replacements: ["<", "=="],
|
|
245
|
+
literal: true
|
|
246
|
+
},
|
|
247
|
+
">": {
|
|
248
|
+
replacements: [">=", "!="],
|
|
249
|
+
literal: false
|
|
250
|
+
},
|
|
251
|
+
">=": {
|
|
252
|
+
replacements: [">", "=="],
|
|
253
|
+
literal: true
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/Location.schema.ts
|
|
258
|
+
const Offset = S.Int.check(S.isGreaterThanOrEqualTo(0));
|
|
259
|
+
const OffsetEnds = S.Struct({
|
|
260
|
+
start: Offset,
|
|
261
|
+
end: Offset
|
|
262
|
+
});
|
|
263
|
+
const Span = S.declare((value) => S.is(OffsetEnds)(value) && Mutant.notReversed(Order.Number)(value), {
|
|
264
|
+
expected: "a span whose end is not before its start",
|
|
265
|
+
toCodecArbitrary: () => S.link()(OffsetEnds, {
|
|
266
|
+
decode: SchemaGetter.transform(Mutant.inOrder(Order.Number)),
|
|
267
|
+
encode: SchemaGetter.transform((ends) => ends)
|
|
268
|
+
})
|
|
269
|
+
});
|
|
270
|
+
const ScriptOrigin = S.Struct({
|
|
271
|
+
line: Mutant.Line,
|
|
272
|
+
columnShift: Offset
|
|
273
|
+
});
|
|
274
|
+
S.is(Offset), S.is(Span);
|
|
275
|
+
//#endregion
|
|
346
276
|
//#region src/Location.ts
|
|
347
277
|
const LINE_TERMINATOR = /\r\n|[\n\r\u2028\u2029]/g;
|
|
348
278
|
const lineStartsOf = (text) => [0, ...[...text.matchAll(LINE_TERMINATOR)].map((match) => match.index + match[0].length)];
|
|
@@ -370,7 +300,7 @@ const positionAtOffset = (lineStarts, offset, low, high, start) => Boolean$1.mat
|
|
|
370
300
|
})
|
|
371
301
|
});
|
|
372
302
|
const positionAt = dual(2, (lineStarts, offset) => positionAtOffset(lineStarts, offset, 0, lineStarts.length - 1, 0));
|
|
373
|
-
const locationOf = dual(2, (lineStarts, span) => Location.make({
|
|
303
|
+
const locationOf = dual(2, (lineStarts, span) => Mutant.Location.make({
|
|
374
304
|
start: positionAt(lineStarts, span.start),
|
|
375
305
|
end: positionAt(lineStarts, span.end)
|
|
376
306
|
}));
|
|
@@ -1407,7 +1337,7 @@ function toApiMutant(mutant) {
|
|
|
1407
1337
|
mutatorName: mutant.mutatorName,
|
|
1408
1338
|
replacement: mutant.replacementCode
|
|
1409
1339
|
};
|
|
1410
|
-
return S.decodeResult(Mutant)(mutant.ignoreReason === void 0 ? baseFields : {
|
|
1340
|
+
return S.decodeResult(Mutant.Mutant)(mutant.ignoreReason === void 0 ? baseFields : {
|
|
1411
1341
|
...baseFields,
|
|
1412
1342
|
statusReason: mutant.ignoreReason,
|
|
1413
1343
|
status: "Ignored"
|
|
@@ -1828,9 +1758,19 @@ const booleanOperators = Object.freeze([
|
|
|
1828
1758
|
">=",
|
|
1829
1759
|
"||"
|
|
1830
1760
|
]);
|
|
1831
|
-
const conditionalExpressionMutator = (node, context) => Match.value(isTestOfLoop(node, context)).pipe(Match.when(true, () => [booleanLiteral(false)]), Match.orElse(() => conditionTestMutants(node, context)));
|
|
1761
|
+
const conditionalExpressionMutator = (node, context) => Match.value(isTestOfLoop(node, context)).pipe(Match.when(true, () => withSufficientConditional(node, context, [booleanLiteral(false)])), Match.orElse(() => conditionTestMutants(node, context)));
|
|
1832
1762
|
function conditionTestMutants(node, context) {
|
|
1833
|
-
return Match.value(isTestOfCondition(node, context)).pipe(Match.when(true, () => [booleanLiteral(true), booleanLiteral(false)]), Match.orElse(() => booleanExpressionMutants(node, context)));
|
|
1763
|
+
return Match.value(isTestOfCondition(node, context)).pipe(Match.when(true, () => withSufficientConditional(node, context, [booleanLiteral(true), booleanLiteral(false)])), Match.orElse(() => booleanExpressionMutants(node, context)));
|
|
1764
|
+
}
|
|
1765
|
+
function withSufficientConditional(node, context, replacements) {
|
|
1766
|
+
const literal = sufficientRelationalLiteral(node, context);
|
|
1767
|
+
return literal === void 0 ? replacements : appendBooleanLiteral(replacements, literal);
|
|
1768
|
+
}
|
|
1769
|
+
function sufficientRelationalLiteral(node, context) {
|
|
1770
|
+
return Option.getOrUndefined(Option.map(Option.filter(Option.fromNullishOr(relationalSiteFacts(node, context)), (facts) => [facts.inConditionPosition, context.mutantSetPolicy === "default"].every(Boolean)), (facts) => SUFFICIENT_RELATIONAL_SETS[facts.operator].literal));
|
|
1771
|
+
}
|
|
1772
|
+
function appendBooleanLiteral(replacements, literal) {
|
|
1773
|
+
return replacements.some((replacement) => isBooleanLiteral(replacement) && replacement.value === literal) ? replacements : [...replacements, booleanLiteral(literal)];
|
|
1834
1774
|
}
|
|
1835
1775
|
function booleanExpressionMutants(node, context) {
|
|
1836
1776
|
return Match.value(isBooleanExpression(node)).pipe(Match.when(true, () => booleanExpressionReplacements(context)), Match.orElse(() => statementMutants(node)));
|
|
@@ -1893,6 +1833,40 @@ function isTestBearingStatement(node) {
|
|
|
1893
1833
|
function testOfStatement(node) {
|
|
1894
1834
|
return Match.value(node).pipe(Match.when(isTestBearingStatement, (statement) => statement.test ?? void 0), Match.orElse(() => void 0));
|
|
1895
1835
|
}
|
|
1836
|
+
const isConditionalExpression = (node) => node.type === "ConditionalExpression";
|
|
1837
|
+
function isTestOfConditionalExpression(node, context) {
|
|
1838
|
+
return Option.exists(Option.filter(Option.fromNullishOr(context.parent), isConditionalExpression), (parent) => parent.test === node);
|
|
1839
|
+
}
|
|
1840
|
+
function isConditionPosition(node, context) {
|
|
1841
|
+
return [
|
|
1842
|
+
isTestOfLoop(node, context),
|
|
1843
|
+
isTestOfCondition(node, context),
|
|
1844
|
+
isTestOfConditionalExpression(node, context)
|
|
1845
|
+
].some(Boolean);
|
|
1846
|
+
}
|
|
1847
|
+
function binaryOperatorOf(node) {
|
|
1848
|
+
return node.type === "BinaryExpression" ? node.operator : void 0;
|
|
1849
|
+
}
|
|
1850
|
+
const isRelationalComparison = (node) => Option.exists(Option.fromNullishOr(binaryOperatorOf(node)), isRelationalOperator);
|
|
1851
|
+
const relationalSiteFactsDataFirst = (node, context) => Option.getOrUndefined(Option.map(Option.filter(Option.fromNullishOr(binaryOperatorOf(node)), isRelationalOperator), (operator) => ({
|
|
1852
|
+
operator,
|
|
1853
|
+
inConditionPosition: isConditionPosition(node, context)
|
|
1854
|
+
})));
|
|
1855
|
+
const relationalSiteFacts = dual((args) => args.length >= 2, relationalSiteFactsDataFirst);
|
|
1856
|
+
const relationalSufficientDataFirst = (facts, replacement) => facts === void 0 ? true : sufficientInCondition(facts, replacement);
|
|
1857
|
+
function sufficientInCondition(facts, replacement) {
|
|
1858
|
+
return facts.inConditionPosition ? sufficientReplacementOf(facts, replacement) : true;
|
|
1859
|
+
}
|
|
1860
|
+
function sufficientReplacementOf(facts, replacement) {
|
|
1861
|
+
return Match.value(replacement).pipe(Match.when(isBooleanLiteral, (literal) => literal.value === SUFFICIENT_RELATIONAL_SETS[facts.operator].literal), Match.when(isBinaryExpressionNode, (binary) => isSufficientOperator(facts, binary.operator)), Match.orElse(() => true));
|
|
1862
|
+
}
|
|
1863
|
+
const relationalSufficientReplacement = dual((args) => args.length >= 2, relationalSufficientDataFirst);
|
|
1864
|
+
function isSufficientOperator(facts, operator) {
|
|
1865
|
+
return SUFFICIENT_RELATIONAL_SETS[facts.operator].replacements.some((sufficient) => sufficient === operator);
|
|
1866
|
+
}
|
|
1867
|
+
function isBinaryExpressionNode(node) {
|
|
1868
|
+
return node.type === "BinaryExpression";
|
|
1869
|
+
}
|
|
1896
1870
|
function isBooleanExpression(node) {
|
|
1897
1871
|
return isOperatorExpression(node) && booleanOperators.includes(node.operator);
|
|
1898
1872
|
}
|
|
@@ -1910,12 +1884,23 @@ const operators = {
|
|
|
1910
1884
|
"!==": ["==="]
|
|
1911
1885
|
};
|
|
1912
1886
|
const EQUALITY_OPERATOR_KEYS = Object.keys(operators);
|
|
1913
|
-
const equalityOperatorMutator = (node) => Match.value(node).pipe(Match.when(isEqualityBinary, (binary) => mutatedEqualityOperators(binary)), Match.orElse(() => NO_MUTANTS));
|
|
1887
|
+
const equalityOperatorMutator = (node, context) => Match.value(node).pipe(Match.when(isEqualityBinary, (binary) => mutatedEqualityOperators(binary, context)), Match.orElse(() => NO_MUTANTS));
|
|
1914
1888
|
function isEqualityBinary(node) {
|
|
1915
1889
|
return node.type === "BinaryExpression" && EQUALITY_OPERATOR_KEYS.includes(node.operator);
|
|
1916
1890
|
}
|
|
1917
|
-
function mutatedEqualityOperators(binary) {
|
|
1918
|
-
|
|
1891
|
+
function mutatedEqualityOperators(binary, context) {
|
|
1892
|
+
const base = operators[binary.operator].map((operator) => withOperator(binary, operator));
|
|
1893
|
+
return isRelationalConditionSite(binary, context) ? [...base, ...sufficientAdditions(binary)] : base;
|
|
1894
|
+
}
|
|
1895
|
+
function isRelationalConditionSite(node, context) {
|
|
1896
|
+
return [
|
|
1897
|
+
context.mutantSetPolicy === "default",
|
|
1898
|
+
isRelationalComparison(node),
|
|
1899
|
+
isConditionPosition(node, context)
|
|
1900
|
+
].every(Boolean);
|
|
1901
|
+
}
|
|
1902
|
+
function sufficientAdditions(binary) {
|
|
1903
|
+
return isRelationalOperator(binary.operator) ? SUFFICIENT_RELATIONAL_SETS[binary.operator].replacements.filter((operator) => !operators[binary.operator].some((replacement) => replacement === operator)).map((operator) => withOperator(binary, operator)) : NO_MUTANTS;
|
|
1919
1904
|
}
|
|
1920
1905
|
const logicalOperatorReplacements = Object.freeze({
|
|
1921
1906
|
"&&": "||",
|
|
@@ -2198,6 +2183,27 @@ const optInMutators = Object.freeze({
|
|
|
2198
2183
|
SynchronizationRemoval: synchronizationRemovalMutator,
|
|
2199
2184
|
FinalizerEscape: finalizerEscapeMutator
|
|
2200
2185
|
});
|
|
2186
|
+
const stockRegistry = {
|
|
2187
|
+
defaults: defaultMutators,
|
|
2188
|
+
optIn: optInMutators
|
|
2189
|
+
};
|
|
2190
|
+
const registryOfDataFirst = (catalogs, contributions) => {
|
|
2191
|
+
const implementations = new Map([
|
|
2192
|
+
...Object.entries(defaultMutators),
|
|
2193
|
+
...Object.entries(optInMutators),
|
|
2194
|
+
...contributions.flatMap(({ entries }) => entries.map((entry) => [entry.name, entry.implementation]))
|
|
2195
|
+
]);
|
|
2196
|
+
const entries = catalogs.flatMap((catalog) => catalog.entries);
|
|
2197
|
+
const entriesOfTier = (tier) => entries.filter((entry) => entry.tier === tier).flatMap((entry) => Option.match(Option.fromNullishOr(implementations.get(entry.name)), {
|
|
2198
|
+
onNone: () => [],
|
|
2199
|
+
onSome: (implementation) => [[entry.name, implementation]]
|
|
2200
|
+
}));
|
|
2201
|
+
return {
|
|
2202
|
+
defaults: Object.fromEntries(entriesOfTier("default")),
|
|
2203
|
+
optIn: Object.fromEntries(entriesOfTier("optIn"))
|
|
2204
|
+
};
|
|
2205
|
+
};
|
|
2206
|
+
const registryOf = dual((args) => args.length >= 2, registryOfDataFirst);
|
|
2201
2207
|
/**
|
|
2202
2208
|
* The entries a run applies, and the names its directives may reference.
|
|
2203
2209
|
*
|
|
@@ -2221,7 +2227,7 @@ const selectMutators = dual((args) => args.length >= 2, selectMutatorsDataFirst)
|
|
|
2221
2227
|
var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/ParseFailed")("ParseFailed", {
|
|
2222
2228
|
fileName: S.String,
|
|
2223
2229
|
message: S.String,
|
|
2224
|
-
location: Position,
|
|
2230
|
+
location: Mutant.Position,
|
|
2225
2231
|
cause: S.Defect()
|
|
2226
2232
|
}) {
|
|
2227
2233
|
get message() {
|
|
@@ -2232,7 +2238,7 @@ var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instr
|
|
|
2232
2238
|
//#region src/Parser.service.ts
|
|
2233
2239
|
const oxcModule = Effect.cached(Effect.promise(() => import("oxc-parser")));
|
|
2234
2240
|
const loadOxc = Effect.flatMap(oxcModule, (load) => load);
|
|
2235
|
-
const parseWithOxcDataFirst = Effect.fn(
|
|
2241
|
+
const parseWithOxcDataFirst = Effect.fn(SpanTaxonomy.Spans.instrumentParserParseWithOxc.name)(function* (text, fileName, lang) {
|
|
2236
2242
|
const result = (yield* loadOxc).parseSync(fileName, text, {
|
|
2237
2243
|
lang,
|
|
2238
2244
|
range: true
|
|
@@ -2259,7 +2265,7 @@ const oxcParseFailure = (errors, fileName, lineStarts) => Option.match(Option.fr
|
|
|
2259
2265
|
});
|
|
2260
2266
|
const oxcErrorLabelStart = (error) => Option.getOrElse(Option.map(Option.fromNullishOr(error.labels.at(0)), (label) => label.start), () => 0);
|
|
2261
2267
|
const createParser = () => ({ parse: (code, fileName, scriptFormat) => Match.value(scriptFormat).pipe(Match.when("js", () => parseJS(code, fileName)), Match.when("ts", () => parseTS(code, fileName)), Match.when("tsx", () => parseTsx(code, fileName)), Match.exhaustive) });
|
|
2262
|
-
const parseJSDataFirst = Effect.fn(
|
|
2268
|
+
const parseJSDataFirst = Effect.fn(SpanTaxonomy.Spans.instrumentParserParseJS.name)(function* (text, fileName) {
|
|
2263
2269
|
const parsed = yield* parseWithOxc(text, fileName, "js");
|
|
2264
2270
|
return {
|
|
2265
2271
|
originFileName: fileName,
|
|
@@ -2270,7 +2276,7 @@ const parseJSDataFirst = Effect.fn("stryker.instrument.parser.parseJS")(function
|
|
|
2270
2276
|
};
|
|
2271
2277
|
});
|
|
2272
2278
|
const parseJS = dual((args) => args.length >= 2, parseJSDataFirst);
|
|
2273
|
-
const parseTSDataFirst = Effect.fn(
|
|
2279
|
+
const parseTSDataFirst = Effect.fn(SpanTaxonomy.Spans.instrumentParserParseTS.name)(function* (text, fileName) {
|
|
2274
2280
|
const parsed = yield* parseWithOxc(text, fileName, "ts");
|
|
2275
2281
|
return {
|
|
2276
2282
|
originFileName: fileName,
|
|
@@ -2281,7 +2287,7 @@ const parseTSDataFirst = Effect.fn("stryker.instrument.parser.parseTS")(function
|
|
|
2281
2287
|
};
|
|
2282
2288
|
});
|
|
2283
2289
|
const parseTS = dual((args) => args.length >= 2, parseTSDataFirst);
|
|
2284
|
-
const parseTsxDataFirst = Effect.fn(
|
|
2290
|
+
const parseTsxDataFirst = Effect.fn(SpanTaxonomy.Spans.instrumentParserParseTsx.name)(function* (text, fileName) {
|
|
2285
2291
|
const parsed = yield* parseWithOxc(text, fileName, "tsx");
|
|
2286
2292
|
return {
|
|
2287
2293
|
root: parsed.root,
|
|
@@ -2766,7 +2772,7 @@ const logicalExpressionText = (ctx, node, prec) => {
|
|
|
2766
2772
|
};
|
|
2767
2773
|
const conditionalExpressionText = (ctx, node, prec) => {
|
|
2768
2774
|
const myPrec = PREC.Conditional;
|
|
2769
|
-
const testStr = wrapIfNeeded(ctx, node.test, precOf(node.test), myPrec,
|
|
2775
|
+
const testStr = wrapIfNeeded(ctx, node.test, precOf(node.test), myPrec, CONDITIONAL_TEST_WRAPPED_KINDS[node.test.type] === true);
|
|
2770
2776
|
const consStr = dispatchNode(ctx, node.consequent, PREC.Assignment);
|
|
2771
2777
|
const altStr = dispatchNode(ctx, node.alternate, PREC.Assignment);
|
|
2772
2778
|
return parenthesizedIf(myPrec < prec, `${testStr} ? ${consStr} : ${altStr}`);
|
|
@@ -3164,6 +3170,7 @@ const MEMBER_OBJECT_WRAPPED_KINDS = {
|
|
|
3164
3170
|
AwaitExpression: true,
|
|
3165
3171
|
YieldExpression: true
|
|
3166
3172
|
};
|
|
3173
|
+
const CONDITIONAL_TEST_WRAPPED_KINDS = { ConditionalExpression: true };
|
|
3167
3174
|
const CALLEE_WRAPPED_KINDS = {
|
|
3168
3175
|
SequenceExpression: true,
|
|
3169
3176
|
ConditionalExpression: true
|
|
@@ -3339,7 +3346,11 @@ var FormatOverrideUnclaimed = class extends S.TaggedError()("FormatOverrideUncla
|
|
|
3339
3346
|
fileName: S.String,
|
|
3340
3347
|
formatId: S.String,
|
|
3341
3348
|
reason: S.String
|
|
3342
|
-
}) {
|
|
3349
|
+
}) {
|
|
3350
|
+
get message() {
|
|
3351
|
+
return `Cannot instrument ${this.fileName}: ${this.reason}`;
|
|
3352
|
+
}
|
|
3353
|
+
};
|
|
3343
3354
|
const pinOf = (command) => Option.fromUndefinedOr(command.formatId);
|
|
3344
3355
|
const matchesCommand = (claim, command) => Match.value(pinOf(command)).pipe(Match.when(Option.isSome, (pin) => claim.formatId === pin.value), Match.orElse(() => claim.extensions.includes(command.extension)));
|
|
3345
3356
|
const claimFor = (command) => command.claims.find((claim) => matchesCommand(claim, command));
|
|
@@ -3380,9 +3391,117 @@ const resolveFormat = Workflow.make({
|
|
|
3380
3391
|
error: FormatOverrideUnclaimed,
|
|
3381
3392
|
decide: (command) => Match.value(selectionFor(command)).pipe(Match.tag("ClaimSelected", ({ claim }) => Result.succeed(assignedFrom(claim, command))), Match.tag("PinUnclaimed", ({ formatId }) => Result.fail(overrideUnclaimedFrom(command, formatId))), Match.tag("ExtensionUnclaimed", () => Result.succeed(skippedFrom(command))), Match.exhaustive)
|
|
3382
3393
|
});
|
|
3394
|
+
const AridRuleId = S.Literals([
|
|
3395
|
+
"arid-logging",
|
|
3396
|
+
"arid-telemetry",
|
|
3397
|
+
"arid-time",
|
|
3398
|
+
"arid-config-default",
|
|
3399
|
+
"arid-memoization"
|
|
3400
|
+
]);
|
|
3401
|
+
const AridCalleeSchema = S.Struct({
|
|
3402
|
+
object: S.String,
|
|
3403
|
+
member: S.String
|
|
3404
|
+
});
|
|
3405
|
+
const AridFrameSchema = S.Struct({
|
|
3406
|
+
callee: S.Option(AridCalleeSchema),
|
|
3407
|
+
childIsArgument: S.Boolean
|
|
3408
|
+
});
|
|
3409
|
+
const NAMED_LOGGERS = ["Logger", "console"];
|
|
3410
|
+
const readsNamespace = (callee, object) => callee.object === object;
|
|
3411
|
+
const readsName = (callee, name) => callee.member === name;
|
|
3412
|
+
const readsMember = (callee, object, member) => [readsNamespace(callee, object), readsName(callee, member)].every(Boolean);
|
|
3413
|
+
const readsMemberPrefixed = (callee, object, prefix) => [readsNamespace(callee, object), callee.member.startsWith(prefix)].every(Boolean);
|
|
3414
|
+
const ARID_RULES_IN_PRECEDENCE_ORDER = [
|
|
3415
|
+
{
|
|
3416
|
+
ruleId: "arid-logging",
|
|
3417
|
+
matches: (callee) => readsMemberPrefixed(callee, "Effect", "log")
|
|
3418
|
+
},
|
|
3419
|
+
{
|
|
3420
|
+
ruleId: "arid-logging",
|
|
3421
|
+
matches: (callee) => NAMED_LOGGERS.includes(callee.object)
|
|
3422
|
+
},
|
|
3423
|
+
{
|
|
3424
|
+
ruleId: "arid-telemetry",
|
|
3425
|
+
matches: (callee) => readsMember(callee, "Effect", "withSpan")
|
|
3426
|
+
},
|
|
3427
|
+
{
|
|
3428
|
+
ruleId: "arid-telemetry",
|
|
3429
|
+
matches: (callee) => readsMemberPrefixed(callee, "Effect", "annotate")
|
|
3430
|
+
},
|
|
3431
|
+
{
|
|
3432
|
+
ruleId: "arid-telemetry",
|
|
3433
|
+
matches: (callee) => readsMember(callee, "Effect", "withLogSpan")
|
|
3434
|
+
},
|
|
3435
|
+
{
|
|
3436
|
+
ruleId: "arid-telemetry",
|
|
3437
|
+
matches: (callee) => readsNamespace(callee, "Metric")
|
|
3438
|
+
},
|
|
3439
|
+
{
|
|
3440
|
+
ruleId: "arid-time",
|
|
3441
|
+
matches: (callee) => readsMember(callee, "Effect", "sleep")
|
|
3442
|
+
},
|
|
3443
|
+
{
|
|
3444
|
+
ruleId: "arid-time",
|
|
3445
|
+
matches: (callee) => readsNamespace(callee, "Schedule")
|
|
3446
|
+
},
|
|
3447
|
+
{
|
|
3448
|
+
ruleId: "arid-time",
|
|
3449
|
+
matches: (callee) => readsNamespace(callee, "Duration")
|
|
3450
|
+
},
|
|
3451
|
+
{
|
|
3452
|
+
ruleId: "arid-time",
|
|
3453
|
+
matches: (callee) => readsMember(callee, "Date", "now")
|
|
3454
|
+
},
|
|
3455
|
+
{
|
|
3456
|
+
ruleId: "arid-config-default",
|
|
3457
|
+
matches: (callee) => readsMember(callee, "Config", "withDefault")
|
|
3458
|
+
},
|
|
3459
|
+
{
|
|
3460
|
+
ruleId: "arid-memoization",
|
|
3461
|
+
matches: (callee) => readsMember(callee, "Effect", "cached")
|
|
3462
|
+
},
|
|
3463
|
+
{
|
|
3464
|
+
ruleId: "arid-memoization",
|
|
3465
|
+
matches: (callee) => readsMember(callee, "Effect", "cachedWithTTL")
|
|
3466
|
+
}
|
|
3467
|
+
];
|
|
3468
|
+
const ruleFor = (callee) => Option.map(Option.fromNullishOr(ARID_RULES_IN_PRECEDENCE_ORDER.find((rule) => rule.matches(callee))), (rule) => rule.ruleId);
|
|
3469
|
+
const calleeDetail = (callee) => `${callee.object}.${callee.member}`;
|
|
3470
|
+
var AridCodeCommand = class extends S.TaggedClass()("AridCodeCommand", {
|
|
3471
|
+
policy: Options.MutantSetPolicy,
|
|
3472
|
+
frames: S.Array(AridFrameSchema)
|
|
3473
|
+
}) {
|
|
3474
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
3475
|
+
};
|
|
3476
|
+
const AridCodeDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js-instrumenter/AridCodeDecision");
|
|
3477
|
+
var AridSuppressed = class extends S.TaggedClass()("AridSuppressed", {
|
|
3478
|
+
ruleId: AridRuleId,
|
|
3479
|
+
detail: S.String
|
|
3480
|
+
}) {
|
|
3481
|
+
[AridCodeDecisionTypeId] = AridCodeDecisionTypeId;
|
|
3482
|
+
};
|
|
3483
|
+
var AridKept = class extends S.TaggedClass()("AridKept", {}) {
|
|
3484
|
+
[AridCodeDecisionTypeId] = AridCodeDecisionTypeId;
|
|
3485
|
+
};
|
|
3486
|
+
const matchOfFrame = (frame) => Option.flatMap(Option.filter(frame.callee, () => frame.childIsArgument), (callee) => Option.map(ruleFor(callee), (ruleId) => ({
|
|
3487
|
+
ruleId,
|
|
3488
|
+
callee
|
|
3489
|
+
})));
|
|
3490
|
+
const firstMatch = (frames) => Option.firstSomeOf(frames.map(matchOfFrame));
|
|
3491
|
+
const defaultPolicyDecision = (frames) => Match.value(firstMatch(frames)).pipe(Match.when(Option.isSome, (found) => AridSuppressed.make({
|
|
3492
|
+
ruleId: found.value.ruleId,
|
|
3493
|
+
detail: calleeDetail(found.value.callee)
|
|
3494
|
+
})), Match.when(Option.isNone, () => AridKept.make({})), Match.exhaustive);
|
|
3495
|
+
const decisionFor = (command) => Match.value(command.policy).pipe(Match.when("default", () => defaultPolicyDecision(command.frames)), Match.when("full", () => AridKept.make({})), Match.exhaustive);
|
|
3496
|
+
const aridCode = Workflow.make({
|
|
3497
|
+
command: AridCodeCommand,
|
|
3498
|
+
decision: S.Union([AridSuppressed, AridKept]),
|
|
3499
|
+
error: S.Never,
|
|
3500
|
+
decide: (command) => Result.succeed(decisionFor(command))
|
|
3501
|
+
});
|
|
3383
3502
|
//#endregion
|
|
3384
3503
|
//#region src/directives/decode-directive.workflow.ts
|
|
3385
|
-
const DIRECTIVE_PATTERN = /^\s?Stryker (disable|restore)(?: (next-line))? ([a-zA-
|
|
3504
|
+
const DIRECTIVE_PATTERN = /^\s?Stryker (disable|restore)(?: (next-line))? ([a-zA-Z0-9,/ -]+)(?::(.+)?)?/;
|
|
3386
3505
|
const DEFAULT_REASON = "Ignored using a comment";
|
|
3387
3506
|
const NEXT_LINE$1 = "next-line";
|
|
3388
3507
|
var DecodeDirectiveCommand = class extends S.TaggedClass()("DecodeDirectiveCommand", { commentText: S.String }) {
|
|
@@ -3436,6 +3555,23 @@ const foldRule = Workflow.make({
|
|
|
3436
3555
|
decide: (command) => Match.value(command.directive.directive.action).pipe(Match.when("restore", () => Result.succeed(RestoreFolded.make({ rule: [...command.rule, command.directive] }))), Match.when("disable", () => Result.succeed(DisableFolded.make({ rule: [...command.rule, command.directive] }))), Match.exhaustive)
|
|
3437
3556
|
});
|
|
3438
3557
|
//#endregion
|
|
3558
|
+
//#region src/InstrumentContext.schema.ts
|
|
3559
|
+
var InstrumenterContext = class extends S.Class("InstrumenterContext")({
|
|
3560
|
+
activeMutant: S.optional(S.String),
|
|
3561
|
+
currentTestId: S.optional(S.String),
|
|
3562
|
+
mutantCoverage: S.optional(Mutant.MutantCoverageSchema),
|
|
3563
|
+
hitCount: S.optional(Mutant.HitCount),
|
|
3564
|
+
hitLimit: S.optional(Mutant.HitCount)
|
|
3565
|
+
}) {
|
|
3566
|
+
static NAMESPACE = "__stryker__";
|
|
3567
|
+
static MUTATION_COVERAGE_OBJECT = "mutantCoverage";
|
|
3568
|
+
static ACTIVE_MUTANT = "activeMutant";
|
|
3569
|
+
static CURRENT_TEST_ID = "currentTestId";
|
|
3570
|
+
static HIT_COUNT = "hitCount";
|
|
3571
|
+
static HIT_LIMIT = "hitLimit";
|
|
3572
|
+
static ACTIVE_MUTANT_ENV_VARIABLE = "__STRYKER_ACTIVE_MUTANT__";
|
|
3573
|
+
};
|
|
3574
|
+
//#endregion
|
|
3439
3575
|
//#region src/InstrumentHeader.ts
|
|
3440
3576
|
const hasLeadingComments$1 = (value) => Predicate.hasProperty(value, "leadingComments") && Array.isArray(value.leadingComments);
|
|
3441
3577
|
const STRYKER_NAMESPACE_HELPER = "stryNS_9fa48";
|
|
@@ -3522,6 +3658,18 @@ function commentedHeader(firstHeader, leadingComments, rest) {
|
|
|
3522
3658
|
return [cloned, ...rest];
|
|
3523
3659
|
}
|
|
3524
3660
|
//#endregion
|
|
3661
|
+
//#region src/MutantIdentity.ts
|
|
3662
|
+
const MUTANT_ID_HEX_LENGTH = 16;
|
|
3663
|
+
const lengthPrefixed = (value) => `${value.length}:${value}`;
|
|
3664
|
+
const tupleFields = (tuple) => [
|
|
3665
|
+
tuple.fileName,
|
|
3666
|
+
tuple.mutatorName,
|
|
3667
|
+
tuple.originalCode,
|
|
3668
|
+
tuple.replacementCode
|
|
3669
|
+
];
|
|
3670
|
+
const mutantTupleKey = (tuple) => tupleFields(tuple).map(lengthPrefixed).join("");
|
|
3671
|
+
const mutantIdOf = (identity) => Mutant.MutantId.make(bytesToHex(sha256(utf8ToBytes([...tupleFields(identity), `${identity.ordinal}`].map(lengthPrefixed).join("")))).slice(0, MUTANT_ID_HEX_LENGTH));
|
|
3672
|
+
//#endregion
|
|
3525
3673
|
//#region src/place-mutants.workflow.ts
|
|
3526
3674
|
const PlacementFactsSchema = S.Struct({
|
|
3527
3675
|
isExpression: S.Boolean,
|
|
@@ -3535,7 +3683,7 @@ const ReplacementFactsSchema = S.Struct({
|
|
|
3535
3683
|
isSwitchCase: S.Boolean
|
|
3536
3684
|
});
|
|
3537
3685
|
const PlacedMutantSchema = S.Struct({
|
|
3538
|
-
id: MutantId,
|
|
3686
|
+
id: Mutant.MutantId,
|
|
3539
3687
|
mutatorName: MutatorNameSchema,
|
|
3540
3688
|
replacement: ReplacementFactsSchema
|
|
3541
3689
|
});
|
|
@@ -3549,19 +3697,19 @@ var PlaceMutantsCommand = class extends S.TaggedClass()("PlaceMutantsCommand", {
|
|
|
3549
3697
|
const PlacementDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js-instrumenter/PlacementDecision");
|
|
3550
3698
|
var ExpressionSite = class extends S.TaggedClass()("ExpressionSite", {
|
|
3551
3699
|
fileName: S.String,
|
|
3552
|
-
mutantIds: S.Array(MutantId)
|
|
3700
|
+
mutantIds: S.Array(Mutant.MutantId)
|
|
3553
3701
|
}) {
|
|
3554
3702
|
[PlacementDecisionTypeId] = PlacementDecisionTypeId;
|
|
3555
3703
|
};
|
|
3556
3704
|
var StatementSite = class extends S.TaggedClass()("StatementSite", {
|
|
3557
3705
|
fileName: S.String,
|
|
3558
|
-
mutantIds: S.Array(MutantId)
|
|
3706
|
+
mutantIds: S.Array(Mutant.MutantId)
|
|
3559
3707
|
}) {
|
|
3560
3708
|
[PlacementDecisionTypeId] = PlacementDecisionTypeId;
|
|
3561
3709
|
};
|
|
3562
3710
|
var SwitchCaseSite = class extends S.TaggedClass()("SwitchCaseSite", {
|
|
3563
3711
|
fileName: S.String,
|
|
3564
|
-
mutantIds: S.Array(MutantId)
|
|
3712
|
+
mutantIds: S.Array(Mutant.MutantId)
|
|
3565
3713
|
}) {
|
|
3566
3714
|
[PlacementDecisionTypeId] = PlacementDecisionTypeId;
|
|
3567
3715
|
};
|
|
@@ -3573,11 +3721,19 @@ const ExpectedKindSchema = S.Literals([
|
|
|
3573
3721
|
var MutantKindMismatch = class extends S.TaggedError()("MutantKindMismatch", {
|
|
3574
3722
|
fileName: S.String,
|
|
3575
3723
|
placer: PlacerNameSchema,
|
|
3576
|
-
mutantId: MutantId,
|
|
3724
|
+
mutantId: Mutant.MutantId,
|
|
3577
3725
|
mutatorName: MutatorNameSchema,
|
|
3578
3726
|
expected: ExpectedKindSchema
|
|
3579
|
-
}) {
|
|
3580
|
-
|
|
3727
|
+
}) {
|
|
3728
|
+
get message() {
|
|
3729
|
+
return `Expected ${this.expected} for mutant ${this.mutantId} (${this.mutatorName}) in ${this.fileName}`;
|
|
3730
|
+
}
|
|
3731
|
+
};
|
|
3732
|
+
var NoPlacerClaimsNode = class extends S.TaggedError()("NoPlacerClaimsNode", { fileName: S.String }) {
|
|
3733
|
+
get message() {
|
|
3734
|
+
return `No placer claims the node in ${this.fileName}`;
|
|
3735
|
+
}
|
|
3736
|
+
};
|
|
3581
3737
|
const claimingPlacer = (facts) => Match.value(facts).pipe(Match.when({
|
|
3582
3738
|
isExpression: true,
|
|
3583
3739
|
expressionIsValid: true
|
|
@@ -3626,66 +3782,156 @@ const placeMutants = Workflow.make({
|
|
|
3626
3782
|
})
|
|
3627
3783
|
});
|
|
3628
3784
|
//#endregion
|
|
3785
|
+
//#region src/mutant-set-policy.workflow.ts
|
|
3786
|
+
const MutantSetFactsSchema = S.Struct({
|
|
3787
|
+
originalCode: S.String,
|
|
3788
|
+
replacementCode: S.String,
|
|
3789
|
+
relationalSufficient: S.Boolean
|
|
3790
|
+
});
|
|
3791
|
+
const MutantSetRuleId = S.Literals([
|
|
3792
|
+
"redundant-relational",
|
|
3793
|
+
"equivalent-to-original",
|
|
3794
|
+
"duplicate-at-site"
|
|
3795
|
+
]);
|
|
3796
|
+
var MutantSetPolicyCommand = class extends S.TaggedClass()("MutantSetPolicyCommand", {
|
|
3797
|
+
policy: Options.MutantSetPolicy,
|
|
3798
|
+
candidates: S.Array(MutantSetFactsSchema)
|
|
3799
|
+
}) {
|
|
3800
|
+
static [Workflow.InstrumentationBrand] = {};
|
|
3801
|
+
};
|
|
3802
|
+
const MutantSetOutcomeTypeId = Symbol.for("@systemfsoftware/stryker-js-instrumenter/MutantSetOutcome");
|
|
3803
|
+
var MutantSuppressed = class extends S.TaggedClass()("MutantSuppressed", {
|
|
3804
|
+
ruleId: MutantSetRuleId,
|
|
3805
|
+
detail: S.String
|
|
3806
|
+
}) {
|
|
3807
|
+
[MutantSetOutcomeTypeId] = MutantSetOutcomeTypeId;
|
|
3808
|
+
};
|
|
3809
|
+
var MutantKept = class extends S.TaggedClass()("MutantKept", {}) {
|
|
3810
|
+
[MutantSetOutcomeTypeId] = MutantSetOutcomeTypeId;
|
|
3811
|
+
};
|
|
3812
|
+
const MutantSetOutcome = S.Union([MutantSuppressed, MutantKept]);
|
|
3813
|
+
const MutantSetDecision = S.Array(MutantSetOutcome);
|
|
3814
|
+
const canonicalForm = (text) => stripOuterParentheses(text.trim());
|
|
3815
|
+
const stripOuterParentheses = (text) => Match.value(wrapsWhole(text)).pipe(Match.when(true, () => stripOuterParentheses(text.slice(1, -1).trim())), Match.orElse(() => text));
|
|
3816
|
+
const parenDepthDelta = (character) => Match.value(character).pipe(Match.when("(", () => 1), Match.when(")", () => -1), Match.orElse(() => 0));
|
|
3817
|
+
const depthsAfter = (text) => text.split("").reduce((depths, character) => [...depths, Option.getOrElse(Arr.last(depths), () => 0) + parenDepthDelta(character)], []);
|
|
3818
|
+
const wrapsWhole = (text) => {
|
|
3819
|
+
const depths = depthsAfter(text);
|
|
3820
|
+
return [
|
|
3821
|
+
text.startsWith("("),
|
|
3822
|
+
text.endsWith(")"),
|
|
3823
|
+
depths.length > 0,
|
|
3824
|
+
depths.slice(0, -1).every((depth) => depth >= 1),
|
|
3825
|
+
Option.getOrElse(Arr.last(depths), () => 0) === 0
|
|
3826
|
+
].every(Boolean);
|
|
3827
|
+
};
|
|
3828
|
+
const defaultOnly = (policy, value) => Match.value(policy).pipe(Match.when("full", () => Option.none()), Match.when("default", value), Match.exhaustive);
|
|
3829
|
+
const printedAs = (code) => canonicalForm(code);
|
|
3830
|
+
const printsSomething = (code) => printedAs(code).length > 0;
|
|
3831
|
+
const samePrintedCode = (left, right) => [printsSomething(left), printedAs(left) === printedAs(right)].every(Boolean);
|
|
3832
|
+
const alreadyPrinted = (code, earlier) => [printsSomething(code), earlier.includes(printedAs(code))].every(Boolean);
|
|
3833
|
+
const relationalSuppression = (facts, policy) => defaultOnly(policy, () => Option.map(Option.filter(Option.some(facts), (candidate) => candidate.relationalSufficient === false), () => MutantSuppressed.make({
|
|
3834
|
+
ruleId: "redundant-relational",
|
|
3835
|
+
detail: `${printedAs(facts.replacementCode)} is not in the sufficient set for ${printedAs(facts.originalCode)}`
|
|
3836
|
+
})));
|
|
3837
|
+
const equivalentSuppression = (facts, policy) => defaultOnly(policy, () => Option.map(Option.filter(Option.some(facts), (candidate) => samePrintedCode(candidate.replacementCode, candidate.originalCode)), () => MutantSuppressed.make({
|
|
3838
|
+
ruleId: "equivalent-to-original",
|
|
3839
|
+
detail: `${printedAs(facts.replacementCode)} is the original code`
|
|
3840
|
+
})));
|
|
3841
|
+
const duplicateSuppression = (facts, earlier, policy) => defaultOnly(policy, () => Option.map(Option.filter(Option.some(facts), (candidate) => alreadyPrinted(candidate.replacementCode, earlier)), () => MutantSuppressed.make({
|
|
3842
|
+
ruleId: "duplicate-at-site",
|
|
3843
|
+
detail: `${printedAs(facts.replacementCode)} is already planted at this site`
|
|
3844
|
+
})));
|
|
3845
|
+
const outcomeOf = (facts, earlier, policy) => Option.getOrElse(Option.orElse(relationalSuppression(facts, policy), () => Option.orElse(equivalentSuppression(facts, policy), () => duplicateSuppression(facts, earlier, policy))), () => MutantKept.make({}));
|
|
3846
|
+
const foldCandidate = (state, facts, policy) => ({
|
|
3847
|
+
outcomes: [...state.outcomes, outcomeOf(facts, state.earlier, policy)],
|
|
3848
|
+
earlier: [...state.earlier, canonicalForm(facts.replacementCode)]
|
|
3849
|
+
});
|
|
3850
|
+
const outcomesFor = (command) => command.candidates.reduce((state, facts) => foldCandidate(state, facts, command.policy), {
|
|
3851
|
+
outcomes: [],
|
|
3852
|
+
earlier: []
|
|
3853
|
+
}).outcomes;
|
|
3854
|
+
const mutantSetPolicy = Workflow.make({
|
|
3855
|
+
command: MutantSetPolicyCommand,
|
|
3856
|
+
decision: MutantSetDecision,
|
|
3857
|
+
error: S.Never,
|
|
3858
|
+
decide: (command) => Result.succeed([...outcomesFor(command)])
|
|
3859
|
+
});
|
|
3860
|
+
//#endregion
|
|
3629
3861
|
//#region src/plan-mutants.workflow.ts
|
|
3630
3862
|
const WILDCARD = "all";
|
|
3631
3863
|
const NEXT_LINE = "next-line";
|
|
3864
|
+
const RULE_SEPARATOR = ": ";
|
|
3865
|
+
const policyWorkflow = mutantSetPolicy;
|
|
3866
|
+
const policyCommand = MutantSetPolicyCommand;
|
|
3867
|
+
const keptOutcome = MutantKept;
|
|
3868
|
+
const ignoreReasonFor = (ruleId, detail) => `${ruleId}${RULE_SEPARATOR}${detail}`;
|
|
3632
3869
|
const MutantCandidateSchema = S.Struct({
|
|
3870
|
+
id: Mutant.MutantId,
|
|
3633
3871
|
mutatorName: MutatorNameSchema,
|
|
3634
3872
|
replacementCode: S.String,
|
|
3635
|
-
location: S.optional(Location),
|
|
3636
|
-
ignorerReason: S.optional(S.String)
|
|
3873
|
+
location: S.optional(Mutant.Location),
|
|
3874
|
+
ignorerReason: S.optional(S.String),
|
|
3875
|
+
mutantSet: MutantSetFactsSchema
|
|
3637
3876
|
});
|
|
3638
3877
|
const PlannedMutantSchema = S.Struct({
|
|
3639
|
-
id: MutantId,
|
|
3878
|
+
id: Mutant.MutantId,
|
|
3640
3879
|
mutatorName: MutatorNameSchema,
|
|
3641
3880
|
replacementCode: S.String,
|
|
3642
|
-
location: Location,
|
|
3881
|
+
location: Mutant.Location,
|
|
3643
3882
|
ignoreReason: S.optional(S.String)
|
|
3644
3883
|
});
|
|
3645
|
-
const MutantCounterSchema = S.Int.pipe(S.check(S.isBetween({
|
|
3646
|
-
minimum: 0,
|
|
3647
|
-
maximum: 1e6
|
|
3648
|
-
})));
|
|
3649
|
-
const MutantCountSchema = S.Int.pipe(S.check(S.isGreaterThanOrEqualTo(0)));
|
|
3650
3884
|
var PlanMutantsCommand = class extends S.TaggedClass()("PlanMutantsCommand", {
|
|
3651
3885
|
fileName: S.String,
|
|
3652
|
-
firstIndex: MutantCounterSchema,
|
|
3653
3886
|
offset: ScriptOrigin,
|
|
3654
|
-
line: Line,
|
|
3887
|
+
line: Mutant.Line,
|
|
3655
3888
|
mutatorNames: S.Array(MutatorNameSchema),
|
|
3656
3889
|
excludedMutations: S.Array(MutatorNameSchema),
|
|
3657
3890
|
rule: S.Array(LocatedDirectiveSchema),
|
|
3658
3891
|
directives: S.Array(LocatedDirectiveSchema),
|
|
3659
|
-
candidates: S.Array(MutantCandidateSchema)
|
|
3892
|
+
candidates: S.Array(MutantCandidateSchema),
|
|
3893
|
+
mutantSetPolicy: Options.MutantSetPolicy
|
|
3660
3894
|
}) {
|
|
3661
3895
|
static [Workflow.InstrumentationBrand] = {};
|
|
3662
3896
|
};
|
|
3663
3897
|
const MutantPlanTypeId = Symbol.for("@systemfsoftware/stryker-js-instrumenter/MutantPlan");
|
|
3664
3898
|
var MutantsPlanned = class extends S.TaggedClass()("MutantsPlanned", {
|
|
3665
3899
|
mutants: S.Array(PlannedMutantSchema),
|
|
3666
|
-
|
|
3667
|
-
warnings: S.Array(S.String)
|
|
3668
|
-
nextIndex: MutantCountSchema
|
|
3900
|
+
placeableIds: S.Array(Mutant.MutantId),
|
|
3901
|
+
warnings: S.Array(S.String)
|
|
3669
3902
|
}) {
|
|
3670
3903
|
[MutantPlanTypeId] = MutantPlanTypeId;
|
|
3671
3904
|
};
|
|
3672
3905
|
var MutantsFullyIgnored = class extends S.TaggedClass()("MutantsFullyIgnored", {
|
|
3673
3906
|
mutants: S.Array(PlannedMutantSchema),
|
|
3674
|
-
warnings: S.Array(S.String)
|
|
3675
|
-
nextIndex: MutantCountSchema
|
|
3907
|
+
warnings: S.Array(S.String)
|
|
3676
3908
|
}) {
|
|
3677
3909
|
[MutantPlanTypeId] = MutantPlanTypeId;
|
|
3678
3910
|
};
|
|
3679
3911
|
var MutantWithoutLocation = class extends S.TaggedError()("MutantWithoutLocation", {
|
|
3680
3912
|
fileName: S.String,
|
|
3681
3913
|
mutatorName: MutatorNameSchema
|
|
3682
|
-
}) {
|
|
3914
|
+
}) {
|
|
3915
|
+
get message() {
|
|
3916
|
+
return `Mutant without a source location: ${this.mutatorName} in ${this.fileName}`;
|
|
3917
|
+
}
|
|
3918
|
+
};
|
|
3683
3919
|
const reachedLine = (located, line) => Match.value(located.directive.scope).pipe(Match.when(NEXT_LINE, () => located.governedLine === line), Match.when("block", () => true), Match.exhaustive);
|
|
3684
3920
|
const namesMutator = (located, lowerMutatorName) => located.directive.mutatorNames.some((name) => [name === WILDCARD, name.toLowerCase() === lowerMutatorName].some(Boolean));
|
|
3685
3921
|
const lastReachingDirective = (rule, lowerMutatorName, line) => Option.fromNullishOr(rule.findLast((located) => [reachedLine(located, line), namesMutator(located, lowerMutatorName)].every(Boolean)));
|
|
3686
|
-
const directiveReason = (rule, mutatorName, line) => Option.flatMap(lastReachingDirective(rule, mutatorName.toLowerCase(), line), (located) => Match.value(located.directive.action).pipe(Match.when("disable", () => Option.some(located.directive.reason)), Match.when("restore", () => Option.none()), Match.exhaustive));
|
|
3687
|
-
const exclusionReason = (excludedMutations, mutatorName) => Match.value(excludedMutations.includes(mutatorName)).pipe(Match.when(true, () => Option.some(`Ignored because of excluded mutation "${mutatorName}"`)), Match.when(false, () => Option.none()), Match.exhaustive);
|
|
3688
|
-
const
|
|
3922
|
+
const directiveReason = (rule, mutatorName, line) => Option.flatMap(lastReachingDirective(rule, mutatorName.toLowerCase(), line), (located) => Match.value(located.directive.action).pipe(Match.when("disable", () => Option.some(ignoreReasonFor("directive", located.directive.reason))), Match.when("restore", () => Option.none()), Match.exhaustive));
|
|
3923
|
+
const exclusionReason = (excludedMutations, mutatorName) => Match.value(excludedMutations.includes(mutatorName)).pipe(Match.when(true, () => Option.some(ignoreReasonFor("excluded-mutator", `Ignored because of excluded mutation "${mutatorName}"`))), Match.when(false, () => Option.none()), Match.exhaustive);
|
|
3924
|
+
const ignorerReason = (candidate) => Option.map(Option.fromNullishOr(candidate.ignorerReason), (reason) => ignoreReasonFor("ignorer", reason));
|
|
3925
|
+
const ignoreReasonOf = (command, candidate, policyReason) => Option.getOrUndefined(Option.orElse(Option.orElse(Option.orElse(directiveReason(command.rule, candidate.mutatorName, command.line), () => exclusionReason(command.excludedMutations, candidate.mutatorName)), () => ignorerReason(candidate)), () => Option.fromNullishOr(policyReason)));
|
|
3926
|
+
const policyOutcomes = (command) => Result.match(policyWorkflow(policyCommand.make({
|
|
3927
|
+
policy: command.mutantSetPolicy,
|
|
3928
|
+
candidates: command.candidates.map((candidate) => candidate.mutantSet)
|
|
3929
|
+
})), {
|
|
3930
|
+
onFailure: () => command.candidates.map(() => keptOutcome.make({})),
|
|
3931
|
+
onSuccess: (outcomes) => outcomes
|
|
3932
|
+
});
|
|
3933
|
+
const policyReasonOf = (outcome) => Match.value(outcome).pipe(Match.withReturnType(), Match.tag("MutantSuppressed", (suppressed) => ignoreReasonFor(suppressed.ruleId, suppressed.detail)), Match.tag("MutantKept", () => void 0), Match.exhaustive);
|
|
3934
|
+
const policyReasonsAt = (command) => policyOutcomes(command).map(policyReasonOf);
|
|
3689
3935
|
const unusedDirectives = (directives, mutatorNames) => directives.flatMap((located) => located.directive.mutatorNames.filter((mutatorName) => mutatorName !== WILDCARD).filter((mutatorName) => !mutatorNames.includes(mutatorName.toLowerCase())).map((mutatorName) => ({
|
|
3690
3936
|
directive: located.directive,
|
|
3691
3937
|
at: located.at,
|
|
@@ -3711,30 +3957,31 @@ const shiftedLocation = (location, offset) => ({
|
|
|
3711
3957
|
start: shiftedPosition(location.start, offset),
|
|
3712
3958
|
end: shiftedPosition(location.end, offset)
|
|
3713
3959
|
});
|
|
3714
|
-
const plannedMutant = (command, candidate,
|
|
3960
|
+
const plannedMutant = (command, candidate, policyReason) => Option.match(Option.fromNullishOr(candidate.location), {
|
|
3715
3961
|
onNone: () => Result.fail(MutantWithoutLocation.make({
|
|
3716
3962
|
fileName: command.fileName,
|
|
3717
3963
|
mutatorName: candidate.mutatorName
|
|
3718
3964
|
})),
|
|
3719
3965
|
onSome: (location) => Result.succeed({
|
|
3720
|
-
id:
|
|
3966
|
+
id: candidate.id,
|
|
3721
3967
|
mutatorName: candidate.mutatorName,
|
|
3722
3968
|
replacementCode: candidate.replacementCode,
|
|
3723
3969
|
location: shiftedLocation(location, command.offset),
|
|
3724
|
-
ignoreReason: ignoreReasonOf(command, candidate)
|
|
3970
|
+
ignoreReason: ignoreReasonOf(command, candidate, policyReason)
|
|
3725
3971
|
})
|
|
3726
3972
|
});
|
|
3727
|
-
const plannedMutants = (command) =>
|
|
3973
|
+
const plannedMutants = (command) => {
|
|
3974
|
+
const policyReasons = policyReasonsAt(command);
|
|
3975
|
+
return command.candidates.reduce((accumulated, candidate, index) => Result.flatMap(accumulated, (mutants) => Result.map(plannedMutant(command, candidate, policyReasons[index]), (mutant) => [...mutants, mutant])), Result.succeed([]));
|
|
3976
|
+
};
|
|
3728
3977
|
const withoutReason = (mutant) => mutant.ignoreReason === void 0;
|
|
3729
3978
|
const planOf = (command, mutants) => Match.value(mutants.some(withoutReason)).pipe(Match.when(true, () => MutantsPlanned.make({
|
|
3730
3979
|
mutants: [...mutants],
|
|
3731
|
-
|
|
3732
|
-
warnings: warningsOf(command)
|
|
3733
|
-
nextIndex: command.firstIndex + mutants.length
|
|
3980
|
+
placeableIds: mutants.filter(withoutReason).map((mutant) => mutant.id),
|
|
3981
|
+
warnings: warningsOf(command)
|
|
3734
3982
|
})), Match.when(false, () => MutantsFullyIgnored.make({
|
|
3735
3983
|
mutants: [...mutants],
|
|
3736
|
-
warnings: warningsOf(command)
|
|
3737
|
-
nextIndex: command.firstIndex + mutants.length
|
|
3984
|
+
warnings: warningsOf(command)
|
|
3738
3985
|
})), Match.exhaustive);
|
|
3739
3986
|
const planMutants = Workflow.make({
|
|
3740
3987
|
command: PlanMutantsCommand,
|
|
@@ -3758,15 +4005,15 @@ const traversalFailure = (cause) => InstrumentError.make({
|
|
|
3758
4005
|
message: cause instanceof Error ? cause.message : errorTextOf$1(cause),
|
|
3759
4006
|
cause
|
|
3760
4007
|
});
|
|
3761
|
-
const DEFAULT_MUTATOR_REGISTRY = {
|
|
3762
|
-
defaults: defaultMutators,
|
|
3763
|
-
optIn: optInMutators
|
|
3764
|
-
};
|
|
3765
4008
|
const createMutantCollector = () => {
|
|
3766
4009
|
const mutants = [];
|
|
4010
|
+
const occurrences = /* @__PURE__ */ new Map();
|
|
3767
4011
|
return {
|
|
3768
|
-
|
|
3769
|
-
|
|
4012
|
+
ordinalOf: (tuple) => {
|
|
4013
|
+
const key = mutantTupleKey(tuple);
|
|
4014
|
+
const ordinal = occurrences.get(key) ?? 0;
|
|
4015
|
+
occurrences.set(key, ordinal + 1);
|
|
4016
|
+
return ordinal;
|
|
3770
4017
|
},
|
|
3771
4018
|
append: (added) => {
|
|
3772
4019
|
mutants.push(...added);
|
|
@@ -4069,9 +4316,8 @@ const MUTATION_OFFSET = {
|
|
|
4069
4316
|
line: 1,
|
|
4070
4317
|
columnShift: 0
|
|
4071
4318
|
};
|
|
4072
|
-
const initialFoldState = (
|
|
4319
|
+
const initialFoldState = () => ({
|
|
4073
4320
|
directiveRule: [],
|
|
4074
|
-
nextIndex: firstIndex,
|
|
4075
4321
|
mutants: [],
|
|
4076
4322
|
warnings: [],
|
|
4077
4323
|
claims: [],
|
|
@@ -4107,29 +4353,77 @@ const replacementRecord = (mutant, applied) => {
|
|
|
4107
4353
|
}
|
|
4108
4354
|
};
|
|
4109
4355
|
};
|
|
4110
|
-
const plannedWithNodes = (candidates, planned, fileName) =>
|
|
4356
|
+
const plannedWithNodes = (candidates, planned, fileName, includes) => planned.flatMap((mutant, index) => Option.match(Option.fromNullishOr(candidates[index]), {
|
|
4111
4357
|
onNone: () => [],
|
|
4112
|
-
onSome: (
|
|
4358
|
+
onSome: (candidate) => includes(mutant) ? [createMutant(mutant, fileName, candidate.node, candidate.replacement)] : []
|
|
4113
4359
|
}));
|
|
4114
4360
|
const ignorersReasonFor = (node, ancestors, ignorers) => ignorers.reduce((reason, ignorer) => Option.orElse(reason, () => Option.fromNullishOr(ignorer.shouldIgnore(node, ancestors))), Option.none());
|
|
4361
|
+
const hasKey = (node, key) => key in node;
|
|
4362
|
+
const readKey = (node, key) => hasKey(node, key) ? node[key] : void 0;
|
|
4363
|
+
const isMemberExpressionValue = (node) => nodeType(node) === "MemberExpression";
|
|
4364
|
+
const isIdentifierValue = (value) => value !== void 0 && readKey(value, "type") === "Identifier";
|
|
4365
|
+
const hasIdentifierParts = (member) => [isIdentifierValue(readKey(member, "property")), isIdentifierValue(readKey(member, "object"))].every(Boolean);
|
|
4366
|
+
const isMemberOfIdentifierParts = (node) => isMemberExpressionValue(node) && hasIdentifierParts(node);
|
|
4367
|
+
function isNamedCallee(node) {
|
|
4368
|
+
return isMemberOfIdentifierParts(node) && readKey(node, "computed") === false;
|
|
4369
|
+
}
|
|
4370
|
+
const aridCalleeOf = (callee) => Match.value(callee).pipe(Match.when(isNamedCallee, (named) => Option.some({
|
|
4371
|
+
object: named.object.name,
|
|
4372
|
+
member: named.property.name
|
|
4373
|
+
})), Match.orElse(() => Option.none()));
|
|
4374
|
+
const aridFrameFor = (child, ancestor) => ancestor.type === "CallExpression" ? Option.some({
|
|
4375
|
+
callee: aridCalleeOf(ancestor.callee),
|
|
4376
|
+
childIsArgument: ancestor.arguments.some((argument) => argument === child)
|
|
4377
|
+
}) : Option.none();
|
|
4378
|
+
const aridFramesOf = (frame) => framesUpward(frame).flatMap((current) => Option.match(Option.fromNullishOr(current.parent), {
|
|
4379
|
+
onNone: () => [],
|
|
4380
|
+
onSome: (parent) => Option.toArray(aridFrameFor(current.node, parent.node))
|
|
4381
|
+
}));
|
|
4382
|
+
const aridStatusReason = (decision) => Match.value(decision).pipe(Match.tag("AridSuppressed", (suppressed) => Option.some(`${suppressed.ruleId}: ${suppressed.detail}`)), Match.tag("AridKept", () => Option.none()), Match.exhaustive);
|
|
4383
|
+
const aridReasonOf = (frame, policy) => Match.value(aridCode(AridCodeCommand.make({
|
|
4384
|
+
policy,
|
|
4385
|
+
frames: [...aridFramesOf(frame)]
|
|
4386
|
+
}))).pipe(Match.when(Result.isSuccess, (decided) => aridStatusReason(decided.success)), Match.orElse(() => Option.none()));
|
|
4115
4387
|
const mutablesFor = (frame, location, context) => {
|
|
4116
4388
|
const ancestors = ancestorsOfFrame(frame);
|
|
4117
|
-
const mutatorContext = toMutatorContext(ancestors);
|
|
4389
|
+
const mutatorContext = toMutatorContext(ancestors, context.mutantSetPolicy);
|
|
4118
4390
|
const replacements = context.mutatorEntries.flatMap(([mutatorName, mutate]) => [...mutate(frame.node, mutatorContext)].map((replacement) => ({
|
|
4119
4391
|
mutatorName,
|
|
4120
4392
|
replacement
|
|
4121
4393
|
})));
|
|
4122
4394
|
const ignorerReason = replacements.length === 0 ? void 0 : Option.getOrUndefined(ignorersReasonFor(frame.node, ancestors, context.ignorers));
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4395
|
+
const aridReason = aridReasonOf(frame, context.mutantSetPolicy);
|
|
4396
|
+
const originalCode = printNode(frame.node);
|
|
4397
|
+
const relationalSite = relationalSiteFacts(frame.node, mutatorContext);
|
|
4398
|
+
return replacements.map(({ mutatorName, replacement }) => {
|
|
4399
|
+
const replacementCode = printNode(replacement);
|
|
4400
|
+
const tuple = {
|
|
4401
|
+
fileName: context.fileName,
|
|
4127
4402
|
mutatorName,
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4403
|
+
originalCode,
|
|
4404
|
+
replacementCode
|
|
4405
|
+
};
|
|
4406
|
+
return {
|
|
4407
|
+
node: frame.node,
|
|
4408
|
+
replacement,
|
|
4409
|
+
aridReason,
|
|
4410
|
+
data: {
|
|
4411
|
+
id: mutantIdOf({
|
|
4412
|
+
...tuple,
|
|
4413
|
+
ordinal: context.ordinalOf(tuple)
|
|
4414
|
+
}),
|
|
4415
|
+
mutatorName,
|
|
4416
|
+
replacementCode,
|
|
4417
|
+
location,
|
|
4418
|
+
ignorerReason,
|
|
4419
|
+
mutantSet: {
|
|
4420
|
+
originalCode,
|
|
4421
|
+
replacementCode,
|
|
4422
|
+
relationalSufficient: relationalSufficientReplacement(relationalSite, replacement)
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
};
|
|
4426
|
+
});
|
|
4133
4427
|
};
|
|
4134
4428
|
const mutateRangesOf = (mutateDescription) => Option.filter(Option.some(mutateDescription), isMutateRangeList);
|
|
4135
4429
|
const isOutsideMutateRanges = (location, mutateDescription) => Option.exists(mutateRangesOf(mutateDescription), (ranges) => ranges.every((range) => !locationOverlaps(range, location)));
|
|
@@ -4167,30 +4461,43 @@ const attachPlaceable = (mutants, frame, state, context) => Match.value(mutants.
|
|
|
4167
4461
|
})),
|
|
4168
4462
|
onSome: (target) => applyToClaim(mutants, target, state, context)
|
|
4169
4463
|
})), Match.exhaustive);
|
|
4464
|
+
const aridReasonAt = (candidates, index) => Option.flatMap(Option.fromNullishOr(candidates[index]), (candidate) => candidate.aridReason);
|
|
4465
|
+
const withAridReason = (mutant, reason) => Option.match(reason, {
|
|
4466
|
+
onNone: () => mutant,
|
|
4467
|
+
onSome: (text) => mutant.ignoreReason === void 0 ? {
|
|
4468
|
+
...mutant,
|
|
4469
|
+
ignoreReason: text
|
|
4470
|
+
} : mutant
|
|
4471
|
+
});
|
|
4472
|
+
const withAridReasons = (candidates, planned) => planned.map((mutant, index) => withAridReason(mutant, aridReasonAt(candidates, index)));
|
|
4170
4473
|
const collectPlan = (frame, candidates, plan, state, context) => {
|
|
4171
|
-
const
|
|
4474
|
+
const planned = withAridReasons(candidates, plan.mutants);
|
|
4475
|
+
const collected = plannedWithNodes(candidates, planned, context.fileName, () => true);
|
|
4172
4476
|
const nextState = {
|
|
4173
4477
|
...state,
|
|
4174
4478
|
mutants: [...state.mutants, ...collected],
|
|
4175
|
-
warnings: [...state.warnings, ...plan.warnings]
|
|
4176
|
-
nextIndex: plan.nextIndex
|
|
4479
|
+
warnings: [...state.warnings, ...plan.warnings]
|
|
4177
4480
|
};
|
|
4178
|
-
return Match.value(plan).pipe(Match.tag("MutantsPlanned", (
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4481
|
+
return Match.value(plan).pipe(Match.tag("MutantsPlanned", (plannedPlan) => {
|
|
4482
|
+
const placeable = new Set(plannedPlan.placeableIds);
|
|
4483
|
+
const live = plannedWithNodes(candidates, planned, context.fileName, (mutant) => placeable.has(mutant.id) && mutant.ignoreReason === void 0);
|
|
4484
|
+
return attachPlaceable(live, frame, {
|
|
4485
|
+
...nextState,
|
|
4486
|
+
hasLiveMutants: nextState.hasLiveMutants || live.length > 0
|
|
4487
|
+
}, context);
|
|
4488
|
+
}), Match.tag("MutantsFullyIgnored", () => Result.succeed(nextState)), Match.exhaustive);
|
|
4182
4489
|
};
|
|
4183
4490
|
const planMutantsAt = (frame, candidates, directives, location, state, context) => {
|
|
4184
4491
|
const plan = planMutants(PlanMutantsCommand.make({
|
|
4185
4492
|
fileName: context.fileName,
|
|
4186
|
-
firstIndex: state.nextIndex,
|
|
4187
4493
|
offset: context.offset,
|
|
4188
4494
|
line: location.start.line,
|
|
4189
4495
|
mutatorNames: [...context.allMutatorNames],
|
|
4190
4496
|
excludedMutations: [...context.excludedMutations],
|
|
4191
4497
|
rule: [...state.directiveRule],
|
|
4192
4498
|
directives: [...directives],
|
|
4193
|
-
candidates: candidates.map((candidate) => candidate.data)
|
|
4499
|
+
candidates: candidates.map((candidate) => candidate.data),
|
|
4500
|
+
mutantSetPolicy: context.mutantSetPolicy
|
|
4194
4501
|
}));
|
|
4195
4502
|
return Match.value(plan).pipe(Match.when(Result.isFailure, (failed) => Result.fail(failed.failure)), Match.orElse((succeeded) => collectPlan(frame, candidates, succeeded.success, state, context)));
|
|
4196
4503
|
};
|
|
@@ -4253,10 +4560,10 @@ const foldPlacements = (frame, state, context) => Result.flatMap(locationOfNode(
|
|
|
4253
4560
|
};
|
|
4254
4561
|
return Match.value(shouldSkipNode(frame, location, context.mutateDescription)).pipe(Match.when(true, () => Result.succeed(ruled)), Match.when(false, () => visitFrame(frame, directives, location, ruled, context)), Match.exhaustive);
|
|
4255
4562
|
});
|
|
4256
|
-
const planInstrumentation = (root,
|
|
4563
|
+
const planInstrumentation = (root, context) => Result.map(foldPlacements({
|
|
4257
4564
|
node: root,
|
|
4258
4565
|
parent: null
|
|
4259
|
-
}, initialFoldState(
|
|
4566
|
+
}, initialFoldState(), context), (state) => ({
|
|
4260
4567
|
mutants: state.mutants,
|
|
4261
4568
|
placements: state.placements,
|
|
4262
4569
|
warnings: state.warnings,
|
|
@@ -4309,23 +4616,24 @@ const refusalError = (refusal) => Match.value(refusal).pipe(Match.tag("NodeWitho
|
|
|
4309
4616
|
message: `Mutant without a source location: ${failed.mutatorName} in ${failed.fileName}`,
|
|
4310
4617
|
cause: void 0
|
|
4311
4618
|
})), Match.exhaustive);
|
|
4312
|
-
const transformScriptDataFirst = Effect.fn(
|
|
4619
|
+
const transformScriptDataFirst = Effect.fn(SpanTaxonomy.Spans.instrumentTransformScript.name)(function* ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription, basePath }) {
|
|
4313
4620
|
const lineStarts = lineStartsOf(rawContent);
|
|
4314
4621
|
attachComments(make(root), comments, lineStarts);
|
|
4315
|
-
const selection = selectMutators(DEFAULT_MUTATOR_REGISTRY, options.optInMutations);
|
|
4316
4622
|
const context = {
|
|
4317
4623
|
fileName: originFileName,
|
|
4318
4624
|
lineStarts,
|
|
4319
4625
|
mutateDescription,
|
|
4320
4626
|
offset: offset ?? MUTATION_OFFSET,
|
|
4321
4627
|
basePath,
|
|
4322
|
-
mutatorEntries:
|
|
4323
|
-
allMutatorNames:
|
|
4628
|
+
mutatorEntries: options.mutators.active,
|
|
4629
|
+
allMutatorNames: options.mutators.known.map((name) => name.toLowerCase()),
|
|
4324
4630
|
excludedMutations: options.excludedMutations,
|
|
4325
|
-
|
|
4631
|
+
mutantSetPolicy: options.mutantSetPolicy,
|
|
4632
|
+
ignorers: options.ignorers,
|
|
4633
|
+
ordinalOf: mutantCollector.ordinalOf
|
|
4326
4634
|
};
|
|
4327
4635
|
const planned = yield* Effect.try({
|
|
4328
|
-
try: () => planInstrumentation(root,
|
|
4636
|
+
try: () => planInstrumentation(root, context),
|
|
4329
4637
|
catch: traversalFailure
|
|
4330
4638
|
});
|
|
4331
4639
|
const plan = yield* Match.value(planned).pipe(Match.when(Result.isFailure, (refused) => {
|
|
@@ -4338,11 +4646,12 @@ const transformScriptDataFirst = Effect.fn("stryker.instrument.transform.script"
|
|
|
4338
4646
|
return plan.warnings;
|
|
4339
4647
|
});
|
|
4340
4648
|
const transformScript = dual((args) => args.length >= 3, transformScriptDataFirst);
|
|
4341
|
-
function toMutatorContext(ancestors) {
|
|
4649
|
+
function toMutatorContext(ancestors, mutantSetPolicy) {
|
|
4342
4650
|
return {
|
|
4343
4651
|
parent: ancestors[0],
|
|
4344
4652
|
grandParent: ancestors[1],
|
|
4345
|
-
ancestors: [...ancestors]
|
|
4653
|
+
ancestors: [...ancestors],
|
|
4654
|
+
mutantSetPolicy
|
|
4346
4655
|
};
|
|
4347
4656
|
}
|
|
4348
4657
|
const toError = (value) => value instanceof Error ? value : new Error("Unexpected error", { cause: value });
|
|
@@ -4498,12 +4807,11 @@ const coreFormatRegistry = formatRegistry([
|
|
|
4498
4807
|
]);
|
|
4499
4808
|
const resolveFileDataFirst = (registry, fileName, formatIdOverride) => resolveFormat(resolutionCommandOf(registry, fileName, formatIdOverride));
|
|
4500
4809
|
const resolveFile = dual((args) => typeof args[0] !== "string", resolveFileDataFirst);
|
|
4501
|
-
const NO_OPT_IN_MUTATIONS = [];
|
|
4502
|
-
const optInMutationsOf = (options) => options.optInMutations ?? NO_OPT_IN_MUTATIONS;
|
|
4503
4810
|
const isIgnorer = (value) => Predicate.isObject(value) && typeof value["shouldIgnore"] === "function";
|
|
4504
4811
|
const toTransformerOptions = (options) => ({
|
|
4505
4812
|
excludedMutations: [...options.excludedMutations],
|
|
4506
|
-
|
|
4813
|
+
mutators: options.mutators,
|
|
4814
|
+
mutantSetPolicy: options.mutantSetPolicy,
|
|
4507
4815
|
ignorers: options.ignorers.filter(isIgnorer),
|
|
4508
4816
|
...options.noHeader !== void 0 ? { noHeader: options.noHeader } : {}
|
|
4509
4817
|
});
|
|
@@ -4643,7 +4951,7 @@ const frameworkEntryOfDataFirst = (moduleName, framework) => ({
|
|
|
4643
4951
|
},
|
|
4644
4952
|
owner: moduleName,
|
|
4645
4953
|
ownerVersion: framework.claim.ownerVersion,
|
|
4646
|
-
parse: Effect.fn(
|
|
4954
|
+
parse: Effect.fn(SpanTaxonomy.Spans.instrumentFrameworkEntryParse.name)(function* (text, fileName) {
|
|
4647
4955
|
const context = frameworkContextOf(yield* loadFrameworkToolkit);
|
|
4648
4956
|
const lineStarts = lineStartsOf(text);
|
|
4649
4957
|
const result = yield* runHook(moduleName, "parse", fileName, () => framework.parse(text, context));
|
|
@@ -4660,7 +4968,7 @@ const frameworkEntryOfDataFirst = (moduleName, framework) => ({
|
|
|
4660
4968
|
}),
|
|
4661
4969
|
transform: (ast, mutantCollector, context) => Option.match(embeddedOf(ast), {
|
|
4662
4970
|
onNone: () => Effect.fail(embeddedAstError(ast)),
|
|
4663
|
-
onSome: Effect.fn(
|
|
4971
|
+
onSome: Effect.fn(SpanTaxonomy.Spans.instrumentFrameworkEntryTransform.name)(function* (embedded) {
|
|
4664
4972
|
const warnings = yield* Effect.forEach(embedded.scripts, (script) => context.transform(script.ast, mutantCollector, context));
|
|
4665
4973
|
embedded.document = yield* runHook(moduleName, "transform", embedded.originFileName, () => framework.transform(embedded.document, embedded.context));
|
|
4666
4974
|
return warnings.flat();
|
|
@@ -4699,7 +5007,7 @@ const readDisable = (input) => Effect.sync(() => {
|
|
|
4699
5007
|
registry: input.registry
|
|
4700
5008
|
};
|
|
4701
5009
|
});
|
|
4702
|
-
const disableTypeChecksCell = Sandwich.named(
|
|
5010
|
+
const disableTypeChecksCell = Sandwich.named(SpanTaxonomy.Spans.instrumentDisableTypeChecks.name)((input) => readDisable(input)).decide(resolveFormat).write({
|
|
4703
5011
|
FormatAssigned: (assigned, raw) => spliceForAssigned({
|
|
4704
5012
|
file: raw.file,
|
|
4705
5013
|
registry: raw.registry,
|
|
@@ -4755,7 +5063,7 @@ const skippedOnlyResult = (raw) => InstrumentResult.make({
|
|
|
4755
5063
|
mutants: [],
|
|
4756
5064
|
skipped: [...raw.skipped]
|
|
4757
5065
|
});
|
|
4758
|
-
const readInstrumentFiles = Effect.fn(
|
|
5066
|
+
const readInstrumentFiles = Effect.fn(SpanTaxonomy.Spans.instrumentReadFiles.name)(function* (input) {
|
|
4759
5067
|
const outcomes = yield* Effect.forEach(input.files, (file) => fileOutcome({
|
|
4760
5068
|
registry: input.registry,
|
|
4761
5069
|
file
|
|
@@ -4794,29 +5102,15 @@ const instrumentFilesCell = Sandwich.named("stryker.instrument.files")((input) =
|
|
|
4794
5102
|
//#endregion
|
|
4795
5103
|
//#region src/Instrument.service.ts
|
|
4796
5104
|
const toSchemaFile = (file) => ({
|
|
4797
|
-
name: CanonicalFileName.make(file.name),
|
|
5105
|
+
name: Mutant.CanonicalFileName.make(file.name),
|
|
4798
5106
|
content: file.content,
|
|
4799
5107
|
mutate: file.mutate
|
|
4800
5108
|
});
|
|
4801
|
-
const
|
|
4802
|
-
const unknownOptInMutations = (requested) => requested.filter((name) => !KNOWN_OPT_IN_MUTATIONS.includes(name));
|
|
4803
|
-
const listNames = (names) => Option.match(Option.fromNullishOr(names.at(0)), {
|
|
4804
|
-
onNone: () => "none",
|
|
4805
|
-
onSome: () => names.map((name) => `'${name}'`).join(", ")
|
|
4806
|
-
});
|
|
4807
|
-
const unknownOptInMutationsError = (requested) => Option.map(Option.fromNullishOr(unknownOptInMutations(requested).at(0)), () => InstrumentError.make({
|
|
4808
|
-
message: `Unknown opt-in mutations: ${listNames(unknownOptInMutations(requested))}. Known opt-in mutations: ${listNames(KNOWN_OPT_IN_MUTATIONS)}.`,
|
|
4809
|
-
cause: void 0
|
|
4810
|
-
}));
|
|
4811
|
-
const refuseUnknownOptInMutations = (options) => Option.match(unknownOptInMutationsError(optInMutationsOf(options)), {
|
|
4812
|
-
onNone: () => Effect.void,
|
|
4813
|
-
onSome: (error) => Effect.fail(error)
|
|
4814
|
-
});
|
|
4815
|
-
const instrumentDataFirst = (files, options, registry = coreFormatRegistry) => refuseUnknownOptInMutations(options).pipe(Effect.andThen(instrumentFilesCell.run({
|
|
5109
|
+
const instrumentDataFirst = (files, options, registry = coreFormatRegistry) => instrumentFilesCell.run({
|
|
4816
5110
|
files: files.map(toSchemaFile),
|
|
4817
5111
|
options,
|
|
4818
5112
|
registry
|
|
4819
|
-
})
|
|
5113
|
+
});
|
|
4820
5114
|
const instrument = dual((args) => Array.isArray(args[0]), instrumentDataFirst);
|
|
4821
5115
|
const disableTypeChecksDataFirst = (file, registry = coreFormatRegistry) => disableTypeChecksCell.run({
|
|
4822
5116
|
file: toSchemaFile(file),
|
|
@@ -4833,36 +5127,25 @@ const disableTypeChecks = dual((args) => Predicate.hasProperty(args[0], "content
|
|
|
4833
5127
|
//#region src/Instrument/mod.ts
|
|
4834
5128
|
var Instrument_exports = /* @__PURE__ */ __exportAll({
|
|
4835
5129
|
InstrumentFileSkip: () => InstrumentFileSkip,
|
|
5130
|
+
InstrumenterContext: () => InstrumenterContext,
|
|
4836
5131
|
disableTypeChecks: () => disableTypeChecks,
|
|
4837
5132
|
instrument: () => instrument
|
|
4838
5133
|
});
|
|
4839
5134
|
//#endregion
|
|
4840
|
-
//#region src/
|
|
4841
|
-
var
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
MutantActivationSchema: () => MutantActivationSchema,
|
|
4852
|
-
MutantCoverageSchema: () => MutantCoverageSchema,
|
|
4853
|
-
MutantFromUnknown: () => MutantFromUnknown,
|
|
4854
|
-
MutantId: () => MutantId,
|
|
4855
|
-
MutantRunOptionsSchema: () => MutantRunOptionsSchema,
|
|
4856
|
-
MutantStatusSchema: () => MutantStatusSchema,
|
|
4857
|
-
MutatorName: () => MutatorName,
|
|
5135
|
+
//#region src/Mutator/mod.ts
|
|
5136
|
+
var Mutator_exports = /* @__PURE__ */ __exportAll({
|
|
5137
|
+
defaultMutators: () => defaultMutators,
|
|
5138
|
+
optInMutators: () => optInMutators,
|
|
5139
|
+
registryOf: () => registryOf,
|
|
5140
|
+
selectMutators: () => selectMutators,
|
|
5141
|
+
stockRegistry: () => stockRegistry
|
|
5142
|
+
});
|
|
5143
|
+
//#endregion
|
|
5144
|
+
//#region src/Source/mod.ts
|
|
5145
|
+
var Source_exports = /* @__PURE__ */ __exportAll({
|
|
4858
5146
|
Offset: () => Offset,
|
|
4859
|
-
OpenEndLocation: () => OpenEndLocation,
|
|
4860
|
-
Position: () => Position,
|
|
4861
|
-
RememberedStatusSchema: () => RememberedStatusSchema,
|
|
4862
|
-
RunOptionsFields: () => RunOptionsFields,
|
|
4863
5147
|
ScriptOrigin: () => ScriptOrigin,
|
|
4864
|
-
Span: () => Span
|
|
4865
|
-
SurvivorStatusSchema: () => SurvivorStatusSchema
|
|
5148
|
+
Span: () => Span
|
|
4866
5149
|
});
|
|
4867
5150
|
//#endregion
|
|
4868
|
-
export { ErrorText_exports as ErrorText, Format_exports as Format, Instrument_exports as Instrument,
|
|
5151
|
+
export { ErrorText_exports as ErrorText, Format_exports as Format, Instrument_exports as Instrument, Mutator_exports as Mutator, Source_exports as Source, lineStartsOf, locationOf, offsetAt, originAt, positionAt };
|