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