@systemfsoftware/stryker-js-instrumenter 6.0.1 → 7.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 +23 -0
- package/README.md +1 -1
- package/dist/index.d.mts +5 -12
- package/dist/index.mjs +466 -714
- package/package.json +27 -21
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { INSTRUMENTER_CONSTANTS, Mutant
|
|
1
|
+
import { INSTRUMENTER_CONSTANTS, Mutant } from "@systemfsoftware/stryker-js-language";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Predicate from "effect/Predicate";
|
|
4
4
|
import * as S from "effect/Schema";
|
|
5
5
|
import * as Arr from "effect/Array";
|
|
6
6
|
import * as Match from "effect/Match";
|
|
7
7
|
import * as Option from "effect/Option";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import { walk } from "oxc-walker";
|
|
9
|
+
import { Schema } from "effect";
|
|
10
10
|
import { RegExpParser, visitRegExpAST } from "@eslint-community/regexpp";
|
|
11
11
|
//#region src/Instrument.schema.ts
|
|
12
|
-
var InstrumentError = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/InstrumentError")("InstrumentError", {
|
|
12
|
+
var InstrumentError = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Instrument.schema/InstrumentError")("InstrumentError", {
|
|
13
13
|
message: S.String,
|
|
14
14
|
cause: S.Defect()
|
|
15
15
|
}) {
|
|
@@ -33,27 +33,11 @@ const FileSchema = S.Struct({
|
|
|
33
33
|
mutate: MutateDescriptionSchema
|
|
34
34
|
});
|
|
35
35
|
const IgnorerSchema = S.Unknown;
|
|
36
|
-
|
|
37
|
-
const InstrumenterOptionsSchema = S.Struct({
|
|
36
|
+
S.Struct({
|
|
38
37
|
excludedMutations: S.Array(S.String),
|
|
39
38
|
ignorers: S.Array(IgnorerSchema),
|
|
40
39
|
noHeader: S.optional(S.Boolean)
|
|
41
40
|
});
|
|
42
|
-
var InstrumentCommand = class extends S.TaggedClass()("InstrumentCommand", {
|
|
43
|
-
files: S.Array(FileSchema),
|
|
44
|
-
options: InstrumenterOptionsSchema
|
|
45
|
-
}) {};
|
|
46
|
-
var InstrumentDecoded = class extends S.TaggedClass()("InstrumentDecoded", {
|
|
47
|
-
files: S.Array(FileSchema),
|
|
48
|
-
options: InstrumenterOptionsSchema,
|
|
49
|
-
asts: S.Array(AstSchema),
|
|
50
|
-
mutants: S.Array(Mutant)
|
|
51
|
-
}) {};
|
|
52
|
-
var InstrumentDecision = class extends S.TaggedClass()("InstrumentDecision", {
|
|
53
|
-
files: S.Array(FileSchema),
|
|
54
|
-
mutants: S.Array(Mutant),
|
|
55
|
-
asts: S.Array(AstSchema)
|
|
56
|
-
}) {};
|
|
57
41
|
var InstrumentResult = class extends S.TaggedClass()("InstrumentResult", {
|
|
58
42
|
files: S.Array(FileSchema),
|
|
59
43
|
mutants: S.Array(Mutant)
|
|
@@ -122,13 +106,10 @@ function requireMidpoint(midValue) {
|
|
|
122
106
|
return midValue;
|
|
123
107
|
}
|
|
124
108
|
//#endregion
|
|
125
|
-
//#region src/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* back standard ESTree, so the instrumenter owns the traversal instead of
|
|
130
|
-
* without pulling scope machinery along.
|
|
131
|
-
*/
|
|
109
|
+
//#region src/Traversal.schema.ts
|
|
110
|
+
var TraversalStopped = class extends Schema.TaggedError()("TraversalStopped", {}) {};
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/Ast.ts
|
|
132
113
|
const EXPRESSION_KINDS = /* @__PURE__ */ new Set([
|
|
133
114
|
"ArrayExpression",
|
|
134
115
|
"ArrowFunctionExpression",
|
|
@@ -194,10 +175,6 @@ const STATEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
194
175
|
"WhileStatement",
|
|
195
176
|
"WithStatement"
|
|
196
177
|
]);
|
|
197
|
-
/**
|
|
198
|
-
* The node's [start, end) offsets. oxc is invoked with `range: true`, so every
|
|
199
|
-
* parsed node carries one; synthesized builders omit it.
|
|
200
|
-
*/
|
|
201
178
|
function spanOf(node) {
|
|
202
179
|
const range = node.range;
|
|
203
180
|
if (range === void 0) return void 0;
|
|
@@ -206,10 +183,6 @@ function spanOf(node) {
|
|
|
206
183
|
end: range[1]
|
|
207
184
|
};
|
|
208
185
|
}
|
|
209
|
-
/**
|
|
210
|
-
* The node's `type` tag, for checks against kinds outside the @types/estree
|
|
211
|
-
* union (TS and JSX extensions oxc emits).
|
|
212
|
-
*/
|
|
213
186
|
function nodeType(node) {
|
|
214
187
|
if (!isAstNode(node)) return void 0;
|
|
215
188
|
return node.type;
|
|
@@ -238,19 +211,22 @@ function identifier(name, loc) {
|
|
|
238
211
|
function stringLiteral(value, loc) {
|
|
239
212
|
return mark({
|
|
240
213
|
type: "Literal",
|
|
241
|
-
value
|
|
214
|
+
value,
|
|
215
|
+
raw: null
|
|
242
216
|
}, loc);
|
|
243
217
|
}
|
|
244
218
|
function booleanLiteral(value, loc) {
|
|
245
219
|
return mark({
|
|
246
220
|
type: "Literal",
|
|
247
|
-
value
|
|
221
|
+
value,
|
|
222
|
+
raw: null
|
|
248
223
|
}, loc);
|
|
249
224
|
}
|
|
250
225
|
function regExpLiteral(pattern, flags, loc) {
|
|
251
226
|
return mark({
|
|
252
227
|
type: "Literal",
|
|
253
228
|
value: null,
|
|
229
|
+
raw: null,
|
|
254
230
|
regex: {
|
|
255
231
|
pattern,
|
|
256
232
|
flags
|
|
@@ -278,12 +254,12 @@ function newExpression(callee, args = [], loc) {
|
|
|
278
254
|
arguments: [...args]
|
|
279
255
|
}, loc);
|
|
280
256
|
}
|
|
281
|
-
function memberExpression(object, property,
|
|
257
|
+
function memberExpression(object, property, optional, loc) {
|
|
282
258
|
return mark({
|
|
283
259
|
type: "MemberExpression",
|
|
284
260
|
object,
|
|
285
261
|
property,
|
|
286
|
-
computed,
|
|
262
|
+
computed: false,
|
|
287
263
|
optional
|
|
288
264
|
}, loc);
|
|
289
265
|
}
|
|
@@ -291,6 +267,8 @@ function arrowFunctionExpression(params, body, loc) {
|
|
|
291
267
|
const fnBody = body;
|
|
292
268
|
return mark({
|
|
293
269
|
type: "ArrowFunctionExpression",
|
|
270
|
+
id: null,
|
|
271
|
+
generator: false,
|
|
294
272
|
params: [...params],
|
|
295
273
|
body: fnBody,
|
|
296
274
|
async: false,
|
|
@@ -391,20 +369,9 @@ function switchCase(test, consequent, loc) {
|
|
|
391
369
|
consequent: [...consequent]
|
|
392
370
|
}, loc);
|
|
393
371
|
}
|
|
394
|
-
/**
|
|
395
|
-
* Deep clone of a plain ESTree node. oxc nodes are JSON-shaped, so
|
|
396
|
-
* Deep clone over plain nodes: no prototypes to preserve.
|
|
397
|
-
*/
|
|
398
372
|
function cloneNode(node) {
|
|
399
373
|
return structuredClone(node);
|
|
400
374
|
}
|
|
401
|
-
/**
|
|
402
|
-
* Attaches every comment to the node it precedes (`leadingComments`) or, when
|
|
403
|
-
* no node follows it, to the node it trails (`trailingComments`). oxc ships
|
|
404
|
-
* comments flat, and the Stryker directive pass reads `node.leadingComments`,
|
|
405
|
-
* so the flat list is folded into the tree once per transform with the file's
|
|
406
|
-
* line table in hand.
|
|
407
|
-
*/
|
|
408
375
|
function attachComments(root, comments, lineTable) {
|
|
409
376
|
if (comments.length === 0) return;
|
|
410
377
|
const nodes = collectNodes(root).filter((entry) => entry.node !== root);
|
|
@@ -421,13 +388,6 @@ function groupComments(nodes, comments) {
|
|
|
421
388
|
for (const comment of comments) hostComment(nodes, comment, groups);
|
|
422
389
|
return groups;
|
|
423
390
|
}
|
|
424
|
-
/**
|
|
425
|
-
* The map a comment is hosted in. A comment attaches to the node it precedes;
|
|
426
|
-
* one that precedes nothing — a same-line trailing comment — attaches to the
|
|
427
|
-
* nearest statement before it, because the statement printer is the only
|
|
428
|
-
* emitter of trailing comments and an expression host would never reach the
|
|
429
|
-
* output.
|
|
430
|
-
*/
|
|
431
391
|
function hostComment(nodes, comment, groups) {
|
|
432
392
|
const host = [{
|
|
433
393
|
field: "leading",
|
|
@@ -465,32 +425,27 @@ function pushComment(map, node, comment) {
|
|
|
465
425
|
if (list === void 0) map.set(node, [comment]);
|
|
466
426
|
else list.push(comment);
|
|
467
427
|
}
|
|
468
|
-
/** oxc emits a node's children as a plain array the walker reads and replaces into. */
|
|
469
428
|
const isNodeList = (value) => Array.isArray(value);
|
|
470
|
-
|
|
429
|
+
const walker = (root, visitors) => {
|
|
430
|
+
const ancestors = [];
|
|
431
|
+
walk(root, {
|
|
432
|
+
enter(node) {
|
|
433
|
+
visitors.enter?.(node, [...ancestors]);
|
|
434
|
+
ancestors.push(node);
|
|
435
|
+
},
|
|
436
|
+
leave(node) {
|
|
437
|
+
ancestors.pop();
|
|
438
|
+
visitors.leave?.(node, [...ancestors]);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
function collectNodes(root) {
|
|
471
443
|
const out = [];
|
|
472
|
-
|
|
444
|
+
walker(root, { enter(node) {
|
|
445
|
+
appendEntry(node, out);
|
|
446
|
+
} });
|
|
473
447
|
return out;
|
|
474
448
|
}
|
|
475
|
-
function collect$1(node, out) {
|
|
476
|
-
if (isNodeList(node)) return collectList(node, out);
|
|
477
|
-
collectAstNode(node, out);
|
|
478
|
-
}
|
|
479
|
-
function collectList(items, out) {
|
|
480
|
-
for (const item of items) collect$1(item, out);
|
|
481
|
-
}
|
|
482
|
-
function collectAstNode(value, out) {
|
|
483
|
-
if (!isAstNode(value)) return;
|
|
484
|
-
appendEntry(value, out);
|
|
485
|
-
collectChildren(value, out);
|
|
486
|
-
}
|
|
487
|
-
function collectChildren(node, out) {
|
|
488
|
-
for (const key of Object.keys(node)) collectChild(node, key, out);
|
|
489
|
-
}
|
|
490
|
-
function collectChild(node, key, out) {
|
|
491
|
-
if (SKIP_KEYS.has(key)) return;
|
|
492
|
-
collect$1(node[key], out);
|
|
493
|
-
}
|
|
494
449
|
function appendEntry(node, out) {
|
|
495
450
|
const span = spanOf(node);
|
|
496
451
|
if (span === void 0) return;
|
|
@@ -510,80 +465,59 @@ function positionFromLineTable(offset, lineTable) {
|
|
|
510
465
|
const zeroBased = positionFromOffset(lineTable, offset);
|
|
511
466
|
return {
|
|
512
467
|
line: zeroBased.line + 1,
|
|
513
|
-
column: zeroBased.column
|
|
468
|
+
column: zeroBased.column + 1
|
|
514
469
|
};
|
|
515
470
|
}
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
"
|
|
519
|
-
"end",
|
|
520
|
-
"range",
|
|
521
|
-
"loc",
|
|
522
|
-
"leadingComments",
|
|
523
|
-
"trailingComments"
|
|
524
|
-
]);
|
|
525
|
-
function traverse(root, visitors) {
|
|
526
|
-
visit(root, null, "root", void 0, visitors, {
|
|
527
|
-
skipped: /* @__PURE__ */ new Set(),
|
|
528
|
-
stopped: false
|
|
529
|
-
});
|
|
471
|
+
const COMMENT_KEYS = /* @__PURE__ */ new Set(["leadingComments", "trailingComments"]);
|
|
472
|
+
function isCommentKey(key) {
|
|
473
|
+
return typeof key === "string" && COMMENT_KEYS.has(key);
|
|
530
474
|
}
|
|
531
|
-
function
|
|
532
|
-
|
|
533
|
-
|
|
475
|
+
function traverse(root, visitors) {
|
|
476
|
+
const stack = [];
|
|
477
|
+
try {
|
|
478
|
+
walk(root, {
|
|
479
|
+
enter(node, _parent, context) {
|
|
480
|
+
readPath(stack, node, this, context, visitors);
|
|
481
|
+
},
|
|
482
|
+
leave(_node, _parent, context) {
|
|
483
|
+
closePath(stack, context, visitors);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
} catch (error) {
|
|
487
|
+
rethrowUnlessStopped(error);
|
|
488
|
+
}
|
|
534
489
|
}
|
|
535
|
-
|
|
536
|
-
if (!
|
|
537
|
-
|
|
490
|
+
const rethrowUnlessStopped = (error) => {
|
|
491
|
+
if (!S.is(TraversalStopped)(error)) throw error;
|
|
492
|
+
};
|
|
493
|
+
const readPath = (stack, node, controls, context, visitors) => {
|
|
494
|
+
if (isCommentKey(context.key)) return;
|
|
495
|
+
const path = createPath(node, parentOf(stack), controls, context);
|
|
496
|
+
stack.push(path);
|
|
538
497
|
notify(visitors.enter, path);
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (context.skipped.has(node)) return;
|
|
546
|
-
visitChildren(node, path, visitors, context);
|
|
547
|
-
notifyExit(visitors.exit, path, context);
|
|
548
|
-
}
|
|
549
|
-
function notifyExit(visitor, path, context) {
|
|
550
|
-
if (context.stopped) return;
|
|
551
|
-
notify(visitor, path);
|
|
552
|
-
}
|
|
498
|
+
};
|
|
499
|
+
const closePath = (stack, context, visitors) => {
|
|
500
|
+
if (isCommentKey(context.key)) return;
|
|
501
|
+
notify(visitors.exit, stack.pop());
|
|
502
|
+
};
|
|
503
|
+
const parentOf = (stack) => Option.getOrNull(Arr.last(stack));
|
|
553
504
|
function notify(visitor, path) {
|
|
554
505
|
if (visitor === void 0) return;
|
|
555
|
-
visitor
|
|
556
|
-
}
|
|
557
|
-
function visitChildren(node, path, visitors, context) {
|
|
558
|
-
Object.keys(node).every((key) => keepVisitingKey(node, path, key, visitors, context));
|
|
559
|
-
}
|
|
560
|
-
function keepVisitingKey(node, path, key, visitors, context) {
|
|
561
|
-
if (SKIP_KEYS.has(key)) return true;
|
|
562
|
-
return keepVisitingChild(node[key], path, key, visitors, context);
|
|
506
|
+
relay(visitor, path);
|
|
563
507
|
}
|
|
564
|
-
|
|
565
|
-
if (
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return items.every((item, index) => keepVisitingValue(item, path, key, String(index), visitors, context));
|
|
570
|
-
}
|
|
571
|
-
function keepVisitingValue(value, path, key, listKey, visitors, context) {
|
|
572
|
-
visit(value, path, key, listKey, visitors, context);
|
|
573
|
-
return !context.stopped;
|
|
574
|
-
}
|
|
575
|
-
function createPath(node, parentPath, key, listKey, context) {
|
|
508
|
+
const relay = (visitor, path) => {
|
|
509
|
+
if (path !== void 0) visitor(path);
|
|
510
|
+
};
|
|
511
|
+
function createPath(node, parentPath, controls, context) {
|
|
512
|
+
const key = typeof context.key === "string" ? context.key : void 0;
|
|
576
513
|
const path = {
|
|
577
514
|
node,
|
|
578
515
|
parentPath,
|
|
579
|
-
parent: parentPath?.node,
|
|
580
|
-
key,
|
|
581
|
-
listKey,
|
|
582
516
|
skip() {
|
|
583
|
-
|
|
517
|
+
controls.skip();
|
|
584
518
|
},
|
|
585
519
|
stop() {
|
|
586
|
-
|
|
520
|
+
throw TraversalStopped.make({});
|
|
587
521
|
},
|
|
588
522
|
find(predicate) {
|
|
589
523
|
return nearest(path, predicate);
|
|
@@ -592,10 +526,7 @@ function createPath(node, parentPath, key, listKey, context) {
|
|
|
592
526
|
return nearest(parentPath, (ancestor) => isStatementKind(ancestor.node));
|
|
593
527
|
},
|
|
594
528
|
replaceWith(replacement) {
|
|
595
|
-
|
|
596
|
-
},
|
|
597
|
-
is(kind) {
|
|
598
|
-
return node.type === kind;
|
|
529
|
+
replaceInSlot(parentPath, key, context.index, replacement);
|
|
599
530
|
},
|
|
600
531
|
isExpression() {
|
|
601
532
|
return isExpressionKind(node);
|
|
@@ -614,39 +545,36 @@ function takeOrAscend(path, predicate) {
|
|
|
614
545
|
if (predicate(path)) return path;
|
|
615
546
|
return nearest(path.parentPath, predicate);
|
|
616
547
|
}
|
|
617
|
-
function
|
|
548
|
+
function replaceInSlot(parentPath, key, index, replacement) {
|
|
618
549
|
if (parentPath === null) return;
|
|
619
|
-
|
|
550
|
+
writeInto(parentPath.node, key, index, replacement);
|
|
620
551
|
}
|
|
621
|
-
function
|
|
552
|
+
function writeInto(parent, key, index, replacement) {
|
|
622
553
|
if (!isAstNode(parent)) return;
|
|
623
|
-
|
|
554
|
+
writeAtKey(parent, key, index, replacement);
|
|
624
555
|
}
|
|
625
|
-
function
|
|
626
|
-
|
|
627
|
-
parent[key] = replacement;
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
assignIndexed(parent, key, listKey, replacement);
|
|
631
|
-
}
|
|
632
|
-
function assignIndexed(parent, key, listKey, replacement) {
|
|
633
|
-
const index = Number(listKey);
|
|
634
|
-
const container = parent[key];
|
|
635
|
-
if (isIndexedList(container, index)) container[index] = replacement;
|
|
556
|
+
function writeAtKey(parent, key, index, replacement) {
|
|
557
|
+
Match.value(key).pipe(Match.when(Predicate.isString, (slot) => writeAtSlot(parent, slot, index, replacement)), Match.orElse(() => void 0));
|
|
636
558
|
}
|
|
637
|
-
function
|
|
638
|
-
|
|
559
|
+
function writeAtSlot(parent, key, index, replacement) {
|
|
560
|
+
Match.value(index).pipe(Match.when(Match.null, () => overwrite(parent, key, replacement)), Match.orElse((position) => writeElement(parent[key], position, replacement)));
|
|
639
561
|
}
|
|
562
|
+
const overwrite = (parent, key, replacement) => {
|
|
563
|
+
parent[key] = replacement;
|
|
564
|
+
};
|
|
565
|
+
const writeElement = (container, index, replacement) => {
|
|
566
|
+
if (isNodeList(container)) container[index] = replacement;
|
|
567
|
+
};
|
|
640
568
|
//#endregion
|
|
641
569
|
//#region src/Oxc.ts
|
|
642
570
|
let oxc;
|
|
643
|
-
const loadOxc =
|
|
644
|
-
if (oxc === void 0) oxc =
|
|
571
|
+
const loadOxc = Effect.gen(function* () {
|
|
572
|
+
if (oxc === void 0) oxc = yield* Effect.promise(() => import("oxc-parser"));
|
|
645
573
|
return oxc;
|
|
646
|
-
};
|
|
574
|
+
});
|
|
647
575
|
//#endregion
|
|
648
576
|
//#region src/Parser.schema.ts
|
|
649
|
-
var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParseFailed")("ParseFailed", {
|
|
577
|
+
var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/ParseFailed")("ParseFailed", {
|
|
650
578
|
fileName: S.String,
|
|
651
579
|
message: S.String,
|
|
652
580
|
location: S.Struct({
|
|
@@ -659,7 +587,7 @@ var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instr
|
|
|
659
587
|
return `Failed to parse ${this.fileName} at ${this.location.line}:${this.location.column}: ${this.message}`;
|
|
660
588
|
}
|
|
661
589
|
};
|
|
662
|
-
var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParserNotFound")("ParserNotFound", {
|
|
590
|
+
var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/ParserNotFound")("ParserNotFound", {
|
|
663
591
|
fileName: S.String,
|
|
664
592
|
extension: S.String,
|
|
665
593
|
cause: S.Defect()
|
|
@@ -668,7 +596,7 @@ var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-in
|
|
|
668
596
|
return `No parser registered for ${this.fileName} (extension "${this.extension}")`;
|
|
669
597
|
}
|
|
670
598
|
};
|
|
671
|
-
var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteVersionNotSupported")("SvelteVersionNotSupported", {
|
|
599
|
+
var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/SvelteVersionNotSupported")("SvelteVersionNotSupported", {
|
|
672
600
|
version: S.String,
|
|
673
601
|
fileName: S.String,
|
|
674
602
|
cause: S.Defect()
|
|
@@ -677,7 +605,7 @@ var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/st
|
|
|
677
605
|
return `Svelte version ${this.version} is not supported for ${this.fileName} (expected >=3.30)`;
|
|
678
606
|
}
|
|
679
607
|
};
|
|
680
|
-
var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteWalkerNotFound")("SvelteWalkerNotFound", {
|
|
608
|
+
var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/SvelteWalkerNotFound")("SvelteWalkerNotFound", {
|
|
681
609
|
fileName: S.String,
|
|
682
610
|
cause: S.Defect()
|
|
683
611
|
}) {
|
|
@@ -685,7 +613,7 @@ var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker
|
|
|
685
613
|
return `Svelte walker not found for ${this.fileName}`;
|
|
686
614
|
}
|
|
687
615
|
};
|
|
688
|
-
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteParseFailed")("SvelteParseFailed", {
|
|
616
|
+
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/SvelteParseFailed")("SvelteParseFailed", {
|
|
689
617
|
fileName: S.String,
|
|
690
618
|
cause: S.Defect()
|
|
691
619
|
});
|
|
@@ -727,23 +655,23 @@ function fieldOf(value, key) {
|
|
|
727
655
|
function appendIfDefined(values, value) {
|
|
728
656
|
if (value !== void 0) values.push(value);
|
|
729
657
|
}
|
|
730
|
-
|
|
731
|
-
const { parseSync } =
|
|
658
|
+
const parseWithOxc = (text, fileName, lang) => Effect.gen(function* () {
|
|
659
|
+
const { parseSync } = yield* loadOxc;
|
|
732
660
|
const result = parseSync(fileName, text, {
|
|
733
661
|
lang,
|
|
734
662
|
range: true
|
|
735
663
|
});
|
|
736
664
|
const failure = oxcParseFailure(result.errors, text, fileName);
|
|
737
|
-
if (failure !== void 0)
|
|
665
|
+
if (failure !== void 0) return yield* failure;
|
|
738
666
|
return {
|
|
739
667
|
root: result.program,
|
|
740
668
|
comments: result.comments
|
|
741
669
|
};
|
|
742
|
-
}
|
|
670
|
+
});
|
|
743
671
|
function oxcParseFailure(errors, text, fileName) {
|
|
744
672
|
const first = errors.at(0);
|
|
745
673
|
if (first === void 0) return;
|
|
746
|
-
return
|
|
674
|
+
return ParseFailed.make({
|
|
747
675
|
fileName,
|
|
748
676
|
message: first.message,
|
|
749
677
|
location: positionFromLineTable(oxcErrorLabelStart(first), buildLineTable(text)),
|
|
@@ -770,13 +698,16 @@ function shiftScriptOffsets(ast, offset) {
|
|
|
770
698
|
}
|
|
771
699
|
function createParser() {
|
|
772
700
|
const jsParse = createJSParser();
|
|
773
|
-
|
|
701
|
+
function parse(code, fileName, formatOverride) {
|
|
774
702
|
const format = getFormat(fileName, formatOverride);
|
|
775
|
-
if (!format)
|
|
776
|
-
fileName
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
703
|
+
if (!format) {
|
|
704
|
+
const ext = extensionOf(fileName);
|
|
705
|
+
return Effect.fail(ParserNotFound.make({
|
|
706
|
+
fileName,
|
|
707
|
+
extension: ext,
|
|
708
|
+
cause: void 0
|
|
709
|
+
}));
|
|
710
|
+
}
|
|
780
711
|
return Match.value(format).pipe(Match.when("js", () => jsParse(code, fileName)), Match.when("tsx", () => parseTsx(code, fileName)), Match.when("ts", () => parseTS(code, fileName)), Match.when("html", () => parseHtml(code, fileName, { parse })), Match.when("svelte", () => parseSvelte(code, fileName, { parse })), Match.exhaustive);
|
|
781
712
|
}
|
|
782
713
|
return parse;
|
|
@@ -796,40 +727,37 @@ const FORMAT_BY_EXTENSION = {
|
|
|
796
727
|
".svelte": "svelte"
|
|
797
728
|
};
|
|
798
729
|
function getFormat(fileName, override) {
|
|
799
|
-
return override ?? FORMAT_BY_EXTENSION[
|
|
730
|
+
return override ?? FORMAT_BY_EXTENSION[extensionOf(fileName)];
|
|
800
731
|
}
|
|
732
|
+
const dotBeforeSlash = (dot, slash) => dot >= 0 && dot > slash;
|
|
733
|
+
const extensionOf = (fileName) => {
|
|
734
|
+
const dot = fileName.lastIndexOf(".");
|
|
735
|
+
const slash = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
|
|
736
|
+
return dotBeforeSlash(dot, slash) ? fileName.slice(dot).toLowerCase() : "";
|
|
737
|
+
};
|
|
801
738
|
function createJSParser() {
|
|
802
|
-
return
|
|
803
|
-
const { root, comments } = await parseWithOxc(text, fileName, "js");
|
|
804
|
-
return {
|
|
805
|
-
originFileName: fileName,
|
|
806
|
-
rawContent: text,
|
|
807
|
-
format: "js",
|
|
808
|
-
root,
|
|
809
|
-
comments
|
|
810
|
-
};
|
|
811
|
-
};
|
|
812
|
-
}
|
|
813
|
-
async function parseTS(text, fileName) {
|
|
814
|
-
const { root, comments } = await parseWithOxc(text, fileName, "ts");
|
|
815
|
-
return {
|
|
739
|
+
return (text, fileName) => Effect.map(parseWithOxc(text, fileName, "js"), ({ root, comments }) => ({
|
|
816
740
|
originFileName: fileName,
|
|
817
741
|
rawContent: text,
|
|
818
|
-
format: "
|
|
742
|
+
format: "js",
|
|
819
743
|
root,
|
|
820
744
|
comments
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
async function parseTsx(text, fileName) {
|
|
824
|
-
const { root, comments } = await parseWithOxc(text, fileName, "tsx");
|
|
825
|
-
return {
|
|
826
|
-
root,
|
|
827
|
-
comments,
|
|
828
|
-
format: "tsx",
|
|
829
|
-
originFileName: fileName,
|
|
830
|
-
rawContent: text
|
|
831
|
-
};
|
|
745
|
+
}));
|
|
832
746
|
}
|
|
747
|
+
const parseTS = (text, fileName) => Effect.map(parseWithOxc(text, fileName, "ts"), ({ root, comments }) => ({
|
|
748
|
+
originFileName: fileName,
|
|
749
|
+
rawContent: text,
|
|
750
|
+
format: "ts",
|
|
751
|
+
root,
|
|
752
|
+
comments
|
|
753
|
+
}));
|
|
754
|
+
const parseTsx = (text, fileName) => Effect.map(parseWithOxc(text, fileName, "tsx"), ({ root, comments }) => ({
|
|
755
|
+
root,
|
|
756
|
+
comments,
|
|
757
|
+
format: "tsx",
|
|
758
|
+
originFileName: fileName,
|
|
759
|
+
rawContent: text
|
|
760
|
+
}));
|
|
833
761
|
const SCRIPT_TYPE_FORMATS = {
|
|
834
762
|
tsx: "tsx",
|
|
835
763
|
"text/tsx": "tsx",
|
|
@@ -841,27 +769,25 @@ const SCRIPT_TYPE_FORMATS = {
|
|
|
841
769
|
javascript: "js",
|
|
842
770
|
module: "js"
|
|
843
771
|
};
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
async function ngHtmlParser(text, fileName, parserContext) {
|
|
853
|
-
const ngParser = await import("angular-html-parser");
|
|
772
|
+
const parseHtml = (text, originFileName, context) => Effect.map(ngHtmlParser(text, originFileName, context), (root) => ({
|
|
773
|
+
originFileName,
|
|
774
|
+
rawContent: text,
|
|
775
|
+
format: "html",
|
|
776
|
+
root
|
|
777
|
+
}));
|
|
778
|
+
const ngHtmlParser = (text, fileName, parserContext) => Effect.gen(function* () {
|
|
779
|
+
const ngParser = yield* Effect.promise(() => import("angular-html-parser"));
|
|
854
780
|
const { rootNodes, errors } = ngParser.parse(text, {
|
|
855
781
|
canSelfClose: true,
|
|
856
782
|
allowHtmComponentClosingTags: true,
|
|
857
783
|
isTagNameCaseSensitive: true
|
|
858
784
|
});
|
|
859
|
-
if (errors.length !== 0)
|
|
860
|
-
const
|
|
785
|
+
if (errors.length !== 0) return yield* htmlErrorFailure(errors, fileName);
|
|
786
|
+
const scriptEffects = [];
|
|
861
787
|
const scriptCollector = {
|
|
862
788
|
visitElement: (el, context) => {
|
|
863
789
|
const scriptFormat = getScriptType(el);
|
|
864
|
-
if (scriptFormat)
|
|
790
|
+
if (scriptFormat) scriptEffects.push(parseScript(el, scriptFormat));
|
|
865
791
|
ngParser.visitAll(scriptCollector, el.children, context);
|
|
866
792
|
},
|
|
867
793
|
visitAttribute: () => void 0,
|
|
@@ -878,10 +804,9 @@ async function ngHtmlParser(text, fileName, parserContext) {
|
|
|
878
804
|
visitDirective: () => void 0
|
|
879
805
|
};
|
|
880
806
|
ngParser.visitAll(scriptCollector, rootNodes);
|
|
881
|
-
return { scripts:
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
if (ast != null) {
|
|
807
|
+
return { scripts: yield* Effect.all(scriptEffects) };
|
|
808
|
+
function parseScript(el, scriptFormat) {
|
|
809
|
+
return Effect.map(parserContext.parse(elementScriptText(el, text), fileName, scriptFormat), (ast) => {
|
|
885
810
|
const offset = el.startSourceSpan.end;
|
|
886
811
|
shiftScriptOffsets(ast, offset.offset);
|
|
887
812
|
return {
|
|
@@ -891,13 +816,12 @@ async function ngHtmlParser(text, fileName, parserContext) {
|
|
|
891
816
|
line: offset.line
|
|
892
817
|
}
|
|
893
818
|
};
|
|
894
|
-
}
|
|
895
|
-
return ast;
|
|
819
|
+
});
|
|
896
820
|
}
|
|
897
|
-
}
|
|
821
|
+
});
|
|
898
822
|
function htmlErrorFailure(errors, fileName) {
|
|
899
823
|
const first = errors.at(0);
|
|
900
|
-
if (first === void 0) return
|
|
824
|
+
if (first === void 0) return ParseFailed.make({
|
|
901
825
|
fileName,
|
|
902
826
|
message: "HTML parser reported errors but first error is missing",
|
|
903
827
|
location: {
|
|
@@ -906,7 +830,7 @@ function htmlErrorFailure(errors, fileName) {
|
|
|
906
830
|
},
|
|
907
831
|
cause: errors
|
|
908
832
|
});
|
|
909
|
-
return
|
|
833
|
+
return ParseFailed.make({
|
|
910
834
|
fileName,
|
|
911
835
|
message: first.msg,
|
|
912
836
|
location: toSourceLocation(first.span.start),
|
|
@@ -948,7 +872,7 @@ const SVELTE_5 = {
|
|
|
948
872
|
major: 5,
|
|
949
873
|
minor: 0
|
|
950
874
|
};
|
|
951
|
-
const
|
|
875
|
+
const WALKER_MODULE_MISSING = "walker module without walk export";
|
|
952
876
|
const COMPILER_WALK_MISSING = "svelte/compiler module without walk export";
|
|
953
877
|
const INSTANCE_RANGE_MISSING = "Svelte instance script without a source range";
|
|
954
878
|
const MODULE_RANGE_MISSING = "Svelte module script without a source range";
|
|
@@ -1029,75 +953,68 @@ function rangedExpressionOf(payload) {
|
|
|
1029
953
|
* Due to the way Svelte 5 is structured, we can no longer use the typings from Svelte 4, even though
|
|
1030
954
|
* we use the legacy AST. The full Svelte 5 migration should update these typings to use the new AST.
|
|
1031
955
|
*/
|
|
1032
|
-
|
|
1033
|
-
return Match.value(isAtLeast(version, SVELTE_5)).pipe(Match.when(true, () => loadWalkerModule(import.meta.resolve("estree-walker"), fileName, ESTREE_WALKER_MISSING)), Match.orElse(() => loadWalkerModule("svelte/compiler", fileName, COMPILER_WALK_MISSING)));
|
|
1034
|
-
}
|
|
956
|
+
const loadWalker = (version, fileName) => Match.value(isAtLeast(version, SVELTE_5)).pipe(Match.when(true, () => loadWalkerModule(import.meta.resolve("oxc-walker"), fileName, WALKER_MODULE_MISSING)), Match.orElse(() => loadWalkerModule("svelte/compiler", fileName, COMPILER_WALK_MISSING)));
|
|
1035
957
|
/**
|
|
1036
958
|
* The specifier is chosen at run time and both modules are optional peers of
|
|
1037
959
|
* this package, so neither can be a static import.
|
|
1038
960
|
*/
|
|
1039
|
-
|
|
1040
|
-
const module =
|
|
961
|
+
const loadWalkerModule = (specifier, fileName, cause) => Effect.gen(function* () {
|
|
962
|
+
const module = yield* Effect.promise(() => import(specifier));
|
|
1041
963
|
const walk = Match.value(module).pipe(Match.when(isRecordWithWalk, (record) => record.walk), Match.orElse(() => void 0));
|
|
1042
|
-
if (walk === void 0)
|
|
964
|
+
if (walk === void 0) return yield* SvelteWalkerNotFound.make({
|
|
1043
965
|
fileName,
|
|
1044
966
|
cause
|
|
1045
967
|
});
|
|
1046
968
|
return walk;
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const { parse: svelteParse, preprocess, VERSION } =
|
|
1050
|
-
if (!isAtLeast(VERSION, MINIMUM_SVELTE_VERSION))
|
|
969
|
+
});
|
|
970
|
+
const parseSvelte = (text, fileName, context) => Effect.gen(function* () {
|
|
971
|
+
const { parse: svelteParse, preprocess, VERSION } = yield* Effect.promise(() => import("svelte/compiler"));
|
|
972
|
+
if (!isAtLeast(VERSION, MINIMUM_SVELTE_VERSION)) return yield* SvelteVersionNotSupported.make({
|
|
1051
973
|
version: VERSION,
|
|
1052
974
|
fileName,
|
|
1053
975
|
cause: `Expected >=3.30`
|
|
1054
976
|
});
|
|
1055
|
-
const walk =
|
|
977
|
+
const walk = yield* loadWalker(VERSION, fileName);
|
|
1056
978
|
const lineStarts = computeLineStarts(text);
|
|
1057
|
-
const { replacedCode, scriptMap } =
|
|
979
|
+
const { replacedCode, scriptMap } = yield* replaceScripts(text, preprocess);
|
|
1058
980
|
const svelteAst = svelteParse(replacedCode, { filename: fileName });
|
|
1059
981
|
const { remappedModuleScriptRange, remappedScriptRanges } = remapScriptLocations(replacedCode, scriptMap, getModuleScriptRange(svelteAst), getTemplateScriptRanges(svelteAst, walk));
|
|
1060
|
-
const [moduleScript, ...additionalScripts] = await Promise.all([parseTemplateScriptIfDefined(remappedModuleScriptRange), ...remappedScriptRanges.map(parseTemplateScript)]);
|
|
1061
982
|
return {
|
|
1062
983
|
originFileName: fileName,
|
|
1063
984
|
rawContent: text,
|
|
1064
985
|
format: "svelte",
|
|
1065
|
-
root: svelteRoot(
|
|
986
|
+
root: svelteRoot(yield* parseTemplateScriptIfDefined(remappedModuleScriptRange, context, text, fileName, lineStarts), yield* Effect.forEach(remappedScriptRanges, (range) => parseTemplateScript(range, context, text, fileName, lineStarts)))
|
|
1066
987
|
};
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
const map = /* @__PURE__ */ new Map();
|
|
1073
|
-
let scriptIndex = 0;
|
|
988
|
+
});
|
|
989
|
+
const replaceScripts = (code, preprocess) => {
|
|
990
|
+
const map = /* @__PURE__ */ new Map();
|
|
991
|
+
let scriptIndex = 0;
|
|
992
|
+
return Effect.gen(function* () {
|
|
1074
993
|
return {
|
|
1075
|
-
replacedCode: (
|
|
994
|
+
replacedCode: (yield* Effect.promise(() => preprocess(code, { script(script) {
|
|
1076
995
|
const scriptName = `script${scriptIndex++}`;
|
|
1077
996
|
map.set(scriptName, script);
|
|
1078
997
|
return { code: scriptName };
|
|
1079
|
-
} })).code,
|
|
998
|
+
} }))).code,
|
|
1080
999
|
scriptMap: map
|
|
1081
1000
|
};
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1001
|
+
});
|
|
1002
|
+
};
|
|
1003
|
+
const parseTemplateScriptIfDefined = (range, context, text, fileName, lineStarts) => Effect.gen(function* () {
|
|
1004
|
+
if (range === void 0) return;
|
|
1005
|
+
return yield* parseTemplateScript(range, context, text, fileName, lineStarts);
|
|
1006
|
+
});
|
|
1007
|
+
const parseTemplateScript = ({ start, end, isExpression, format }, context, text, fileName, lineStarts) => Effect.map(context.parse(text.slice(start, end), fileName, format), (parsed) => ({
|
|
1008
|
+
ast: {
|
|
1009
|
+
...parsed,
|
|
1010
|
+
offset: positionFromOffset(lineStarts, start)
|
|
1011
|
+
},
|
|
1012
|
+
range: {
|
|
1013
|
+
start,
|
|
1014
|
+
end
|
|
1015
|
+
},
|
|
1016
|
+
isExpression
|
|
1017
|
+
}));
|
|
1101
1018
|
function svelteRoot(moduleScript, additionalScripts) {
|
|
1102
1019
|
return Match.value(moduleScript).pipe(Match.when(void 0, () => ({ additionalScripts })), Match.orElse((script) => ({
|
|
1103
1020
|
moduleScript: script,
|
|
@@ -1723,15 +1640,15 @@ var PrintState = class {
|
|
|
1723
1640
|
case "accessor":
|
|
1724
1641
|
this.out += `${fields.kind} `;
|
|
1725
1642
|
this.out += this.propertyKeyText(fields.key, fields.computed === true, PREC.Assignment);
|
|
1726
|
-
this.
|
|
1643
|
+
this.printFunctionTail(fields.value);
|
|
1727
1644
|
break;
|
|
1728
1645
|
case "method":
|
|
1729
1646
|
this.out += `${flagText(fields.async, "async ")}${flagText(fields.generator, "*")}`;
|
|
1730
1647
|
this.out += this.propertyKeyText(fields.key, fields.computed === true, PREC.Assignment);
|
|
1731
|
-
this.
|
|
1648
|
+
this.printFunctionTail(fields.value);
|
|
1732
1649
|
break;
|
|
1733
1650
|
case "shorthand":
|
|
1734
|
-
this.out += identifierName
|
|
1651
|
+
this.out += identifierName(fields.key);
|
|
1735
1652
|
break;
|
|
1736
1653
|
case "shorthandDefault":
|
|
1737
1654
|
this.printShorthandDefaultProperty(fields);
|
|
@@ -1744,7 +1661,7 @@ var PrintState = class {
|
|
|
1744
1661
|
}
|
|
1745
1662
|
printShorthandDefaultProperty(fields) {
|
|
1746
1663
|
const right = this.assignmentNodeText(fields.value.right);
|
|
1747
|
-
this.out += `${identifierName
|
|
1664
|
+
this.out += `${identifierName(fields.key)} = ${right}`;
|
|
1748
1665
|
}
|
|
1749
1666
|
propertyKeyText(key, computed, computedPrec) {
|
|
1750
1667
|
switch (computed) {
|
|
@@ -1763,10 +1680,6 @@ var PrintState = class {
|
|
|
1763
1680
|
printPropertyKeyForClass(key, computed) {
|
|
1764
1681
|
this.out += this.propertyKeyText(key, computed, PREC.Sequence);
|
|
1765
1682
|
}
|
|
1766
|
-
printFunctionValue(fn) {
|
|
1767
|
-
if (!fn) return;
|
|
1768
|
-
this.printFunctionTail(fn);
|
|
1769
|
-
}
|
|
1770
1683
|
printFunctionTail(fn) {
|
|
1771
1684
|
this.out += this.typeParametersText(fn.typeParameters);
|
|
1772
1685
|
this.out += `(${this.paramsText(fn.params)})`;
|
|
@@ -2222,13 +2135,16 @@ var PrintState = class {
|
|
|
2222
2135
|
}
|
|
2223
2136
|
}
|
|
2224
2137
|
printExpressionStatement(node) {
|
|
2225
|
-
if (node.directive) {
|
|
2138
|
+
if (this.isDirective(node.directive)) {
|
|
2226
2139
|
this.out += JSON.stringify(node.directive) + ";";
|
|
2227
2140
|
return;
|
|
2228
2141
|
}
|
|
2229
2142
|
this.printNode(node.expression, PREC.Sequence);
|
|
2230
2143
|
this.out += ";";
|
|
2231
2144
|
}
|
|
2145
|
+
isDirective(directive) {
|
|
2146
|
+
return directive != null && directive !== "";
|
|
2147
|
+
}
|
|
2232
2148
|
printIfStatement(node) {
|
|
2233
2149
|
this.out += "if (";
|
|
2234
2150
|
this.printNode(node.test, PREC.Sequence);
|
|
@@ -3092,12 +3008,12 @@ function propertyForm(fields) {
|
|
|
3092
3008
|
}
|
|
3093
3009
|
}
|
|
3094
3010
|
function isShorthandMatch(fields) {
|
|
3095
|
-
return fields.shorthand === true && namesMatch(identifierName
|
|
3011
|
+
return fields.shorthand === true && namesMatch(identifierName(fields.key), identifierName(fields.value));
|
|
3096
3012
|
}
|
|
3097
3013
|
function isShorthandDefaultMatch(fields) {
|
|
3098
|
-
return fields.shorthand === true && namesMatch(identifierName
|
|
3014
|
+
return fields.shorthand === true && namesMatch(identifierName(fields.key), defaultTargetName(fields.value));
|
|
3099
3015
|
}
|
|
3100
|
-
function identifierName
|
|
3016
|
+
function identifierName(node) {
|
|
3101
3017
|
switch (nodeKind(node)) {
|
|
3102
3018
|
case "Identifier": return node.name;
|
|
3103
3019
|
default: return;
|
|
@@ -3105,7 +3021,7 @@ function identifierName$1(node) {
|
|
|
3105
3021
|
}
|
|
3106
3022
|
function defaultTargetName(node) {
|
|
3107
3023
|
switch (nodeKind(node)) {
|
|
3108
|
-
case "AssignmentPattern": return identifierName
|
|
3024
|
+
case "AssignmentPattern": return identifierName(node.left);
|
|
3109
3025
|
default: return;
|
|
3110
3026
|
}
|
|
3111
3027
|
}
|
|
@@ -3374,12 +3290,8 @@ const hashbangOf = (root) => {
|
|
|
3374
3290
|
if (!isHashbang(hashbang)) return null;
|
|
3375
3291
|
return hashbang;
|
|
3376
3292
|
};
|
|
3377
|
-
const jsPrint = (file) => {
|
|
3378
|
-
|
|
3379
|
-
};
|
|
3380
|
-
const tsPrint = (file) => {
|
|
3381
|
-
return printProgram(file.root, { hashbang: hashbangOf(file.root) });
|
|
3382
|
-
};
|
|
3293
|
+
const jsPrint = (file) => printProgram(file.root, { hashbang: hashbangOf(file.root) });
|
|
3294
|
+
const tsPrint = (file) => printProgram(file.root, { hashbang: hashbangOf(file.root) });
|
|
3383
3295
|
function getScriptStart$1(script) {
|
|
3384
3296
|
const span = spanOf(script.root);
|
|
3385
3297
|
if (span === void 0) throw new Error("Script AST root without start");
|
|
@@ -3437,7 +3349,7 @@ function appendStatement(state, script, rawContent, context) {
|
|
|
3437
3349
|
/**
|
|
3438
3350
|
* Node identity: same kind, same span. oxc nodes always carry a range
|
|
3439
3351
|
* (parsed with `range: true`), which is a stronger identity than the old
|
|
3440
|
-
*
|
|
3352
|
+
* line/column loc.
|
|
3441
3353
|
*/
|
|
3442
3354
|
function eqNode(a, b) {
|
|
3443
3355
|
const identity = nodeIdentity(a);
|
|
@@ -3738,7 +3650,13 @@ const arithmeticOperatorReplacements = Object.freeze({
|
|
|
3738
3650
|
const ARITHMETIC_OPERATOR_KEYS = Object.keys(arithmeticOperatorReplacements);
|
|
3739
3651
|
const arithmeticOperatorMutator = (node) => Match.value(node).pipe(Match.when(isArithmeticBinary, (binary) => [withOperator(binary, arithmeticOperatorReplacements[binary.operator])]), Match.orElse(() => NO_MUTANTS));
|
|
3740
3652
|
function isArithmeticBinary(node) {
|
|
3741
|
-
return node
|
|
3653
|
+
return isBinaryExpression(node) && isSupportedArithmeticOperator(node.operator, node);
|
|
3654
|
+
}
|
|
3655
|
+
function isBinaryExpression(node) {
|
|
3656
|
+
return node.type === "BinaryExpression" && !isPrivateInExpression(node);
|
|
3657
|
+
}
|
|
3658
|
+
function isPrivateInExpression(node) {
|
|
3659
|
+
return node.left.type === "PrivateIdentifier";
|
|
3742
3660
|
}
|
|
3743
3661
|
function isSupportedArithmeticOperator(operator, node) {
|
|
3744
3662
|
return ARITHMETIC_OPERATOR_KEYS.includes(operator) && !isStringConcatenation(node);
|
|
@@ -4085,7 +4003,7 @@ function methodExpressionReplacement(mutation) {
|
|
|
4085
4003
|
return Match.value(mutation.newName).pipe(Match.when(null, () => callExpression(cloneNode(mutation.callee.object), [], mutation.callee.optional === true)), Match.orElse((newName) => renamedMethodCall(mutation, newName)));
|
|
4086
4004
|
}
|
|
4087
4005
|
function renamedMethodCall(mutation, newName) {
|
|
4088
|
-
return callExpression(memberExpression(cloneNode(mutation.callee.object), identifier(newName),
|
|
4006
|
+
return callExpression(memberExpression(cloneNode(mutation.callee.object), identifier(newName), mutation.callee.optional === true), spreadFreeArguments(mutation.call.arguments), mutation.call.optional === true);
|
|
4089
4007
|
}
|
|
4090
4008
|
function spreadFreeArguments(args) {
|
|
4091
4009
|
return args.filter(isNotSpreadElement).map((argument) => cloneNode(argument));
|
|
@@ -4275,13 +4193,13 @@ const allMutators = Object.freeze({
|
|
|
4275
4193
|
UnaryOperator: unaryOperatorMutator,
|
|
4276
4194
|
UpdateOperator: updateOperatorMutator
|
|
4277
4195
|
});
|
|
4278
|
-
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/PlacementFailed")("PlacementFailed", {
|
|
4196
|
+
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Transformer.schema/PlacementFailed")("PlacementFailed", {
|
|
4279
4197
|
fileName: S.String,
|
|
4280
4198
|
placerName: S.String,
|
|
4281
4199
|
mutantIds: S.Array(S.String),
|
|
4282
4200
|
cause: S.Defect()
|
|
4283
4201
|
});
|
|
4284
|
-
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/TransformFailed")("TransformFailed", {
|
|
4202
|
+
S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Transformer.schema/TransformFailed")("TransformFailed", {
|
|
4285
4203
|
fileName: S.String,
|
|
4286
4204
|
cause: S.Defect()
|
|
4287
4205
|
});
|
|
@@ -4390,32 +4308,10 @@ function mutatorWarning(directive, mutatorName, originFileName) {
|
|
|
4390
4308
|
onSome: (scope) => `${directive.type} ${scope}`
|
|
4391
4309
|
})}' directive. Mutator with name '${mutatorName}' not found. Directive found at: ${originFileName}:${loc.start.line}:${loc.start.column}.`;
|
|
4392
4310
|
}
|
|
4393
|
-
function
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
return {
|
|
4398
|
-
node: path.node,
|
|
4399
|
-
parentPath: parentResult,
|
|
4400
|
-
isObjectExpression() {
|
|
4401
|
-
return nodeType(node) === "ObjectExpression";
|
|
4402
|
-
},
|
|
4403
|
-
isCallExpression() {
|
|
4404
|
-
return nodeType(node) === "CallExpression";
|
|
4405
|
-
},
|
|
4406
|
-
isClassProperty() {
|
|
4407
|
-
return nodeType(node) === "PropertyDefinition";
|
|
4408
|
-
},
|
|
4409
|
-
isClassPrivateProperty() {
|
|
4410
|
-
return nodeType(node) === "PropertyDefinition" && nodeType(propertyKeyOf(node)) === "PrivateIdentifier";
|
|
4411
|
-
},
|
|
4412
|
-
isClassAccessorProperty() {
|
|
4413
|
-
return nodeType(node) === "AccessorProperty";
|
|
4414
|
-
}
|
|
4415
|
-
};
|
|
4416
|
-
}
|
|
4417
|
-
function propertyKeyOf(node) {
|
|
4418
|
-
return Option.getOrUndefined(Option.map(Option.filter(Option.some(node), Predicate.hasProperty("key")), (holder) => holder["key"]));
|
|
4311
|
+
function ancestorsOf(path) {
|
|
4312
|
+
const ancestors = [];
|
|
4313
|
+
for (let current = path.parentPath; current !== null; current = current.parentPath) ancestors.push(current.node);
|
|
4314
|
+
return ancestors;
|
|
4419
4315
|
}
|
|
4420
4316
|
function isTypeNode(path) {
|
|
4421
4317
|
return [
|
|
@@ -4475,27 +4371,35 @@ function nodeOfKind(mutant, node, isKind, kind) {
|
|
|
4475
4371
|
if (!isKind(node)) throw new Error(`Cannot place mutant ${mutant.id}: expected ${kind}, got ${node.type}`);
|
|
4476
4372
|
return node;
|
|
4477
4373
|
}
|
|
4478
|
-
function throwPlacementError(error, nodePath, placer, mutants, fileName, lineTable) {
|
|
4479
|
-
const message = `${placer.name} could not place mutants with type(s): "${
|
|
4480
|
-
const errorMessage = `${placementLocation(nodePath.node, fileName, lineTable)} ${message}. Either remove this file from the list of files to be mutated, or exclude the mutator (using
|
|
4374
|
+
function throwPlacementError(error, nodePath, placer, mutants, fileName, lineTable, basePath) {
|
|
4375
|
+
const message = `${placer.name} could not place mutants with type(s): "${placementListFormat.format(mutants.map((mutant) => mutant.mutatorName))}"`;
|
|
4376
|
+
const errorMessage = `${placementLocation(nodePath.node, fileName, lineTable, basePath)} ${message}. Either remove this file from the list of files to be mutated, or exclude the mutator (using \`mutator.excludedMutations\`). Original error: ${error.stack}`;
|
|
4481
4377
|
throw new Error(errorMessage);
|
|
4482
4378
|
}
|
|
4483
|
-
function placementLocation(node, fileName, lineTable) {
|
|
4484
|
-
const relativeFile =
|
|
4379
|
+
function placementLocation(node, fileName, lineTable, basePath) {
|
|
4380
|
+
const relativeFile = basePath === void 0 ? fileName : relativeTo(basePath, fileName);
|
|
4485
4381
|
const position = Option.map(Option.fromNullishOr(spanOf(node)), (span) => positionFromLineTable(span.start, lineTable));
|
|
4486
4382
|
return Option.match(position, {
|
|
4487
4383
|
onNone: () => `${relativeFile}:undefined:undefined`,
|
|
4488
4384
|
onSome: (at) => `${relativeFile}:${at.line}:${at.column}`
|
|
4489
4385
|
});
|
|
4490
4386
|
}
|
|
4387
|
+
const placementListFormat = new Intl.ListFormat("en");
|
|
4388
|
+
const normalizeSeparators = (value) => value.replace(/\\/g, "/");
|
|
4389
|
+
const withTrailingSlash = (basePath) => {
|
|
4390
|
+
const normalized = normalizeSeparators(basePath);
|
|
4391
|
+
return normalized.endsWith("/") ? normalized : `${normalized}/`;
|
|
4392
|
+
};
|
|
4393
|
+
const relativeTo = (basePath, fileName) => {
|
|
4394
|
+
const prefix = withTrailingSlash(basePath);
|
|
4395
|
+
const normalizedFile = normalizeSeparators(fileName);
|
|
4396
|
+
return normalizedFile.startsWith(prefix) ? normalizedFile.slice(prefix.length) : fileName;
|
|
4397
|
+
};
|
|
4491
4398
|
function classOrFunctionExpressionNamedIfNeeded(path) {
|
|
4492
4399
|
return Match.value(path.node).pipe(Match.when(isAnonymousFunctionOrClass, (node) => nameFromParent(path, node)), Match.orElse(() => void 0));
|
|
4493
4400
|
}
|
|
4494
4401
|
function nameFromParent(path, node) {
|
|
4495
|
-
return Match.value(path.parentPath?.node).pipe(Match.when({
|
|
4496
|
-
type: "VariableDeclarator",
|
|
4497
|
-
id: { type: "Identifier" }
|
|
4498
|
-
}, (declarator) => adoptIdentifier(node, declarator.id)), Match.when({
|
|
4402
|
+
return Match.value(path.parentPath?.node).pipe(Match.when(isVariableDeclarator, (declarator) => adoptDeclaredName(node, declarator)), Match.when({
|
|
4499
4403
|
type: "Property",
|
|
4500
4404
|
key: { type: "Identifier" }
|
|
4501
4405
|
}, () => namedPropertyValue(path, node)), Match.orElse(() => void 0));
|
|
@@ -4528,10 +4432,22 @@ function namedArrowExpression(node, identifier) {
|
|
|
4528
4432
|
return callExpression(arrowFunctionExpression([], blockStatement([variableDeclaration("const", [variableDeclarator(identifier, node)]), returnStatement(identifier)])), []);
|
|
4529
4433
|
}
|
|
4530
4434
|
function declaratorIdentifier(parentPath) {
|
|
4531
|
-
return Option.flatMap(Option.fromNullishOr(parentPath), (parent) => Match.value(parent.node).pipe(Match.when(
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4435
|
+
return Option.flatMap(Option.fromNullishOr(parentPath), (parent) => Match.value(parent.node).pipe(Match.when(isVariableDeclarator, (declarator) => declaredName(declarator)), Match.orElse(() => Option.none())));
|
|
4436
|
+
}
|
|
4437
|
+
function isVariableDeclarator(node) {
|
|
4438
|
+
return nodeType(node) === "VariableDeclarator";
|
|
4439
|
+
}
|
|
4440
|
+
function adoptDeclaredName(node, declarator) {
|
|
4441
|
+
return Option.match(declaredName(declarator), {
|
|
4442
|
+
onNone: () => void 0,
|
|
4443
|
+
onSome: (identifier) => adoptIdentifier(node, identifier)
|
|
4444
|
+
});
|
|
4445
|
+
}
|
|
4446
|
+
function declaredName(declarator) {
|
|
4447
|
+
return Match.value(declarator.id).pipe(Match.when(isIdentifierReference, (identifier) => Option.some(identifier)), Match.orElse(() => Option.none()));
|
|
4448
|
+
}
|
|
4449
|
+
function isIdentifierReference(node) {
|
|
4450
|
+
return nodeType(node) === "Identifier";
|
|
4535
4451
|
}
|
|
4536
4452
|
function nameIfAnonymous(path) {
|
|
4537
4453
|
return classOrFunctionExpressionNamedIfNeeded(path) ?? arrowNameOrNode(path);
|
|
@@ -4666,139 +4582,9 @@ const allMutantPlacers = Object.freeze([
|
|
|
4666
4582
|
}
|
|
4667
4583
|
}
|
|
4668
4584
|
]);
|
|
4669
|
-
|
|
4670
|
-
"input",
|
|
4671
|
-
"model",
|
|
4672
|
-
"output"
|
|
4673
|
-
]);
|
|
4674
|
-
const ANGULAR_SIGNAL_QUERY_FUNCTIONS = Object.freeze([
|
|
4675
|
-
"contentChild",
|
|
4676
|
-
"contentChildren",
|
|
4677
|
-
"viewChild",
|
|
4678
|
-
"viewChildren"
|
|
4679
|
-
]);
|
|
4680
|
-
const INPUT_MODEL_OUTPUT_CONFIG_MSG = "Angular signal based input, model and output functions configuration object cannot be mutated as that causes issues with the Angular compiler.";
|
|
4681
|
-
const SIGNAL_QUERY_OPTIONS_MSG = "Angular signal query options object cannot be mutated as that causes issues with the Angular compiler.";
|
|
4682
|
-
function shouldIgnore(path) {
|
|
4683
|
-
return Option.orElse(reasonAt(path), () => ancestorReason(path));
|
|
4684
|
-
}
|
|
4685
|
-
function reasonAt(path) {
|
|
4686
|
-
return Match.value(path).pipe(Match.when(isInputModelOrOutputConfigurationObject, () => Option.some(INPUT_MODEL_OUTPUT_CONFIG_MSG)), Match.when(isSignalQueryOptionsObject, () => Option.some(SIGNAL_QUERY_OPTIONS_MSG)), Match.orElse(() => Option.none()));
|
|
4687
|
-
}
|
|
4688
|
-
function ancestorReason(path) {
|
|
4689
|
-
return Option.flatMap(Option.fromNullishOr(path.parentPath), shouldIgnore);
|
|
4690
|
-
}
|
|
4691
|
-
const angularIgnorer = { shouldIgnore };
|
|
4692
|
-
function isClassFieldLike(path) {
|
|
4693
|
-
return CLASS_FIELD_KINDS.includes(nodeType(path.node) ?? "");
|
|
4694
|
-
}
|
|
4695
|
-
const CLASS_FIELD_KINDS = Object.freeze(["PropertyDefinition", "AccessorProperty"]);
|
|
4696
|
-
function isInputModelOrOutputConfigurationObject(path) {
|
|
4697
|
-
return Option.match(signalCallSiteOf(path, isPropertyDefinitionField), {
|
|
4698
|
-
onNone: () => false,
|
|
4699
|
-
onSome: (site) => isArgumentAt(site, signalIoArgumentIndex(site.callee))
|
|
4700
|
-
});
|
|
4701
|
-
}
|
|
4702
|
-
function isSignalQueryOptionsObject(path) {
|
|
4703
|
-
return Option.match(signalCallSiteOf(path, isClassFieldLike), {
|
|
4704
|
-
onNone: () => false,
|
|
4705
|
-
onSome: (site) => isSignalQueryCall(site.callee) && isArgumentAt(site, Option.some(1))
|
|
4706
|
-
});
|
|
4707
|
-
}
|
|
4708
|
-
function isPropertyDefinitionField(path) {
|
|
4709
|
-
return nodeType(path.node) === "PropertyDefinition";
|
|
4710
|
-
}
|
|
4711
|
-
/** The call that takes the object expression as an argument, when a field-like member owns it. */
|
|
4712
|
-
function signalCallSiteOf(path, ownsCallSite) {
|
|
4713
|
-
return Option.flatMap(ownedCallPath(path, ownsCallSite), (callPath) => Option.map(callArgumentsOf(callPath), (call) => ({
|
|
4714
|
-
...call,
|
|
4715
|
-
objectExpression: path
|
|
4716
|
-
})));
|
|
4717
|
-
}
|
|
4718
|
-
function ownedCallPath(path, ownsCallSite) {
|
|
4719
|
-
const argument = Option.filter(Option.some(path), (candidate) => isOwnedCallArgument(candidate, ownsCallSite));
|
|
4720
|
-
return Option.flatMap(argument, (candidate) => Option.fromNullishOr(candidate.parentPath));
|
|
4721
|
-
}
|
|
4722
|
-
function isOwnedCallArgument(path, ownsCallSite) {
|
|
4723
|
-
return isObjectArgumentOfCall(path) && ownsCallSiteOf(path, ownsCallSite);
|
|
4724
|
-
}
|
|
4725
|
-
function isObjectArgumentOfCall(path) {
|
|
4726
|
-
return nodeType(path.node) === "ObjectExpression" && parentIsCallExpression(path);
|
|
4727
|
-
}
|
|
4728
|
-
function parentIsCallExpression(path) {
|
|
4729
|
-
return nodeType(path.parentPath?.node) === "CallExpression";
|
|
4730
|
-
}
|
|
4731
|
-
function ownsCallSiteOf(path, ownsCallSite) {
|
|
4732
|
-
return Option.exists(Option.fromNullishOr(path.parentPath?.parentPath), ownsCallSite);
|
|
4733
|
-
}
|
|
4734
|
-
function callArgumentsOf(callPath) {
|
|
4735
|
-
return Option.flatMap(Option.filter(Option.some(callPath.node), hasCallShape), (call) => Option.map(argumentArrayOf(call["arguments"]), (args) => ({
|
|
4736
|
-
callee: call["callee"],
|
|
4737
|
-
args
|
|
4738
|
-
})));
|
|
4739
|
-
}
|
|
4740
|
-
function hasCallShape(callNode) {
|
|
4741
|
-
return Predicate.hasProperty(callNode, "callee") && Predicate.hasProperty(callNode, "arguments");
|
|
4742
|
-
}
|
|
4743
|
-
function argumentArrayOf(argument) {
|
|
4744
|
-
return Option.filter(Option.some(argument), isUnknownArray);
|
|
4745
|
-
}
|
|
4746
|
-
function isUnknownArray(value) {
|
|
4585
|
+
function isCommentArray(value) {
|
|
4747
4586
|
return Array.isArray(value);
|
|
4748
4587
|
}
|
|
4749
|
-
function signalIoArgumentIndex(callee) {
|
|
4750
|
-
return Match.value(callee).pipe(Match.when(isRequiredSignalIoCall, () => Option.some(0)), Match.when(isOutputCall, () => Option.some(0)), Match.when(isSignalIoCall, () => Option.some(1)), Match.orElse(() => Option.none()));
|
|
4751
|
-
}
|
|
4752
|
-
function isRequiredSignalIoCall(callee) {
|
|
4753
|
-
return isMemberExpressionWithIdentifier(callee, ANGULAR_SIGNAL_IO_FUNCTIONS, "required");
|
|
4754
|
-
}
|
|
4755
|
-
function isOutputCall(callee) {
|
|
4756
|
-
return isIdentifierWithName(callee, "output");
|
|
4757
|
-
}
|
|
4758
|
-
function isSignalIoCall(callee) {
|
|
4759
|
-
return isIdentifierIn(callee, ANGULAR_SIGNAL_IO_FUNCTIONS);
|
|
4760
|
-
}
|
|
4761
|
-
function isSignalQueryCall(callee) {
|
|
4762
|
-
return isIdentifierIn(callee, ANGULAR_SIGNAL_QUERY_FUNCTIONS) || isMemberExpressionWithIdentifier(callee, ANGULAR_SIGNAL_QUERY_FUNCTIONS, "required");
|
|
4763
|
-
}
|
|
4764
|
-
function isArgumentAt(site, index) {
|
|
4765
|
-
return Option.exists(index, (position) => site.args.length > position && site.args[position] === site.objectExpression.node);
|
|
4766
|
-
}
|
|
4767
|
-
function isIdentifierWithName(node, name) {
|
|
4768
|
-
return Option.contains(identifierName(node), name);
|
|
4769
|
-
}
|
|
4770
|
-
function isIdentifierIn(node, names) {
|
|
4771
|
-
return Option.exists(identifierName(node), (name) => names.includes(name));
|
|
4772
|
-
}
|
|
4773
|
-
function identifierName(node) {
|
|
4774
|
-
return Option.map(identifierNode(node), (identifier) => identifier.name);
|
|
4775
|
-
}
|
|
4776
|
-
function identifierNode(node) {
|
|
4777
|
-
return Option.filter(Option.some(node), isNamedIdentifier);
|
|
4778
|
-
}
|
|
4779
|
-
function isNamedIdentifier(node) {
|
|
4780
|
-
return hasNodeType(node, "Identifier") && isStringProperty(node, "name");
|
|
4781
|
-
}
|
|
4782
|
-
function hasNodeType(node, type) {
|
|
4783
|
-
return Predicate.hasProperty(node, "type") && node["type"] === type;
|
|
4784
|
-
}
|
|
4785
|
-
function isStringProperty(node, property) {
|
|
4786
|
-
return Predicate.hasProperty(node, property) && typeof node[property] === "string";
|
|
4787
|
-
}
|
|
4788
|
-
function isMemberExpressionWithIdentifier(node, objectNames, propertyName) {
|
|
4789
|
-
return Option.exists(memberPartsOf(node), (member) => isIdentifierIn(member.object, objectNames) && isIdentifierWithName(member.property, propertyName));
|
|
4790
|
-
}
|
|
4791
|
-
function memberPartsOf(node) {
|
|
4792
|
-
return Option.filter(Option.some(node), isMemberExpressionRecord);
|
|
4793
|
-
}
|
|
4794
|
-
function isMemberExpressionRecord(node) {
|
|
4795
|
-
return hasNodeType(node, "MemberExpression") && isPropertyBearing(node);
|
|
4796
|
-
}
|
|
4797
|
-
function isPropertyBearing(node) {
|
|
4798
|
-
return Predicate.hasProperty(node, "object") && Predicate.hasProperty(node, "property");
|
|
4799
|
-
}
|
|
4800
|
-
const strykerPlugins = [];
|
|
4801
|
-
const frameworkPluginsFileUrl = import.meta.url;
|
|
4802
4588
|
const INSTRUMENTATION_HEADER_SOURCE = `// @ts-nocheck
|
|
4803
4589
|
var ${STRYKER_NAMESPACE_HELPER} = function(){
|
|
4804
4590
|
var g = typeof globalThis === 'object' && globalThis && globalThis.Math === Math && globalThis || new Function("return this")();
|
|
@@ -4845,32 +4631,29 @@ var ${IS_MUTANT_ACTIVE_HELPER} = function(id) {
|
|
|
4845
4631
|
return isActive(id);
|
|
4846
4632
|
}`;
|
|
4847
4633
|
let instrumentationHeaderValue;
|
|
4848
|
-
const instrumentationHeader =
|
|
4634
|
+
const instrumentationHeader = Effect.gen(function* () {
|
|
4849
4635
|
if (instrumentationHeaderValue === void 0) {
|
|
4850
|
-
instrumentationHeaderValue = (
|
|
4636
|
+
instrumentationHeaderValue = (yield* parseWithOxc(INSTRUMENTATION_HEADER_SOURCE, "instrumenter-header.js", "js")).root.body;
|
|
4851
4637
|
deepFreeze(instrumentationHeaderValue);
|
|
4852
4638
|
}
|
|
4853
4639
|
return instrumentationHeaderValue;
|
|
4854
|
-
};
|
|
4855
|
-
|
|
4856
|
-
if (shouldPlaceHeader(mutantCollector, originFileName, options))
|
|
4857
|
-
}
|
|
4640
|
+
});
|
|
4641
|
+
const placeHeaderIfNeeded = (mutantCollector, originFileName, options, root) => Effect.gen(function* () {
|
|
4642
|
+
if (shouldPlaceHeader(mutantCollector, originFileName, options)) yield* placeHeader(root);
|
|
4643
|
+
});
|
|
4644
|
+
const placeHeader = (root) => Effect.map(headerFor(root), (header) => {
|
|
4645
|
+
root.body.unshift(...header);
|
|
4646
|
+
});
|
|
4858
4647
|
function shouldPlaceHeader(mutantCollector, originFileName, options) {
|
|
4859
4648
|
return hasPlacedMutants(mutantCollector, originFileName) && options.noHeader !== true;
|
|
4860
4649
|
}
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
const header = await instrumentationHeader();
|
|
4866
|
-
return Option.match(leadingCommentsOf(root), {
|
|
4867
|
-
onNone: () => header,
|
|
4868
|
-
onSome: (leadingComments) => [commentedHeader(leadingComments, header), ...header.slice(1)]
|
|
4869
|
-
});
|
|
4870
|
-
}
|
|
4650
|
+
const headerFor = (root) => Effect.map(instrumentationHeader, (header) => Option.match(leadingCommentsOf(root), {
|
|
4651
|
+
onNone: () => header,
|
|
4652
|
+
onSome: (leadingComments) => [commentedHeader(leadingComments, header), ...header.slice(1)]
|
|
4653
|
+
}));
|
|
4871
4654
|
function leadingCommentsOf(root) {
|
|
4872
4655
|
const firstStatement = root.body[0];
|
|
4873
|
-
return Option.filter(Option.fromNullishOr(firstStatement?.leadingComments),
|
|
4656
|
+
return Option.filter(Option.fromNullishOr(firstStatement?.leadingComments), isCommentArray);
|
|
4874
4657
|
}
|
|
4875
4658
|
function commentedHeader(leadingComments, header) {
|
|
4876
4659
|
const cloned = cloneNode(Option.getOrThrowWith(Option.fromNullishOr(header[0]), () => /* @__PURE__ */ new Error("Instrumentation header is empty")));
|
|
@@ -4913,7 +4696,7 @@ function isMap(value) {
|
|
|
4913
4696
|
function isSet(value) {
|
|
4914
4697
|
return value instanceof Set;
|
|
4915
4698
|
}
|
|
4916
|
-
|
|
4699
|
+
const transform = (ast, mutantCollector, transformerContext) => {
|
|
4917
4700
|
const context = {
|
|
4918
4701
|
...transformerContext,
|
|
4919
4702
|
transform
|
|
@@ -4925,32 +4708,27 @@ async function transform(ast, mutantCollector, transformerContext) {
|
|
|
4925
4708
|
case "tsx": return transformScript(ast, mutantCollector, context);
|
|
4926
4709
|
case "svelte": return transformSvelte(ast, mutantCollector, context);
|
|
4927
4710
|
}
|
|
4928
|
-
}
|
|
4929
|
-
const transformHtml = async ({ root }, mutantCollector, context) => {
|
|
4930
|
-
const warnings = [];
|
|
4931
|
-
for (const script of root.scripts) warnings.push(...await context.transform(script, mutantCollector, context));
|
|
4932
|
-
return warnings;
|
|
4933
4711
|
};
|
|
4712
|
+
const transformHtml = ({ root }, mutantCollector, context) => Effect.map(Effect.forEach(root.scripts, (script) => context.transform(script, mutantCollector, context)), (perScript) => perScript.flat());
|
|
4934
4713
|
const moduleScript = `<script context="module">
|
|
4935
4714
|
\n<\/script>\n`;
|
|
4936
|
-
const transformSvelte =
|
|
4937
|
-
const warnings = [];
|
|
4715
|
+
const transformSvelte = (svelte, mutantCollector, context) => Effect.gen(function* () {
|
|
4938
4716
|
const { root } = svelte;
|
|
4939
4717
|
const scripts = [root.moduleScript, ...root.additionalScripts].filter(Predicate.isNotNullish);
|
|
4940
|
-
|
|
4718
|
+
const warnings = (yield* Effect.forEach(scripts, (script) => context.transform(script.ast, mutantCollector, {
|
|
4941
4719
|
...context,
|
|
4942
4720
|
options: {
|
|
4943
4721
|
...context.options,
|
|
4944
4722
|
noHeader: true
|
|
4945
4723
|
}
|
|
4946
|
-
}));
|
|
4947
|
-
|
|
4724
|
+
}))).flat();
|
|
4725
|
+
yield* placeModuleHeaderIfNeeded(svelte, mutantCollector);
|
|
4948
4726
|
return warnings;
|
|
4949
|
-
};
|
|
4950
|
-
|
|
4951
|
-
if (hasPlacedMutants(mutantCollector, svelte.originFileName))
|
|
4952
|
-
}
|
|
4953
|
-
|
|
4727
|
+
});
|
|
4728
|
+
const placeModuleHeaderIfNeeded = (svelte, mutantCollector) => Effect.gen(function* () {
|
|
4729
|
+
if (hasPlacedMutants(mutantCollector, svelte.originFileName)) yield* placeModuleHeader(svelte);
|
|
4730
|
+
});
|
|
4731
|
+
const placeModuleHeader = (svelte) => Effect.gen(function* () {
|
|
4954
4732
|
const { root, originFileName } = svelte;
|
|
4955
4733
|
if (!root.moduleScript) {
|
|
4956
4734
|
root.moduleScript = {
|
|
@@ -4973,162 +4751,161 @@ async function placeModuleHeader(svelte) {
|
|
|
4973
4751
|
script.range.end += moduleScript.length;
|
|
4974
4752
|
});
|
|
4975
4753
|
}
|
|
4976
|
-
|
|
4977
|
-
}
|
|
4754
|
+
yield* placeHeader(root.moduleScript.ast.root);
|
|
4755
|
+
});
|
|
4978
4756
|
function emptyProgram() {
|
|
4979
4757
|
return {
|
|
4980
4758
|
type: "Program",
|
|
4981
4759
|
sourceType: "module",
|
|
4982
|
-
body: []
|
|
4760
|
+
body: [],
|
|
4761
|
+
hashbang: null
|
|
4983
4762
|
};
|
|
4984
4763
|
}
|
|
4764
|
+
const emptyAppliedMutants = () => /* @__PURE__ */ new Map();
|
|
4985
4765
|
function isMutateRangeList(value) {
|
|
4986
4766
|
return Array.isArray(value);
|
|
4987
4767
|
}
|
|
4988
|
-
const transformScript =
|
|
4989
|
-
const lineTable = buildLineTable(rawContent);
|
|
4990
|
-
attachComments(root, comments, lineTable);
|
|
4768
|
+
const transformScript = ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription, basePath }, mutators, mutantPlacers) => {
|
|
4991
4769
|
const placementMap = /* @__PURE__ */ new Map();
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
4770
|
+
return Effect.gen(function* () {
|
|
4771
|
+
const lineTable = buildLineTable(rawContent);
|
|
4772
|
+
attachComments(root, comments, lineTable);
|
|
4773
|
+
let directiveRule = rootRule;
|
|
4774
|
+
const mutatorEntries = Object.entries(Option.getOrElse(Option.fromNullishOr(mutators), () => allMutators));
|
|
4775
|
+
const placers = Option.getOrElse(Option.fromNullishOr(mutantPlacers), () => allMutantPlacers);
|
|
4776
|
+
const allMutatorNames = mutatorEntries.map(([name]) => name.toLowerCase());
|
|
4777
|
+
const warnings = [];
|
|
4778
|
+
traverse(root, {
|
|
4779
|
+
enter(path) {
|
|
4780
|
+
const result = processStrykerDirectives(directiveRule, path.node, allMutatorNames, originFileName);
|
|
4781
|
+
directiveRule = result.rule;
|
|
4782
|
+
warnings.push(...result.warnings);
|
|
4783
|
+
visitNode(path);
|
|
4784
|
+
},
|
|
4785
|
+
exit(path) {
|
|
4786
|
+
const placement = placementMap.get(path.node);
|
|
4787
|
+
if (hasAppliedMutants(placement)) applyPlacement(path, placement);
|
|
4788
|
+
}
|
|
4789
|
+
});
|
|
4790
|
+
yield* placeHeaderIfNeeded(mutantCollector, originFileName, options, root);
|
|
4791
|
+
return warnings;
|
|
4792
|
+
function visitNode(path) {
|
|
4793
|
+
if (shouldSkip(path)) {
|
|
4794
|
+
path.skip();
|
|
4795
|
+
return;
|
|
4796
|
+
}
|
|
4797
|
+
addToPlacementMapIfPossible(path);
|
|
4798
|
+
placeCollectedMutantsIfMutating(path);
|
|
5007
4799
|
}
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
return;
|
|
4800
|
+
function addToPlacementMapIfPossible(path) {
|
|
4801
|
+
const placer = placers.find((candidate) => candidate.canPlace(path));
|
|
4802
|
+
if (placer !== void 0) placementMap.set(path.node, {
|
|
4803
|
+
appliedMutants: emptyAppliedMutants(),
|
|
4804
|
+
placer
|
|
4805
|
+
});
|
|
5015
4806
|
}
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
}
|
|
5019
|
-
function addToPlacementMapIfPossible(path) {
|
|
5020
|
-
const placer = placers.find((candidate) => candidate.canPlace(path));
|
|
5021
|
-
if (placer !== void 0) placementMap.set(path.node, {
|
|
5022
|
-
appliedMutants: /* @__PURE__ */ new Map(),
|
|
5023
|
-
placer
|
|
5024
|
-
});
|
|
5025
|
-
}
|
|
5026
|
-
function hasAppliedMutants(placement) {
|
|
5027
|
-
return placement !== void 0 && placement.appliedMutants.size > 0;
|
|
5028
|
-
}
|
|
5029
|
-
function applyPlacement(path, placement) {
|
|
5030
|
-
try {
|
|
5031
|
-
placement.placer.place(path, placement.appliedMutants);
|
|
5032
|
-
path.skip();
|
|
5033
|
-
} catch (error) {
|
|
5034
|
-
throwPlacementError(toError(error), path, placement.placer, [...placement.appliedMutants.keys()], originFileName, lineTable);
|
|
4807
|
+
function hasAppliedMutants(placement) {
|
|
4808
|
+
return placement !== void 0 && placement.appliedMutants.size > 0;
|
|
5035
4809
|
}
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
}
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
4810
|
+
function applyPlacement(path, placement) {
|
|
4811
|
+
try {
|
|
4812
|
+
placement.placer.place(path, placement.appliedMutants);
|
|
4813
|
+
path.skip();
|
|
4814
|
+
} catch (error) {
|
|
4815
|
+
throwPlacementError(toError(error), path, placement.placer, [...placement.appliedMutants.keys()], originFileName, lineTable, basePath);
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
function placeCollectedMutantsIfMutating(path) {
|
|
4819
|
+
if (shouldMutate(path)) placeCollectedMutants(path);
|
|
4820
|
+
}
|
|
4821
|
+
function placeCollectedMutants(path) {
|
|
4822
|
+
const mutantsToPlace = collectMutants(path);
|
|
4823
|
+
if (mutantsToPlace.length === 0) return;
|
|
4824
|
+
const placementPath = requiredPlacementPath(path, mutantsToPlace);
|
|
4825
|
+
const placement = requiredPlacement(placementPath.node);
|
|
4826
|
+
mutantsToPlace.forEach((mutant) => {
|
|
4827
|
+
placement.appliedMutants.set(mutant, applyMutant(mutant, placementPath.node));
|
|
4828
|
+
});
|
|
4829
|
+
}
|
|
4830
|
+
function requiredPlacementPath(path, mutantsToPlace) {
|
|
4831
|
+
return Option.getOrThrowWith(Option.fromNullishOr(path.find((ancestor) => placementMap.has(ancestor.node))), () => unplacedMutantsError(mutantsToPlace));
|
|
4832
|
+
}
|
|
4833
|
+
function unplacedMutantsError(mutantsToPlace) {
|
|
4834
|
+
return /* @__PURE__ */ new Error(`Mutants cannot be placed. This shouldn't happen! Unplaced mutants: ${JSON.stringify(mutantsToPlace, null, 2)}`);
|
|
4835
|
+
}
|
|
4836
|
+
function requiredPlacement(node) {
|
|
4837
|
+
return Option.getOrThrowWith(Option.fromNullishOr(placementMap.get(node)), () => /* @__PURE__ */ new Error("Placement not found for node"));
|
|
4838
|
+
}
|
|
4839
|
+
function shouldSkip(path) {
|
|
4840
|
+
return [
|
|
4841
|
+
isTypeNode(path),
|
|
4842
|
+
isImportDeclaration(path),
|
|
4843
|
+
nodeType(path.node) === "Decorator",
|
|
4844
|
+
mutateDescription === false,
|
|
4845
|
+
isOutsideMutateRanges(path)
|
|
4846
|
+
].some((skip) => skip);
|
|
4847
|
+
}
|
|
4848
|
+
function mutateRanges() {
|
|
4849
|
+
return Option.filter(Option.some(mutateDescription), isMutateRangeList);
|
|
4850
|
+
}
|
|
4851
|
+
function isOutsideMutateRanges(path) {
|
|
4852
|
+
return Option.exists(mutateRanges(), (ranges) => ranges.every((range) => !locationOverlaps(range, getNodeLocation(path.node))));
|
|
4853
|
+
}
|
|
4854
|
+
function shouldMutate(path) {
|
|
4855
|
+
return mutateDescription === true || isInsideMutateRanges(path);
|
|
4856
|
+
}
|
|
4857
|
+
function isInsideMutateRanges(path) {
|
|
4858
|
+
return Option.exists(mutateRanges(), (ranges) => ranges.some((range) => locationIncluded(range, getNodeLocation(path.node))));
|
|
4859
|
+
}
|
|
4860
|
+
function getNodeLocation(node) {
|
|
4861
|
+
const span = spanOf(node);
|
|
4862
|
+
if (span === void 0) throw new Error("Node without a span");
|
|
4863
|
+
return {
|
|
4864
|
+
start: positionFromLineTable(span.start, lineTable),
|
|
4865
|
+
end: positionFromLineTable(span.end, lineTable)
|
|
4866
|
+
};
|
|
4867
|
+
}
|
|
4868
|
+
function ignoreMessageFor(node, ancestors) {
|
|
4869
|
+
return ignorerReason(node, ancestors);
|
|
4870
|
+
}
|
|
4871
|
+
function ignorerReason(node, ancestors) {
|
|
4872
|
+
return options.ignorers.map((ignorer) => ignorer.shouldIgnore(node, ancestors)).find((reason) => reason !== void 0);
|
|
4873
|
+
}
|
|
4874
|
+
function collectMutants(path) {
|
|
4875
|
+
return mutablesFor(path).map((mutable) => collect(mutantCollector, originFileName, path.node, mutable, offset, lineTable)).filter((mutant) => mutant.ignoreReason === void 0);
|
|
4876
|
+
}
|
|
4877
|
+
function mutablesFor(path) {
|
|
4878
|
+
const ancestors = ancestorsOf(path);
|
|
4879
|
+
const context = toMutatorContext(ancestors);
|
|
4880
|
+
const line = getNodeLocation(path.node).start.line;
|
|
4881
|
+
return mutatorEntries.flatMap(([mutatorName, mutate]) => [...mutate(path.node, context)].map((replacement) => mutableFor(path.node, ancestors, mutatorName, replacement, line)));
|
|
4882
|
+
}
|
|
4883
|
+
function mutableFor(node, ancestors, mutatorName, replacement, line) {
|
|
4884
|
+
const mutableEntry = {
|
|
4885
|
+
replacement,
|
|
4886
|
+
mutatorName
|
|
4887
|
+
};
|
|
4888
|
+
const ignoreReason = ignoreReasonFor(node, ancestors, mutatorName, line);
|
|
4889
|
+
if (ignoreReason !== void 0) mutableEntry.ignoreReason = ignoreReason;
|
|
4890
|
+
return mutableEntry;
|
|
4891
|
+
}
|
|
4892
|
+
function ignoreReasonFor(node, ancestors, mutatorName, line) {
|
|
4893
|
+
return directiveOrExclusion(mutatorName, line) ?? ignoreMessageFor(node, ancestors);
|
|
4894
|
+
}
|
|
4895
|
+
function directiveOrExclusion(mutatorName, line) {
|
|
4896
|
+
return findIgnoreReason(directiveRule, mutatorName, line) ?? findExcludedMutatorIgnoreReason(mutatorName);
|
|
4897
|
+
}
|
|
4898
|
+
function findExcludedMutatorIgnoreReason(mutatorName) {
|
|
4899
|
+
if (options.excludedMutations.includes(mutatorName)) return `Ignored because of excluded mutation "${mutatorName}"`;
|
|
4900
|
+
else return;
|
|
4901
|
+
}
|
|
4902
|
+
});
|
|
5120
4903
|
};
|
|
5121
|
-
function toMutatorContext(
|
|
5122
|
-
const ancestors = [];
|
|
5123
|
-
let current = path.parentPath;
|
|
5124
|
-
while (current !== null) {
|
|
5125
|
-
ancestors.push(current.node);
|
|
5126
|
-
current = current.parentPath;
|
|
5127
|
-
}
|
|
4904
|
+
function toMutatorContext(ancestors) {
|
|
5128
4905
|
return {
|
|
5129
4906
|
parent: ancestors[0],
|
|
5130
4907
|
grandParent: ancestors[1],
|
|
5131
|
-
ancestors
|
|
4908
|
+
ancestors: [...ancestors]
|
|
5132
4909
|
};
|
|
5133
4910
|
}
|
|
5134
4911
|
function toError(value) {
|
|
@@ -5140,18 +4917,22 @@ function toError(value) {
|
|
|
5140
4917
|
const commentDirectiveRegEx = /^(\s*)@(ts-[a-z-]+).*$/;
|
|
5141
4918
|
const tsDirectiveLikeRegEx = /@(ts-[a-z-]+)/;
|
|
5142
4919
|
const STARTING_COMMENT = /^\s*\/\*[\s\S]*?\*\//;
|
|
5143
|
-
|
|
4920
|
+
const disableTypeChecks = (file) => {
|
|
5144
4921
|
const format = getFormat(file.name);
|
|
5145
|
-
if (format === void 0) return file;
|
|
4922
|
+
if (format === void 0) return Effect.succeed(file);
|
|
5146
4923
|
return disableTypeChecksFor(file, format);
|
|
5147
|
-
}
|
|
5148
|
-
|
|
5149
|
-
if (isJSFileWithoutTSDirectives(file, format)) return {
|
|
4924
|
+
};
|
|
4925
|
+
const disableTypeChecksFor = (file, format) => {
|
|
4926
|
+
if (isJSFileWithoutTSDirectives(file, format)) return Effect.succeed({
|
|
5150
4927
|
...file,
|
|
5151
4928
|
content: prefixWithNoCheck(file.content)
|
|
5152
|
-
};
|
|
5153
|
-
|
|
5154
|
-
|
|
4929
|
+
});
|
|
4930
|
+
const parse = createParser();
|
|
4931
|
+
return Effect.map(parse(file.content, file.name).pipe(Effect.mapError((cause) => InstrumentError.make({
|
|
4932
|
+
message: `Failed to parse ${file.name}`,
|
|
4933
|
+
cause
|
|
4934
|
+
}))), (ast) => withDisabledTypeChecking(file, ast));
|
|
4935
|
+
};
|
|
5155
4936
|
function withDisabledTypeChecking(file, ast) {
|
|
5156
4937
|
switch (ast.format) {
|
|
5157
4938
|
case "js":
|
|
@@ -5276,13 +5057,13 @@ function toOneBasedLineNumber(range) {
|
|
|
5276
5057
|
}
|
|
5277
5058
|
}));
|
|
5278
5059
|
}
|
|
5279
|
-
function
|
|
5060
|
+
function isIgnorer(value) {
|
|
5280
5061
|
return Predicate.isObject(value) && typeof value["shouldIgnore"] === "function";
|
|
5281
5062
|
}
|
|
5282
5063
|
function toTransformerOptions(options) {
|
|
5283
5064
|
const base = {
|
|
5284
5065
|
excludedMutations: [...options.excludedMutations],
|
|
5285
|
-
ignorers: options.ignorers.filter(
|
|
5066
|
+
ignorers: options.ignorers.filter(isIgnorer)
|
|
5286
5067
|
};
|
|
5287
5068
|
if (options.noHeader !== void 0) return {
|
|
5288
5069
|
...base,
|
|
@@ -5294,54 +5075,6 @@ const AST_SHAPE = ["format", "root"];
|
|
|
5294
5075
|
function isAst(value) {
|
|
5295
5076
|
return Predicate.isObject(value) && AST_SHAPE.every((key) => key in value);
|
|
5296
5077
|
}
|
|
5297
|
-
const readCollected = (command) => Effect.gen(function* () {
|
|
5298
|
-
const { files, options } = command;
|
|
5299
|
-
const parse = createParser();
|
|
5300
|
-
const parsed = yield* Effect.forEach(files, (file) => Effect.map(Effect.tryPromise({
|
|
5301
|
-
try: () => parse(file.content, file.name),
|
|
5302
|
-
catch: (cause) => new InstrumentError({
|
|
5303
|
-
message: `Failed to parse ${file.name}`,
|
|
5304
|
-
cause
|
|
5305
|
-
})
|
|
5306
|
-
}), (ast) => ({
|
|
5307
|
-
file,
|
|
5308
|
-
ast
|
|
5309
|
-
})));
|
|
5310
|
-
const collector = createMutantCollector();
|
|
5311
|
-
yield* Effect.forEach(parsed, ({ file, ast }) => Effect.tryPromise({
|
|
5312
|
-
try: () => transform(ast, collector, {
|
|
5313
|
-
options: toTransformerOptions(options),
|
|
5314
|
-
mutateDescription: toOneBasedLineNumber(file.mutate)
|
|
5315
|
-
}),
|
|
5316
|
-
catch: (cause) => new InstrumentError({
|
|
5317
|
-
message: `Failed to transform ${file.name}`,
|
|
5318
|
-
cause
|
|
5319
|
-
})
|
|
5320
|
-
}));
|
|
5321
|
-
const mutants = yield* Effect.try({
|
|
5322
|
-
try: () => collector.map(toApiMutant),
|
|
5323
|
-
catch: (cause) => new InstrumentError({
|
|
5324
|
-
message: "Failed to instrument",
|
|
5325
|
-
cause
|
|
5326
|
-
})
|
|
5327
|
-
});
|
|
5328
|
-
return {
|
|
5329
|
-
files,
|
|
5330
|
-
options,
|
|
5331
|
-
asts: parsed.map(({ ast }) => ast),
|
|
5332
|
-
mutants
|
|
5333
|
-
};
|
|
5334
|
-
});
|
|
5335
|
-
const printDecision = (decision) => Effect.try({
|
|
5336
|
-
try: () => InstrumentResult.make({
|
|
5337
|
-
files: decision.files.flatMap((file, index) => printedFile(file, decision.asts[index])),
|
|
5338
|
-
mutants: decision.mutants
|
|
5339
|
-
}),
|
|
5340
|
-
catch: (cause) => new InstrumentError({
|
|
5341
|
-
message: "Failed to print",
|
|
5342
|
-
cause
|
|
5343
|
-
})
|
|
5344
|
-
});
|
|
5345
5078
|
function printedFile(file, ast) {
|
|
5346
5079
|
if (!isAst(ast)) return [];
|
|
5347
5080
|
return [{
|
|
@@ -5350,28 +5083,47 @@ function printedFile(file, ast) {
|
|
|
5350
5083
|
content: print(ast)
|
|
5351
5084
|
}];
|
|
5352
5085
|
}
|
|
5353
|
-
const
|
|
5354
|
-
files: decoded.files,
|
|
5355
|
-
mutants: decoded.mutants,
|
|
5356
|
-
asts: decoded.asts
|
|
5357
|
-
});
|
|
5358
|
-
const instrument = (files, options) => Effect.gen(function* () {
|
|
5086
|
+
const instrument = (files, options, basePath) => Effect.gen(function* () {
|
|
5359
5087
|
const schemaFiles = files.map((file) => ({
|
|
5360
5088
|
name: file.name,
|
|
5361
5089
|
content: file.content,
|
|
5362
5090
|
mutate: file.mutate
|
|
5363
5091
|
}));
|
|
5364
|
-
const
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
})
|
|
5374
|
-
|
|
5092
|
+
const parse = createParser();
|
|
5093
|
+
const parsed = yield* Effect.forEach(schemaFiles, (file) => Effect.map(parse(file.content, file.name).pipe(Effect.mapError((cause) => InstrumentError.make({
|
|
5094
|
+
message: `Failed to parse ${file.name}`,
|
|
5095
|
+
cause
|
|
5096
|
+
}))), (ast) => ({
|
|
5097
|
+
file,
|
|
5098
|
+
ast
|
|
5099
|
+
})));
|
|
5100
|
+
const collector = createMutantCollector();
|
|
5101
|
+
yield* Effect.forEach(parsed, ({ file, ast }) => transform(ast, collector, {
|
|
5102
|
+
options: toTransformerOptions(options),
|
|
5103
|
+
mutateDescription: toOneBasedLineNumber(file.mutate),
|
|
5104
|
+
basePath
|
|
5105
|
+
}).pipe(Effect.mapError((cause) => InstrumentError.make({
|
|
5106
|
+
message: `Failed to transform ${file.name}`,
|
|
5107
|
+
cause
|
|
5108
|
+
}))));
|
|
5109
|
+
const mutants = yield* Effect.try({
|
|
5110
|
+
try: () => collector.map(toApiMutant),
|
|
5111
|
+
catch: (cause) => InstrumentError.make({
|
|
5112
|
+
message: "Failed to instrument",
|
|
5113
|
+
cause
|
|
5114
|
+
})
|
|
5115
|
+
});
|
|
5116
|
+
const printed = yield* Effect.try({
|
|
5117
|
+
try: () => parsed.flatMap(({ file, ast }) => printedFile(file, ast)),
|
|
5118
|
+
catch: (cause) => InstrumentError.make({
|
|
5119
|
+
message: "Failed to print",
|
|
5120
|
+
cause
|
|
5121
|
+
})
|
|
5122
|
+
});
|
|
5123
|
+
return InstrumentResult.make({
|
|
5124
|
+
files: printed,
|
|
5125
|
+
mutants
|
|
5126
|
+
});
|
|
5375
5127
|
});
|
|
5376
5128
|
//#endregion
|
|
5377
|
-
export {
|
|
5129
|
+
export { disableTypeChecks, instrument };
|