@systemfsoftware/stryker-js-instrumenter 6.0.1 → 7.1.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/dist/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
- import { INSTRUMENTER_CONSTANTS, Mutant, propertyPath, strykerReportBugUrl } from "@systemfsoftware/stryker-js";
1
+ import { a as isErrnoException, c as Mutant, d as MutantStatusSchema, f as RunOptionsFields, h as PositionSchema, i as errorToString, l as MutantActivationSchema, m as OpenEndLocationSchema, n as INSTRUMENTER_CONSTANTS, o as isMutant, p as LocationSchema, r as causeText, s as normalizeFileName, t as ERROR_CODES, u as MutantRunOptionsSchema } from "./Mutant-DnhV_fpo.mjs";
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 path from "path";
9
- import path$1 from "node:path";
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
  }) {
@@ -18,13 +18,13 @@ var InstrumentError = class extends S.TaggedError("@systemfsoftware/stryker-js-i
18
18
  return this.message;
19
19
  }
20
20
  };
21
- const PositionSchema = S.Struct({
21
+ const PositionSchema$1 = S.Struct({
22
22
  line: S.Finite,
23
23
  column: S.Finite
24
24
  });
25
25
  const RangeSchema = S.Struct({
26
- start: PositionSchema,
27
- end: PositionSchema
26
+ start: PositionSchema$1,
27
+ end: PositionSchema$1
28
28
  });
29
29
  const MutateDescriptionSchema = S.Union([S.Boolean, S.Array(RangeSchema)]);
30
30
  const FileSchema = S.Struct({
@@ -33,27 +33,11 @@ const FileSchema = S.Struct({
33
33
  mutate: MutateDescriptionSchema
34
34
  });
35
35
  const IgnorerSchema = S.Unknown;
36
- const AstSchema = S.Unknown;
37
36
  const InstrumenterOptionsSchema = 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)
@@ -68,6 +52,9 @@ S.Literals([
68
52
  //#endregion
69
53
  //#region src/Syntax.ts
70
54
  /**
55
+ * Syntax — the instrumenter's AST shapes, location helpers and syntax utilities.
56
+ */
57
+ /**
71
58
  * Determines if a location (needle) is included in an other location (haystack)
72
59
  * @param haystack The range to look in
73
60
  * @param needle the range to search for
@@ -122,13 +109,10 @@ function requireMidpoint(midValue) {
122
109
  return midValue;
123
110
  }
124
111
  //#endregion
125
- //#region src/estree.ts
126
- /**
127
- * ESTree toolkit — node builders, kind classification and a walker with
128
- * parent-chain paths. The walker replaces the previous traversal stack: oxc hands
129
- * back standard ESTree, so the instrumenter owns the traversal instead of
130
- * without pulling scope machinery along.
131
- */
112
+ //#region src/Traversal.schema.ts
113
+ var TraversalStopped = class extends Schema.TaggedError()("TraversalStopped", {}) {};
114
+ //#endregion
115
+ //#region src/Ast.ts
132
116
  const EXPRESSION_KINDS = /* @__PURE__ */ new Set([
133
117
  "ArrayExpression",
134
118
  "ArrowFunctionExpression",
@@ -194,10 +178,6 @@ const STATEMENT_KINDS = /* @__PURE__ */ new Set([
194
178
  "WhileStatement",
195
179
  "WithStatement"
196
180
  ]);
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
181
  function spanOf(node) {
202
182
  const range = node.range;
203
183
  if (range === void 0) return void 0;
@@ -206,10 +186,6 @@ function spanOf(node) {
206
186
  end: range[1]
207
187
  };
208
188
  }
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
189
  function nodeType(node) {
214
190
  if (!isAstNode(node)) return void 0;
215
191
  return node.type;
@@ -238,19 +214,22 @@ function identifier(name, loc) {
238
214
  function stringLiteral(value, loc) {
239
215
  return mark({
240
216
  type: "Literal",
241
- value
217
+ value,
218
+ raw: null
242
219
  }, loc);
243
220
  }
244
221
  function booleanLiteral(value, loc) {
245
222
  return mark({
246
223
  type: "Literal",
247
- value
224
+ value,
225
+ raw: null
248
226
  }, loc);
249
227
  }
250
228
  function regExpLiteral(pattern, flags, loc) {
251
229
  return mark({
252
230
  type: "Literal",
253
231
  value: null,
232
+ raw: null,
254
233
  regex: {
255
234
  pattern,
256
235
  flags
@@ -278,12 +257,12 @@ function newExpression(callee, args = [], loc) {
278
257
  arguments: [...args]
279
258
  }, loc);
280
259
  }
281
- function memberExpression(object, property, computed, optional, loc) {
260
+ function memberExpression(object, property, optional, loc) {
282
261
  return mark({
283
262
  type: "MemberExpression",
284
263
  object,
285
264
  property,
286
- computed,
265
+ computed: false,
287
266
  optional
288
267
  }, loc);
289
268
  }
@@ -291,6 +270,8 @@ function arrowFunctionExpression(params, body, loc) {
291
270
  const fnBody = body;
292
271
  return mark({
293
272
  type: "ArrowFunctionExpression",
273
+ id: null,
274
+ generator: false,
294
275
  params: [...params],
295
276
  body: fnBody,
296
277
  async: false,
@@ -391,20 +372,9 @@ function switchCase(test, consequent, loc) {
391
372
  consequent: [...consequent]
392
373
  }, loc);
393
374
  }
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
375
  function cloneNode(node) {
399
376
  return structuredClone(node);
400
377
  }
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
378
  function attachComments(root, comments, lineTable) {
409
379
  if (comments.length === 0) return;
410
380
  const nodes = collectNodes(root).filter((entry) => entry.node !== root);
@@ -421,13 +391,6 @@ function groupComments(nodes, comments) {
421
391
  for (const comment of comments) hostComment(nodes, comment, groups);
422
392
  return groups;
423
393
  }
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
394
  function hostComment(nodes, comment, groups) {
432
395
  const host = [{
433
396
  field: "leading",
@@ -465,32 +428,27 @@ function pushComment(map, node, comment) {
465
428
  if (list === void 0) map.set(node, [comment]);
466
429
  else list.push(comment);
467
430
  }
468
- /** oxc emits a node's children as a plain array the walker reads and replaces into. */
469
431
  const isNodeList = (value) => Array.isArray(value);
470
- function collectNodes(node) {
432
+ const walker = (root, visitors) => {
433
+ const ancestors = [];
434
+ walk(root, {
435
+ enter(node) {
436
+ visitors.enter?.(node, [...ancestors]);
437
+ ancestors.push(node);
438
+ },
439
+ leave(node) {
440
+ ancestors.pop();
441
+ visitors.leave?.(node, [...ancestors]);
442
+ }
443
+ });
444
+ };
445
+ function collectNodes(root) {
471
446
  const out = [];
472
- collect$1(node, out);
447
+ walker(root, { enter(node) {
448
+ appendEntry(node, out);
449
+ } });
473
450
  return out;
474
451
  }
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
452
  function appendEntry(node, out) {
495
453
  const span = spanOf(node);
496
454
  if (span === void 0) return;
@@ -510,80 +468,59 @@ function positionFromLineTable(offset, lineTable) {
510
468
  const zeroBased = positionFromOffset(lineTable, offset);
511
469
  return {
512
470
  line: zeroBased.line + 1,
513
- column: zeroBased.column
471
+ column: zeroBased.column + 1
514
472
  };
515
473
  }
516
- const SKIP_KEYS = /* @__PURE__ */ new Set([
517
- "type",
518
- "start",
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
- });
474
+ const COMMENT_KEYS = /* @__PURE__ */ new Set(["leadingComments", "trailingComments"]);
475
+ function isCommentKey(key) {
476
+ return typeof key === "string" && COMMENT_KEYS.has(key);
530
477
  }
531
- function visit(node, parentPath, key, listKey, visitors, context) {
532
- if (context.stopped) return;
533
- visitAstNode(node, parentPath, key, listKey, visitors, context);
478
+ function traverse(root, visitors) {
479
+ const stack = [];
480
+ try {
481
+ walk(root, {
482
+ enter(node, _parent, context) {
483
+ readPath(stack, node, this, context, visitors);
484
+ },
485
+ leave(_node, _parent, context) {
486
+ closePath(stack, context, visitors);
487
+ }
488
+ });
489
+ } catch (error) {
490
+ rethrowUnlessStopped(error);
491
+ }
534
492
  }
535
- function visitAstNode(node, parentPath, key, listKey, visitors, context) {
536
- if (!isVisitable(node, context)) return;
537
- const path = createPath(node, parentPath, key, listKey, context);
493
+ const rethrowUnlessStopped = (error) => {
494
+ if (!S.is(TraversalStopped)(error)) throw error;
495
+ };
496
+ const readPath = (stack, node, controls, context, visitors) => {
497
+ if (isCommentKey(context.key)) return;
498
+ const path = createPath(node, parentOf(stack), controls, context);
499
+ stack.push(path);
538
500
  notify(visitors.enter, path);
539
- visitEnteredNode(node, path, visitors, context);
540
- }
541
- function isVisitable(node, context) {
542
- return isAstNode(node) && !context.skipped.has(node);
543
- }
544
- function visitEnteredNode(node, path, visitors, context) {
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
- }
501
+ };
502
+ const closePath = (stack, context, visitors) => {
503
+ if (isCommentKey(context.key)) return;
504
+ notify(visitors.exit, stack.pop());
505
+ };
506
+ const parentOf = (stack) => Option.getOrNull(Arr.last(stack));
553
507
  function notify(visitor, path) {
554
508
  if (visitor === void 0) return;
555
- visitor(path);
509
+ relay(visitor, path);
556
510
  }
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);
563
- }
564
- function keepVisitingChild(child, path, key, visitors, context) {
565
- if (isNodeList(child)) return keepVisitingList(child, path, key, visitors, context);
566
- return keepVisitingValue(child, path, key, void 0, visitors, context);
567
- }
568
- function keepVisitingList(items, path, key, visitors, context) {
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) {
511
+ const relay = (visitor, path) => {
512
+ if (path !== void 0) visitor(path);
513
+ };
514
+ function createPath(node, parentPath, controls, context) {
515
+ const key = typeof context.key === "string" ? context.key : void 0;
576
516
  const path = {
577
517
  node,
578
518
  parentPath,
579
- parent: parentPath?.node,
580
- key,
581
- listKey,
582
519
  skip() {
583
- context.skipped.add(node);
520
+ controls.skip();
584
521
  },
585
522
  stop() {
586
- context.stopped = true;
523
+ throw TraversalStopped.make({});
587
524
  },
588
525
  find(predicate) {
589
526
  return nearest(path, predicate);
@@ -592,10 +529,7 @@ function createPath(node, parentPath, key, listKey, context) {
592
529
  return nearest(parentPath, (ancestor) => isStatementKind(ancestor.node));
593
530
  },
594
531
  replaceWith(replacement) {
595
- replaceInParent(parentPath, key, listKey, replacement);
596
- },
597
- is(kind) {
598
- return node.type === kind;
532
+ replaceInSlot(parentPath, key, context.index, replacement);
599
533
  },
600
534
  isExpression() {
601
535
  return isExpressionKind(node);
@@ -614,39 +548,36 @@ function takeOrAscend(path, predicate) {
614
548
  if (predicate(path)) return path;
615
549
  return nearest(path.parentPath, predicate);
616
550
  }
617
- function replaceInParent(parentPath, key, listKey, replacement) {
551
+ function replaceInSlot(parentPath, key, index, replacement) {
618
552
  if (parentPath === null) return;
619
- replaceChild(parentPath.node, key, listKey, replacement);
553
+ writeInto(parentPath.node, key, index, replacement);
620
554
  }
621
- function replaceChild(parent, key, listKey, replacement) {
555
+ function writeInto(parent, key, index, replacement) {
622
556
  if (!isAstNode(parent)) return;
623
- assignChild(parent, key, listKey, replacement);
624
- }
625
- function assignChild(parent, key, listKey, replacement) {
626
- if (listKey === void 0) {
627
- parent[key] = replacement;
628
- return;
629
- }
630
- assignIndexed(parent, key, listKey, replacement);
557
+ writeAtKey(parent, key, index, replacement);
631
558
  }
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;
559
+ function writeAtKey(parent, key, index, replacement) {
560
+ Match.value(key).pipe(Match.when(Predicate.isString, (slot) => writeAtSlot(parent, slot, index, replacement)), Match.orElse(() => void 0));
636
561
  }
637
- function isIndexedList(container, index) {
638
- return isNodeList(container) && Number.isInteger(index);
562
+ function writeAtSlot(parent, key, index, replacement) {
563
+ Match.value(index).pipe(Match.when(Match.null, () => overwrite(parent, key, replacement)), Match.orElse((position) => writeElement(parent[key], position, replacement)));
639
564
  }
565
+ const overwrite = (parent, key, replacement) => {
566
+ parent[key] = replacement;
567
+ };
568
+ const writeElement = (container, index, replacement) => {
569
+ if (isNodeList(container)) container[index] = replacement;
570
+ };
640
571
  //#endregion
641
572
  //#region src/Oxc.ts
642
573
  let oxc;
643
- const loadOxc = async () => {
644
- if (oxc === void 0) oxc = await import("oxc-parser");
574
+ const loadOxc = Effect.gen(function* () {
575
+ if (oxc === void 0) oxc = yield* Effect.promise(() => import("oxc-parser"));
645
576
  return oxc;
646
- };
577
+ });
647
578
  //#endregion
648
579
  //#region src/Parser.schema.ts
649
- var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParseFailed")("ParseFailed", {
580
+ var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/ParseFailed")("ParseFailed", {
650
581
  fileName: S.String,
651
582
  message: S.String,
652
583
  location: S.Struct({
@@ -659,7 +590,7 @@ var ParseFailed = class extends S.TaggedError("@systemfsoftware/stryker-js-instr
659
590
  return `Failed to parse ${this.fileName} at ${this.location.line}:${this.location.column}: ${this.message}`;
660
591
  }
661
592
  };
662
- var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/ParserNotFound")("ParserNotFound", {
593
+ var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/ParserNotFound")("ParserNotFound", {
663
594
  fileName: S.String,
664
595
  extension: S.String,
665
596
  cause: S.Defect()
@@ -668,7 +599,7 @@ var ParserNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-in
668
599
  return `No parser registered for ${this.fileName} (extension "${this.extension}")`;
669
600
  }
670
601
  };
671
- var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteVersionNotSupported")("SvelteVersionNotSupported", {
602
+ var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/SvelteVersionNotSupported")("SvelteVersionNotSupported", {
672
603
  version: S.String,
673
604
  fileName: S.String,
674
605
  cause: S.Defect()
@@ -677,7 +608,7 @@ var SvelteVersionNotSupported = class extends S.TaggedError("@systemfsoftware/st
677
608
  return `Svelte version ${this.version} is not supported for ${this.fileName} (expected >=3.30)`;
678
609
  }
679
610
  };
680
- var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteWalkerNotFound")("SvelteWalkerNotFound", {
611
+ var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/SvelteWalkerNotFound")("SvelteWalkerNotFound", {
681
612
  fileName: S.String,
682
613
  cause: S.Defect()
683
614
  }) {
@@ -685,7 +616,7 @@ var SvelteWalkerNotFound = class extends S.TaggedError("@systemfsoftware/stryker
685
616
  return `Svelte walker not found for ${this.fileName}`;
686
617
  }
687
618
  };
688
- S.TaggedError("@systemfsoftware/stryker-js-instrumenter/SvelteParseFailed")("SvelteParseFailed", {
619
+ S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Parser.schema/SvelteParseFailed")("SvelteParseFailed", {
689
620
  fileName: S.String,
690
621
  cause: S.Defect()
691
622
  });
@@ -727,23 +658,23 @@ function fieldOf(value, key) {
727
658
  function appendIfDefined(values, value) {
728
659
  if (value !== void 0) values.push(value);
729
660
  }
730
- async function parseWithOxc(text, fileName, lang) {
731
- const { parseSync } = await loadOxc();
661
+ const parseWithOxc = (text, fileName, lang) => Effect.gen(function* () {
662
+ const { parseSync } = yield* loadOxc;
732
663
  const result = parseSync(fileName, text, {
733
664
  lang,
734
665
  range: true
735
666
  });
736
667
  const failure = oxcParseFailure(result.errors, text, fileName);
737
- if (failure !== void 0) throw failure;
668
+ if (failure !== void 0) return yield* failure;
738
669
  return {
739
670
  root: result.program,
740
671
  comments: result.comments
741
672
  };
742
- }
673
+ });
743
674
  function oxcParseFailure(errors, text, fileName) {
744
675
  const first = errors.at(0);
745
676
  if (first === void 0) return;
746
- return new ParseFailed({
677
+ return ParseFailed.make({
747
678
  fileName,
748
679
  message: first.message,
749
680
  location: positionFromLineTable(oxcErrorLabelStart(first), buildLineTable(text)),
@@ -770,13 +701,16 @@ function shiftScriptOffsets(ast, offset) {
770
701
  }
771
702
  function createParser() {
772
703
  const jsParse = createJSParser();
773
- async function parse(code, fileName, formatOverride) {
704
+ function parse(code, fileName, formatOverride) {
774
705
  const format = getFormat(fileName, formatOverride);
775
- if (!format) throw new ParserNotFound({
776
- fileName,
777
- extension: path.extname(fileName).toLowerCase(),
778
- cause: void 0
779
- });
706
+ if (!format) {
707
+ const ext = extensionOf(fileName);
708
+ return Effect.fail(ParserNotFound.make({
709
+ fileName,
710
+ extension: ext,
711
+ cause: void 0
712
+ }));
713
+ }
780
714
  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
715
  }
782
716
  return parse;
@@ -796,40 +730,37 @@ const FORMAT_BY_EXTENSION = {
796
730
  ".svelte": "svelte"
797
731
  };
798
732
  function getFormat(fileName, override) {
799
- return override ?? FORMAT_BY_EXTENSION[path.extname(fileName).toLowerCase()];
733
+ return override ?? FORMAT_BY_EXTENSION[extensionOf(fileName)];
800
734
  }
735
+ const dotBeforeSlash = (dot, slash) => dot >= 0 && dot > slash;
736
+ const extensionOf = (fileName) => {
737
+ const dot = fileName.lastIndexOf(".");
738
+ const slash = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
739
+ return dotBeforeSlash(dot, slash) ? fileName.slice(dot).toLowerCase() : "";
740
+ };
801
741
  function createJSParser() {
802
- return async function parse(text, fileName) {
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 {
742
+ return (text, fileName) => Effect.map(parseWithOxc(text, fileName, "js"), ({ root, comments }) => ({
816
743
  originFileName: fileName,
817
744
  rawContent: text,
818
- format: "ts",
745
+ format: "js",
819
746
  root,
820
747
  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
- };
748
+ }));
832
749
  }
750
+ const parseTS = (text, fileName) => Effect.map(parseWithOxc(text, fileName, "ts"), ({ root, comments }) => ({
751
+ originFileName: fileName,
752
+ rawContent: text,
753
+ format: "ts",
754
+ root,
755
+ comments
756
+ }));
757
+ const parseTsx = (text, fileName) => Effect.map(parseWithOxc(text, fileName, "tsx"), ({ root, comments }) => ({
758
+ root,
759
+ comments,
760
+ format: "tsx",
761
+ originFileName: fileName,
762
+ rawContent: text
763
+ }));
833
764
  const SCRIPT_TYPE_FORMATS = {
834
765
  tsx: "tsx",
835
766
  "text/tsx": "tsx",
@@ -841,27 +772,25 @@ const SCRIPT_TYPE_FORMATS = {
841
772
  javascript: "js",
842
773
  module: "js"
843
774
  };
844
- async function parseHtml(text, originFileName, context) {
845
- return {
846
- originFileName,
847
- rawContent: text,
848
- format: "html",
849
- root: await ngHtmlParser(text, originFileName, context)
850
- };
851
- }
852
- async function ngHtmlParser(text, fileName, parserContext) {
853
- const ngParser = await import("angular-html-parser");
775
+ const parseHtml = (text, originFileName, context) => Effect.map(ngHtmlParser(text, originFileName, context), (root) => ({
776
+ originFileName,
777
+ rawContent: text,
778
+ format: "html",
779
+ root
780
+ }));
781
+ const ngHtmlParser = (text, fileName, parserContext) => Effect.gen(function* () {
782
+ const ngParser = yield* Effect.promise(() => import("angular-html-parser"));
854
783
  const { rootNodes, errors } = ngParser.parse(text, {
855
784
  canSelfClose: true,
856
785
  allowHtmComponentClosingTags: true,
857
786
  isTagNameCaseSensitive: true
858
787
  });
859
- if (errors.length !== 0) throw htmlErrorFailure(errors, fileName);
860
- const scriptsAsPromised = [];
788
+ if (errors.length !== 0) return yield* htmlErrorFailure(errors, fileName);
789
+ const scriptEffects = [];
861
790
  const scriptCollector = {
862
791
  visitElement: (el, context) => {
863
792
  const scriptFormat = getScriptType(el);
864
- if (scriptFormat) scriptsAsPromised.push(parseScript(el, scriptFormat));
793
+ if (scriptFormat) scriptEffects.push(parseScript(el, scriptFormat));
865
794
  ngParser.visitAll(scriptCollector, el.children, context);
866
795
  },
867
796
  visitAttribute: () => void 0,
@@ -878,10 +807,9 @@ async function ngHtmlParser(text, fileName, parserContext) {
878
807
  visitDirective: () => void 0
879
808
  };
880
809
  ngParser.visitAll(scriptCollector, rootNodes);
881
- return { scripts: await Promise.all(scriptsAsPromised) };
882
- async function parseScript(el, scriptFormat) {
883
- const ast = await parserContext.parse(elementScriptText(el, text), fileName, scriptFormat);
884
- if (ast != null) {
810
+ return { scripts: yield* Effect.all(scriptEffects) };
811
+ function parseScript(el, scriptFormat) {
812
+ return Effect.map(parserContext.parse(elementScriptText(el, text), fileName, scriptFormat), (ast) => {
885
813
  const offset = el.startSourceSpan.end;
886
814
  shiftScriptOffsets(ast, offset.offset);
887
815
  return {
@@ -891,13 +819,12 @@ async function ngHtmlParser(text, fileName, parserContext) {
891
819
  line: offset.line
892
820
  }
893
821
  };
894
- }
895
- return ast;
822
+ });
896
823
  }
897
- }
824
+ });
898
825
  function htmlErrorFailure(errors, fileName) {
899
826
  const first = errors.at(0);
900
- if (first === void 0) return new ParseFailed({
827
+ if (first === void 0) return ParseFailed.make({
901
828
  fileName,
902
829
  message: "HTML parser reported errors but first error is missing",
903
830
  location: {
@@ -906,7 +833,7 @@ function htmlErrorFailure(errors, fileName) {
906
833
  },
907
834
  cause: errors
908
835
  });
909
- return new ParseFailed({
836
+ return ParseFailed.make({
910
837
  fileName,
911
838
  message: first.msg,
912
839
  location: toSourceLocation(first.span.start),
@@ -948,7 +875,7 @@ const SVELTE_5 = {
948
875
  major: 5,
949
876
  minor: 0
950
877
  };
951
- const ESTREE_WALKER_MISSING = "estree-walker module without walk export";
878
+ const WALKER_MODULE_MISSING = "walker module without walk export";
952
879
  const COMPILER_WALK_MISSING = "svelte/compiler module without walk export";
953
880
  const INSTANCE_RANGE_MISSING = "Svelte instance script without a source range";
954
881
  const MODULE_RANGE_MISSING = "Svelte module script without a source range";
@@ -1029,75 +956,68 @@ function rangedExpressionOf(payload) {
1029
956
  * Due to the way Svelte 5 is structured, we can no longer use the typings from Svelte 4, even though
1030
957
  * we use the legacy AST. The full Svelte 5 migration should update these typings to use the new AST.
1031
958
  */
1032
- function loadWalker(version, fileName) {
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
- }
959
+ 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
960
  /**
1036
961
  * The specifier is chosen at run time and both modules are optional peers of
1037
962
  * this package, so neither can be a static import.
1038
963
  */
1039
- async function loadWalkerModule(specifier, fileName, cause) {
1040
- const module = await import(specifier);
964
+ const loadWalkerModule = (specifier, fileName, cause) => Effect.gen(function* () {
965
+ const module = yield* Effect.promise(() => import(specifier));
1041
966
  const walk = Match.value(module).pipe(Match.when(isRecordWithWalk, (record) => record.walk), Match.orElse(() => void 0));
1042
- if (walk === void 0) throw new SvelteWalkerNotFound({
967
+ if (walk === void 0) return yield* SvelteWalkerNotFound.make({
1043
968
  fileName,
1044
969
  cause
1045
970
  });
1046
971
  return walk;
1047
- }
1048
- async function parseSvelte(text, fileName, context) {
1049
- const { parse: svelteParse, preprocess, VERSION } = await import("svelte/compiler");
1050
- if (!isAtLeast(VERSION, MINIMUM_SVELTE_VERSION)) throw new SvelteVersionNotSupported({
972
+ });
973
+ const parseSvelte = (text, fileName, context) => Effect.gen(function* () {
974
+ const { parse: svelteParse, preprocess, VERSION } = yield* Effect.promise(() => import("svelte/compiler"));
975
+ if (!isAtLeast(VERSION, MINIMUM_SVELTE_VERSION)) return yield* SvelteVersionNotSupported.make({
1051
976
  version: VERSION,
1052
977
  fileName,
1053
978
  cause: `Expected >=3.30`
1054
979
  });
1055
- const walk = await loadWalker(VERSION, fileName);
980
+ const walk = yield* loadWalker(VERSION, fileName);
1056
981
  const lineStarts = computeLineStarts(text);
1057
- const { replacedCode, scriptMap } = await replaceScripts(text);
982
+ const { replacedCode, scriptMap } = yield* replaceScripts(text, preprocess);
1058
983
  const svelteAst = svelteParse(replacedCode, { filename: fileName });
1059
984
  const { remappedModuleScriptRange, remappedScriptRanges } = remapScriptLocations(replacedCode, scriptMap, getModuleScriptRange(svelteAst), getTemplateScriptRanges(svelteAst, walk));
1060
- const [moduleScript, ...additionalScripts] = await Promise.all([parseTemplateScriptIfDefined(remappedModuleScriptRange), ...remappedScriptRanges.map(parseTemplateScript)]);
1061
985
  return {
1062
986
  originFileName: fileName,
1063
987
  rawContent: text,
1064
988
  format: "svelte",
1065
- root: svelteRoot(moduleScript, additionalScripts)
989
+ root: svelteRoot(yield* parseTemplateScriptIfDefined(remappedModuleScriptRange, context, text, fileName, lineStarts), yield* Effect.forEach(remappedScriptRanges, (range) => parseTemplateScript(range, context, text, fileName, lineStarts)))
1066
990
  };
1067
- /**
1068
- * Replaces script tags with placeholders.
1069
- * This is needed, because svelte's `parse` doesn't support `lang="ts"`.
1070
- */
1071
- async function replaceScripts(code) {
1072
- const map = /* @__PURE__ */ new Map();
1073
- let scriptIndex = 0;
991
+ });
992
+ const replaceScripts = (code, preprocess) => {
993
+ const map = /* @__PURE__ */ new Map();
994
+ let scriptIndex = 0;
995
+ return Effect.gen(function* () {
1074
996
  return {
1075
- replacedCode: (await preprocess(code, { script(script) {
997
+ replacedCode: (yield* Effect.promise(() => preprocess(code, { script(script) {
1076
998
  const scriptName = `script${scriptIndex++}`;
1077
999
  map.set(scriptName, script);
1078
1000
  return { code: scriptName };
1079
- } })).code,
1001
+ } }))).code,
1080
1002
  scriptMap: map
1081
1003
  };
1082
- }
1083
- async function parseTemplateScriptIfDefined(range) {
1084
- if (range) return parseTemplateScript(range);
1085
- }
1086
- async function parseTemplateScript({ start, end, isExpression, format }) {
1087
- const scriptText = text.slice(start, end);
1088
- return {
1089
- ast: {
1090
- ...await context.parse(scriptText, fileName, format),
1091
- offset: positionFromOffset(lineStarts, start)
1092
- },
1093
- range: {
1094
- start,
1095
- end
1096
- },
1097
- isExpression
1098
- };
1099
- }
1100
- }
1004
+ });
1005
+ };
1006
+ const parseTemplateScriptIfDefined = (range, context, text, fileName, lineStarts) => Effect.gen(function* () {
1007
+ if (range === void 0) return;
1008
+ return yield* parseTemplateScript(range, context, text, fileName, lineStarts);
1009
+ });
1010
+ const parseTemplateScript = ({ start, end, isExpression, format }, context, text, fileName, lineStarts) => Effect.map(context.parse(text.slice(start, end), fileName, format), (parsed) => ({
1011
+ ast: {
1012
+ ...parsed,
1013
+ offset: positionFromOffset(lineStarts, start)
1014
+ },
1015
+ range: {
1016
+ start,
1017
+ end
1018
+ },
1019
+ isExpression
1020
+ }));
1101
1021
  function svelteRoot(moduleScript, additionalScripts) {
1102
1022
  return Match.value(moduleScript).pipe(Match.when(void 0, () => ({ additionalScripts })), Match.orElse((script) => ({
1103
1023
  moduleScript: script,
@@ -1723,15 +1643,15 @@ var PrintState = class {
1723
1643
  case "accessor":
1724
1644
  this.out += `${fields.kind} `;
1725
1645
  this.out += this.propertyKeyText(fields.key, fields.computed === true, PREC.Assignment);
1726
- this.printFunctionValue(fields.value);
1646
+ this.printFunctionTail(fields.value);
1727
1647
  break;
1728
1648
  case "method":
1729
1649
  this.out += `${flagText(fields.async, "async ")}${flagText(fields.generator, "*")}`;
1730
1650
  this.out += this.propertyKeyText(fields.key, fields.computed === true, PREC.Assignment);
1731
- this.printFunctionValue(fields.value);
1651
+ this.printFunctionTail(fields.value);
1732
1652
  break;
1733
1653
  case "shorthand":
1734
- this.out += identifierName$1(fields.key);
1654
+ this.out += identifierName(fields.key);
1735
1655
  break;
1736
1656
  case "shorthandDefault":
1737
1657
  this.printShorthandDefaultProperty(fields);
@@ -1744,7 +1664,7 @@ var PrintState = class {
1744
1664
  }
1745
1665
  printShorthandDefaultProperty(fields) {
1746
1666
  const right = this.assignmentNodeText(fields.value.right);
1747
- this.out += `${identifierName$1(fields.key)} = ${right}`;
1667
+ this.out += `${identifierName(fields.key)} = ${right}`;
1748
1668
  }
1749
1669
  propertyKeyText(key, computed, computedPrec) {
1750
1670
  switch (computed) {
@@ -1763,10 +1683,6 @@ var PrintState = class {
1763
1683
  printPropertyKeyForClass(key, computed) {
1764
1684
  this.out += this.propertyKeyText(key, computed, PREC.Sequence);
1765
1685
  }
1766
- printFunctionValue(fn) {
1767
- if (!fn) return;
1768
- this.printFunctionTail(fn);
1769
- }
1770
1686
  printFunctionTail(fn) {
1771
1687
  this.out += this.typeParametersText(fn.typeParameters);
1772
1688
  this.out += `(${this.paramsText(fn.params)})`;
@@ -2222,13 +2138,16 @@ var PrintState = class {
2222
2138
  }
2223
2139
  }
2224
2140
  printExpressionStatement(node) {
2225
- if (node.directive) {
2141
+ if (this.isDirective(node.directive)) {
2226
2142
  this.out += JSON.stringify(node.directive) + ";";
2227
2143
  return;
2228
2144
  }
2229
2145
  this.printNode(node.expression, PREC.Sequence);
2230
2146
  this.out += ";";
2231
2147
  }
2148
+ isDirective(directive) {
2149
+ return directive != null && directive !== "";
2150
+ }
2232
2151
  printIfStatement(node) {
2233
2152
  this.out += "if (";
2234
2153
  this.printNode(node.test, PREC.Sequence);
@@ -3092,12 +3011,12 @@ function propertyForm(fields) {
3092
3011
  }
3093
3012
  }
3094
3013
  function isShorthandMatch(fields) {
3095
- return fields.shorthand === true && namesMatch(identifierName$1(fields.key), identifierName$1(fields.value));
3014
+ return fields.shorthand === true && namesMatch(identifierName(fields.key), identifierName(fields.value));
3096
3015
  }
3097
3016
  function isShorthandDefaultMatch(fields) {
3098
- return fields.shorthand === true && namesMatch(identifierName$1(fields.key), defaultTargetName(fields.value));
3017
+ return fields.shorthand === true && namesMatch(identifierName(fields.key), defaultTargetName(fields.value));
3099
3018
  }
3100
- function identifierName$1(node) {
3019
+ function identifierName(node) {
3101
3020
  switch (nodeKind(node)) {
3102
3021
  case "Identifier": return node.name;
3103
3022
  default: return;
@@ -3105,7 +3024,7 @@ function identifierName$1(node) {
3105
3024
  }
3106
3025
  function defaultTargetName(node) {
3107
3026
  switch (nodeKind(node)) {
3108
- case "AssignmentPattern": return identifierName$1(node.left);
3027
+ case "AssignmentPattern": return identifierName(node.left);
3109
3028
  default: return;
3110
3029
  }
3111
3030
  }
@@ -3374,12 +3293,8 @@ const hashbangOf = (root) => {
3374
3293
  if (!isHashbang(hashbang)) return null;
3375
3294
  return hashbang;
3376
3295
  };
3377
- const jsPrint = (file) => {
3378
- return printProgram(file.root, { hashbang: hashbangOf(file.root) });
3379
- };
3380
- const tsPrint = (file) => {
3381
- return printProgram(file.root, { hashbang: hashbangOf(file.root) });
3382
- };
3296
+ const jsPrint = (file) => printProgram(file.root, { hashbang: hashbangOf(file.root) });
3297
+ const tsPrint = (file) => printProgram(file.root, { hashbang: hashbangOf(file.root) });
3383
3298
  function getScriptStart$1(script) {
3384
3299
  const span = spanOf(script.root);
3385
3300
  if (span === void 0) throw new Error("Script AST root without start");
@@ -3437,7 +3352,7 @@ function appendStatement(state, script, rawContent, context) {
3437
3352
  /**
3438
3353
  * Node identity: same kind, same span. oxc nodes always carry a range
3439
3354
  * (parsed with `range: true`), which is a stronger identity than the old
3440
- * estree line/column loc.
3355
+ * line/column loc.
3441
3356
  */
3442
3357
  function eqNode(a, b) {
3443
3358
  const identity = nodeIdentity(a);
@@ -3738,7 +3653,13 @@ const arithmeticOperatorReplacements = Object.freeze({
3738
3653
  const ARITHMETIC_OPERATOR_KEYS = Object.keys(arithmeticOperatorReplacements);
3739
3654
  const arithmeticOperatorMutator = (node) => Match.value(node).pipe(Match.when(isArithmeticBinary, (binary) => [withOperator(binary, arithmeticOperatorReplacements[binary.operator])]), Match.orElse(() => NO_MUTANTS));
3740
3655
  function isArithmeticBinary(node) {
3741
- return node.type === "BinaryExpression" && isSupportedArithmeticOperator(node.operator, node);
3656
+ return isBinaryExpression(node) && isSupportedArithmeticOperator(node.operator, node);
3657
+ }
3658
+ function isBinaryExpression(node) {
3659
+ return node.type === "BinaryExpression" && !isPrivateInExpression(node);
3660
+ }
3661
+ function isPrivateInExpression(node) {
3662
+ return node.left.type === "PrivateIdentifier";
3742
3663
  }
3743
3664
  function isSupportedArithmeticOperator(operator, node) {
3744
3665
  return ARITHMETIC_OPERATOR_KEYS.includes(operator) && !isStringConcatenation(node);
@@ -4085,7 +4006,7 @@ function methodExpressionReplacement(mutation) {
4085
4006
  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
4007
  }
4087
4008
  function renamedMethodCall(mutation, newName) {
4088
- return callExpression(memberExpression(cloneNode(mutation.callee.object), identifier(newName), false, mutation.callee.optional === true), spreadFreeArguments(mutation.call.arguments), mutation.call.optional === true);
4009
+ return callExpression(memberExpression(cloneNode(mutation.callee.object), identifier(newName), mutation.callee.optional === true), spreadFreeArguments(mutation.call.arguments), mutation.call.optional === true);
4089
4010
  }
4090
4011
  function spreadFreeArguments(args) {
4091
4012
  return args.filter(isNotSpreadElement).map((argument) => cloneNode(argument));
@@ -4275,13 +4196,13 @@ const allMutators = Object.freeze({
4275
4196
  UnaryOperator: unaryOperatorMutator,
4276
4197
  UpdateOperator: updateOperatorMutator
4277
4198
  });
4278
- S.TaggedError("@systemfsoftware/stryker-js-instrumenter/PlacementFailed")("PlacementFailed", {
4199
+ S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Transformer.schema/PlacementFailed")("PlacementFailed", {
4279
4200
  fileName: S.String,
4280
4201
  placerName: S.String,
4281
4202
  mutantIds: S.Array(S.String),
4282
4203
  cause: S.Defect()
4283
4204
  });
4284
- S.TaggedError("@systemfsoftware/stryker-js-instrumenter/TransformFailed")("TransformFailed", {
4205
+ S.TaggedError("@systemfsoftware/stryker-js-instrumenter/Transformer.schema/TransformFailed")("TransformFailed", {
4285
4206
  fileName: S.String,
4286
4207
  cause: S.Defect()
4287
4208
  });
@@ -4390,32 +4311,10 @@ function mutatorWarning(directive, mutatorName, originFileName) {
4390
4311
  onSome: (scope) => `${directive.type} ${scope}`
4391
4312
  })}' directive. Mutator with name '${mutatorName}' not found. Directive found at: ${originFileName}:${loc.start.line}:${loc.start.column}.`;
4392
4313
  }
4393
- function toIgnorerPath(path) {
4394
- let parentResult = null;
4395
- if (path.parentPath !== null) parentResult = toIgnorerPath(path.parentPath);
4396
- const node = path.node;
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"]));
4314
+ function ancestorsOf(path) {
4315
+ const ancestors = [];
4316
+ for (let current = path.parentPath; current !== null; current = current.parentPath) ancestors.push(current.node);
4317
+ return ancestors;
4419
4318
  }
4420
4319
  function isTypeNode(path) {
4421
4320
  return [
@@ -4475,27 +4374,35 @@ function nodeOfKind(mutant, node, isKind, kind) {
4475
4374
  if (!isKind(node)) throw new Error(`Cannot place mutant ${mutant.id}: expected ${kind}, got ${node.type}`);
4476
4375
  return node;
4477
4376
  }
4478
- function throwPlacementError(error, nodePath, placer, mutants, fileName, lineTable) {
4479
- const message = `${placer.name} could not place mutants with type(s): "${new Intl.ListFormat("en").format(mutants.map((mutant) => mutant.mutatorName))}"`;
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 ${propertyPath()("mutator", "excludedMutations")}). Please report this issue at ${strykerReportBugUrl(message)}. Original error: ${error.stack}`;
4377
+ function throwPlacementError(error, nodePath, placer, mutants, fileName, lineTable, basePath) {
4378
+ const message = `${placer.name} could not place mutants with type(s): "${placementListFormat.format(mutants.map((mutant) => mutant.mutatorName))}"`;
4379
+ 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
4380
  throw new Error(errorMessage);
4482
4381
  }
4483
- function placementLocation(node, fileName, lineTable) {
4484
- const relativeFile = path$1.relative(process.cwd(), fileName);
4382
+ function placementLocation(node, fileName, lineTable, basePath) {
4383
+ const relativeFile = basePath === void 0 ? fileName : relativeTo(basePath, fileName);
4485
4384
  const position = Option.map(Option.fromNullishOr(spanOf(node)), (span) => positionFromLineTable(span.start, lineTable));
4486
4385
  return Option.match(position, {
4487
4386
  onNone: () => `${relativeFile}:undefined:undefined`,
4488
4387
  onSome: (at) => `${relativeFile}:${at.line}:${at.column}`
4489
4388
  });
4490
4389
  }
4390
+ const placementListFormat = new Intl.ListFormat("en");
4391
+ const normalizeSeparators = (value) => value.replace(/\\/g, "/");
4392
+ const withTrailingSlash = (basePath) => {
4393
+ const normalized = normalizeSeparators(basePath);
4394
+ return normalized.endsWith("/") ? normalized : `${normalized}/`;
4395
+ };
4396
+ const relativeTo = (basePath, fileName) => {
4397
+ const prefix = withTrailingSlash(basePath);
4398
+ const normalizedFile = normalizeSeparators(fileName);
4399
+ return normalizedFile.startsWith(prefix) ? normalizedFile.slice(prefix.length) : fileName;
4400
+ };
4491
4401
  function classOrFunctionExpressionNamedIfNeeded(path) {
4492
4402
  return Match.value(path.node).pipe(Match.when(isAnonymousFunctionOrClass, (node) => nameFromParent(path, node)), Match.orElse(() => void 0));
4493
4403
  }
4494
4404
  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({
4405
+ return Match.value(path.parentPath?.node).pipe(Match.when(isVariableDeclarator, (declarator) => adoptDeclaredName(node, declarator)), Match.when({
4499
4406
  type: "Property",
4500
4407
  key: { type: "Identifier" }
4501
4408
  }, () => namedPropertyValue(path, node)), Match.orElse(() => void 0));
@@ -4528,10 +4435,22 @@ function namedArrowExpression(node, identifier) {
4528
4435
  return callExpression(arrowFunctionExpression([], blockStatement([variableDeclaration("const", [variableDeclarator(identifier, node)]), returnStatement(identifier)])), []);
4529
4436
  }
4530
4437
  function declaratorIdentifier(parentPath) {
4531
- return Option.flatMap(Option.fromNullishOr(parentPath), (parent) => Match.value(parent.node).pipe(Match.when({
4532
- type: "VariableDeclarator",
4533
- id: { type: "Identifier" }
4534
- }, (declarator) => Option.some(declarator.id)), Match.orElse(() => Option.none())));
4438
+ return Option.flatMap(Option.fromNullishOr(parentPath), (parent) => Match.value(parent.node).pipe(Match.when(isVariableDeclarator, (declarator) => declaredName(declarator)), Match.orElse(() => Option.none())));
4439
+ }
4440
+ function isVariableDeclarator(node) {
4441
+ return nodeType(node) === "VariableDeclarator";
4442
+ }
4443
+ function adoptDeclaredName(node, declarator) {
4444
+ return Option.match(declaredName(declarator), {
4445
+ onNone: () => void 0,
4446
+ onSome: (identifier) => adoptIdentifier(node, identifier)
4447
+ });
4448
+ }
4449
+ function declaredName(declarator) {
4450
+ return Match.value(declarator.id).pipe(Match.when(isIdentifierReference, (identifier) => Option.some(identifier)), Match.orElse(() => Option.none()));
4451
+ }
4452
+ function isIdentifierReference(node) {
4453
+ return nodeType(node) === "Identifier";
4535
4454
  }
4536
4455
  function nameIfAnonymous(path) {
4537
4456
  return classOrFunctionExpressionNamedIfNeeded(path) ?? arrowNameOrNode(path);
@@ -4666,139 +4585,9 @@ const allMutantPlacers = Object.freeze([
4666
4585
  }
4667
4586
  }
4668
4587
  ]);
4669
- const ANGULAR_SIGNAL_IO_FUNCTIONS = Object.freeze([
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) {
4588
+ function isCommentArray(value) {
4747
4589
  return Array.isArray(value);
4748
4590
  }
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
4591
  const INSTRUMENTATION_HEADER_SOURCE = `// @ts-nocheck
4803
4592
  var ${STRYKER_NAMESPACE_HELPER} = function(){
4804
4593
  var g = typeof globalThis === 'object' && globalThis && globalThis.Math === Math && globalThis || new Function("return this")();
@@ -4845,32 +4634,29 @@ var ${IS_MUTANT_ACTIVE_HELPER} = function(id) {
4845
4634
  return isActive(id);
4846
4635
  }`;
4847
4636
  let instrumentationHeaderValue;
4848
- const instrumentationHeader = async () => {
4637
+ const instrumentationHeader = Effect.gen(function* () {
4849
4638
  if (instrumentationHeaderValue === void 0) {
4850
- instrumentationHeaderValue = (await parseWithOxc(INSTRUMENTATION_HEADER_SOURCE, "instrumenter-header.js", "js")).root.body;
4639
+ instrumentationHeaderValue = (yield* parseWithOxc(INSTRUMENTATION_HEADER_SOURCE, "instrumenter-header.js", "js")).root.body;
4851
4640
  deepFreeze(instrumentationHeaderValue);
4852
4641
  }
4853
4642
  return instrumentationHeaderValue;
4854
- };
4855
- async function placeHeaderIfNeeded(mutantCollector, originFileName, options, root) {
4856
- if (shouldPlaceHeader(mutantCollector, originFileName, options)) await placeHeader(root);
4857
- }
4643
+ });
4644
+ const placeHeaderIfNeeded = (mutantCollector, originFileName, options, root) => Effect.gen(function* () {
4645
+ if (shouldPlaceHeader(mutantCollector, originFileName, options)) yield* placeHeader(root);
4646
+ });
4647
+ const placeHeader = (root) => Effect.map(headerFor(root), (header) => {
4648
+ root.body.unshift(...header);
4649
+ });
4858
4650
  function shouldPlaceHeader(mutantCollector, originFileName, options) {
4859
4651
  return hasPlacedMutants(mutantCollector, originFileName) && options.noHeader !== true;
4860
4652
  }
4861
- async function placeHeader(root) {
4862
- root.body.unshift(...await headerFor(root));
4863
- }
4864
- async function headerFor(root) {
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
- }
4653
+ const headerFor = (root) => Effect.map(instrumentationHeader, (header) => Option.match(leadingCommentsOf(root), {
4654
+ onNone: () => header,
4655
+ onSome: (leadingComments) => [commentedHeader(leadingComments, header), ...header.slice(1)]
4656
+ }));
4871
4657
  function leadingCommentsOf(root) {
4872
4658
  const firstStatement = root.body[0];
4873
- return Option.filter(Option.fromNullishOr(firstStatement?.leadingComments), isUnknownArray);
4659
+ return Option.filter(Option.fromNullishOr(firstStatement?.leadingComments), isCommentArray);
4874
4660
  }
4875
4661
  function commentedHeader(leadingComments, header) {
4876
4662
  const cloned = cloneNode(Option.getOrThrowWith(Option.fromNullishOr(header[0]), () => /* @__PURE__ */ new Error("Instrumentation header is empty")));
@@ -4913,7 +4699,7 @@ function isMap(value) {
4913
4699
  function isSet(value) {
4914
4700
  return value instanceof Set;
4915
4701
  }
4916
- async function transform(ast, mutantCollector, transformerContext) {
4702
+ const transform = (ast, mutantCollector, transformerContext) => {
4917
4703
  const context = {
4918
4704
  ...transformerContext,
4919
4705
  transform
@@ -4925,32 +4711,27 @@ async function transform(ast, mutantCollector, transformerContext) {
4925
4711
  case "tsx": return transformScript(ast, mutantCollector, context);
4926
4712
  case "svelte": return transformSvelte(ast, mutantCollector, context);
4927
4713
  }
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
4714
  };
4715
+ const transformHtml = ({ root }, mutantCollector, context) => Effect.map(Effect.forEach(root.scripts, (script) => context.transform(script, mutantCollector, context)), (perScript) => perScript.flat());
4934
4716
  const moduleScript = `<script context="module">
4935
4717
  \n<\/script>\n`;
4936
- const transformSvelte = async (svelte, mutantCollector, context) => {
4937
- const warnings = [];
4718
+ const transformSvelte = (svelte, mutantCollector, context) => Effect.gen(function* () {
4938
4719
  const { root } = svelte;
4939
4720
  const scripts = [root.moduleScript, ...root.additionalScripts].filter(Predicate.isNotNullish);
4940
- for (const script of scripts) warnings.push(...await context.transform(script.ast, mutantCollector, {
4721
+ const warnings = (yield* Effect.forEach(scripts, (script) => context.transform(script.ast, mutantCollector, {
4941
4722
  ...context,
4942
4723
  options: {
4943
4724
  ...context.options,
4944
4725
  noHeader: true
4945
4726
  }
4946
- }));
4947
- await placeModuleHeaderIfNeeded(svelte, mutantCollector);
4727
+ }))).flat();
4728
+ yield* placeModuleHeaderIfNeeded(svelte, mutantCollector);
4948
4729
  return warnings;
4949
- };
4950
- async function placeModuleHeaderIfNeeded(svelte, mutantCollector) {
4951
- if (hasPlacedMutants(mutantCollector, svelte.originFileName)) await placeModuleHeader(svelte);
4952
- }
4953
- async function placeModuleHeader(svelte) {
4730
+ });
4731
+ const placeModuleHeaderIfNeeded = (svelte, mutantCollector) => Effect.gen(function* () {
4732
+ if (hasPlacedMutants(mutantCollector, svelte.originFileName)) yield* placeModuleHeader(svelte);
4733
+ });
4734
+ const placeModuleHeader = (svelte) => Effect.gen(function* () {
4954
4735
  const { root, originFileName } = svelte;
4955
4736
  if (!root.moduleScript) {
4956
4737
  root.moduleScript = {
@@ -4973,162 +4754,161 @@ async function placeModuleHeader(svelte) {
4973
4754
  script.range.end += moduleScript.length;
4974
4755
  });
4975
4756
  }
4976
- await placeHeader(root.moduleScript.ast.root);
4977
- }
4757
+ yield* placeHeader(root.moduleScript.ast.root);
4758
+ });
4978
4759
  function emptyProgram() {
4979
4760
  return {
4980
4761
  type: "Program",
4981
4762
  sourceType: "module",
4982
- body: []
4763
+ body: [],
4764
+ hashbang: null
4983
4765
  };
4984
4766
  }
4767
+ const emptyAppliedMutants = () => /* @__PURE__ */ new Map();
4985
4768
  function isMutateRangeList(value) {
4986
4769
  return Array.isArray(value);
4987
4770
  }
4988
- const transformScript = async ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription }, mutators, mutantPlacers) => {
4989
- const lineTable = buildLineTable(rawContent);
4990
- attachComments(root, comments, lineTable);
4771
+ const transformScript = ({ root, originFileName, rawContent, offset, comments }, mutantCollector, { options, mutateDescription, basePath }, mutators, mutantPlacers) => {
4991
4772
  const placementMap = /* @__PURE__ */ new Map();
4992
- let directiveRule = rootRule;
4993
- const mutatorEntries = Object.entries(Option.getOrElse(Option.fromNullishOr(mutators), () => allMutators));
4994
- const placers = Option.getOrElse(Option.fromNullishOr(mutantPlacers), () => allMutantPlacers);
4995
- const allMutatorNames = mutatorEntries.map(([name]) => name.toLowerCase());
4996
- const warnings = [];
4997
- traverse(root, {
4998
- enter(path) {
4999
- const result = processStrykerDirectives(directiveRule, path.node, allMutatorNames, originFileName);
5000
- directiveRule = result.rule;
5001
- warnings.push(...result.warnings);
5002
- visitNode(path);
5003
- },
5004
- exit(path) {
5005
- const placement = placementMap.get(path.node);
5006
- if (hasAppliedMutants(placement)) applyPlacement(path, placement);
4773
+ return Effect.gen(function* () {
4774
+ const lineTable = buildLineTable(rawContent);
4775
+ attachComments(root, comments, lineTable);
4776
+ let directiveRule = rootRule;
4777
+ const mutatorEntries = Object.entries(Option.getOrElse(Option.fromNullishOr(mutators), () => allMutators));
4778
+ const placers = Option.getOrElse(Option.fromNullishOr(mutantPlacers), () => allMutantPlacers);
4779
+ const allMutatorNames = mutatorEntries.map(([name]) => name.toLowerCase());
4780
+ const warnings = [];
4781
+ traverse(root, {
4782
+ enter(path) {
4783
+ const result = processStrykerDirectives(directiveRule, path.node, allMutatorNames, originFileName);
4784
+ directiveRule = result.rule;
4785
+ warnings.push(...result.warnings);
4786
+ visitNode(path);
4787
+ },
4788
+ exit(path) {
4789
+ const placement = placementMap.get(path.node);
4790
+ if (hasAppliedMutants(placement)) applyPlacement(path, placement);
4791
+ }
4792
+ });
4793
+ yield* placeHeaderIfNeeded(mutantCollector, originFileName, options, root);
4794
+ return warnings;
4795
+ function visitNode(path) {
4796
+ if (shouldSkip(path)) {
4797
+ path.skip();
4798
+ return;
4799
+ }
4800
+ addToPlacementMapIfPossible(path);
4801
+ placeCollectedMutantsIfMutating(path);
5007
4802
  }
5008
- });
5009
- await placeHeaderIfNeeded(mutantCollector, originFileName, options, root);
5010
- return warnings;
5011
- function visitNode(path) {
5012
- if (shouldSkip(path)) {
5013
- path.skip();
5014
- return;
4803
+ function addToPlacementMapIfPossible(path) {
4804
+ const placer = placers.find((candidate) => candidate.canPlace(path));
4805
+ if (placer !== void 0) placementMap.set(path.node, {
4806
+ appliedMutants: emptyAppliedMutants(),
4807
+ placer
4808
+ });
5015
4809
  }
5016
- addToPlacementMapIfPossible(path);
5017
- placeCollectedMutantsIfMutating(path);
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);
4810
+ function hasAppliedMutants(placement) {
4811
+ return placement !== void 0 && placement.appliedMutants.size > 0;
5035
4812
  }
5036
- }
5037
- function placeCollectedMutantsIfMutating(path) {
5038
- if (shouldMutate(path)) placeCollectedMutants(path);
5039
- }
5040
- function placeCollectedMutants(path) {
5041
- const mutantsToPlace = collectMutants(path);
5042
- if (mutantsToPlace.length === 0) return;
5043
- const placementPath = requiredPlacementPath(path, mutantsToPlace);
5044
- const placement = requiredPlacement(placementPath.node);
5045
- mutantsToPlace.forEach((mutant) => {
5046
- placement.appliedMutants.set(mutant, applyMutant(mutant, placementPath.node));
5047
- });
5048
- }
5049
- function requiredPlacementPath(path, mutantsToPlace) {
5050
- return Option.getOrThrowWith(Option.fromNullishOr(path.find((ancestor) => placementMap.has(ancestor.node))), () => unplacedMutantsError(mutantsToPlace));
5051
- }
5052
- function unplacedMutantsError(mutantsToPlace) {
5053
- return /* @__PURE__ */ new Error(`Mutants cannot be placed. This shouldn't happen! Unplaced mutants: ${JSON.stringify(mutantsToPlace, null, 2)}`);
5054
- }
5055
- function requiredPlacement(node) {
5056
- return Option.getOrThrowWith(Option.fromNullishOr(placementMap.get(node)), () => /* @__PURE__ */ new Error("Placement not found for node"));
5057
- }
5058
- function shouldSkip(path) {
5059
- return [
5060
- isTypeNode(path),
5061
- isImportDeclaration(path),
5062
- nodeType(path.node) === "Decorator",
5063
- mutateDescription === false,
5064
- isOutsideMutateRanges(path)
5065
- ].some((skip) => skip);
5066
- }
5067
- function mutateRanges() {
5068
- return Option.filter(Option.some(mutateDescription), isMutateRangeList);
5069
- }
5070
- function isOutsideMutateRanges(path) {
5071
- return Option.exists(mutateRanges(), (ranges) => ranges.every((range) => !locationOverlaps(range, getNodeLocation(path.node))));
5072
- }
5073
- function shouldMutate(path) {
5074
- return mutateDescription === true || isInsideMutateRanges(path);
5075
- }
5076
- function isInsideMutateRanges(path) {
5077
- return Option.exists(mutateRanges(), (ranges) => ranges.some((range) => locationIncluded(range, getNodeLocation(path.node))));
5078
- }
5079
- function getNodeLocation(node) {
5080
- const span = spanOf(node);
5081
- if (span === void 0) throw new Error("Node without a span");
5082
- return {
5083
- start: positionFromLineTable(span.start, lineTable),
5084
- end: positionFromLineTable(span.end, lineTable)
5085
- };
5086
- }
5087
- function ignoreMessageFor(path) {
5088
- return Option.getOrUndefined(ignorerReason(toIgnorerPath(path)));
5089
- }
5090
- function ignorerReason(view) {
5091
- return options.ignorers.reduce((reason, ignorer) => Option.orElse(reason, () => ignorer.shouldIgnore(view)), Option.none());
5092
- }
5093
- function collectMutants(path) {
5094
- return mutablesFor(path).map((mutable) => collect(mutantCollector, originFileName, path.node, mutable, offset, lineTable)).filter((mutant) => mutant.ignoreReason === void 0);
5095
- }
5096
- function mutablesFor(path) {
5097
- const context = toMutatorContext(path);
5098
- const line = getNodeLocation(path.node).start.line;
5099
- return mutatorEntries.flatMap(([mutatorName, mutate]) => [...mutate(path.node, context)].map((replacement) => mutableFor(path, mutatorName, replacement, line)));
5100
- }
5101
- function mutableFor(path, mutatorName, replacement, line) {
5102
- const mutableEntry = {
5103
- replacement,
5104
- mutatorName
5105
- };
5106
- const ignoreReason = ignoreReasonFor(path, mutatorName, line);
5107
- if (ignoreReason !== void 0) mutableEntry.ignoreReason = ignoreReason;
5108
- return mutableEntry;
5109
- }
5110
- function ignoreReasonFor(path, mutatorName, line) {
5111
- return directiveOrExclusion(mutatorName, line) ?? ignoreMessageFor(path);
5112
- }
5113
- function directiveOrExclusion(mutatorName, line) {
5114
- return findIgnoreReason(directiveRule, mutatorName, line) ?? findExcludedMutatorIgnoreReason(mutatorName);
5115
- }
5116
- function findExcludedMutatorIgnoreReason(mutatorName) {
5117
- if (options.excludedMutations.includes(mutatorName)) return `Ignored because of excluded mutation "${mutatorName}"`;
5118
- else return;
5119
- }
4813
+ function applyPlacement(path, placement) {
4814
+ try {
4815
+ placement.placer.place(path, placement.appliedMutants);
4816
+ path.skip();
4817
+ } catch (error) {
4818
+ throwPlacementError(toError(error), path, placement.placer, [...placement.appliedMutants.keys()], originFileName, lineTable, basePath);
4819
+ }
4820
+ }
4821
+ function placeCollectedMutantsIfMutating(path) {
4822
+ if (shouldMutate(path)) placeCollectedMutants(path);
4823
+ }
4824
+ function placeCollectedMutants(path) {
4825
+ const mutantsToPlace = collectMutants(path);
4826
+ if (mutantsToPlace.length === 0) return;
4827
+ const placementPath = requiredPlacementPath(path, mutantsToPlace);
4828
+ const placement = requiredPlacement(placementPath.node);
4829
+ mutantsToPlace.forEach((mutant) => {
4830
+ placement.appliedMutants.set(mutant, applyMutant(mutant, placementPath.node));
4831
+ });
4832
+ }
4833
+ function requiredPlacementPath(path, mutantsToPlace) {
4834
+ return Option.getOrThrowWith(Option.fromNullishOr(path.find((ancestor) => placementMap.has(ancestor.node))), () => unplacedMutantsError(mutantsToPlace));
4835
+ }
4836
+ function unplacedMutantsError(mutantsToPlace) {
4837
+ return /* @__PURE__ */ new Error(`Mutants cannot be placed. This shouldn't happen! Unplaced mutants: ${JSON.stringify(mutantsToPlace, null, 2)}`);
4838
+ }
4839
+ function requiredPlacement(node) {
4840
+ return Option.getOrThrowWith(Option.fromNullishOr(placementMap.get(node)), () => /* @__PURE__ */ new Error("Placement not found for node"));
4841
+ }
4842
+ function shouldSkip(path) {
4843
+ return [
4844
+ isTypeNode(path),
4845
+ isImportDeclaration(path),
4846
+ nodeType(path.node) === "Decorator",
4847
+ mutateDescription === false,
4848
+ isOutsideMutateRanges(path)
4849
+ ].some((skip) => skip);
4850
+ }
4851
+ function mutateRanges() {
4852
+ return Option.filter(Option.some(mutateDescription), isMutateRangeList);
4853
+ }
4854
+ function isOutsideMutateRanges(path) {
4855
+ return Option.exists(mutateRanges(), (ranges) => ranges.every((range) => !locationOverlaps(range, getNodeLocation(path.node))));
4856
+ }
4857
+ function shouldMutate(path) {
4858
+ return mutateDescription === true || isInsideMutateRanges(path);
4859
+ }
4860
+ function isInsideMutateRanges(path) {
4861
+ return Option.exists(mutateRanges(), (ranges) => ranges.some((range) => locationIncluded(range, getNodeLocation(path.node))));
4862
+ }
4863
+ function getNodeLocation(node) {
4864
+ const span = spanOf(node);
4865
+ if (span === void 0) throw new Error("Node without a span");
4866
+ return {
4867
+ start: positionFromLineTable(span.start, lineTable),
4868
+ end: positionFromLineTable(span.end, lineTable)
4869
+ };
4870
+ }
4871
+ function ignoreMessageFor(node, ancestors) {
4872
+ return ignorerReason(node, ancestors);
4873
+ }
4874
+ function ignorerReason(node, ancestors) {
4875
+ return options.ignorers.map((ignorer) => ignorer.shouldIgnore(node, ancestors)).find((reason) => reason !== void 0);
4876
+ }
4877
+ function collectMutants(path) {
4878
+ return mutablesFor(path).map((mutable) => collect(mutantCollector, originFileName, path.node, mutable, offset, lineTable)).filter((mutant) => mutant.ignoreReason === void 0);
4879
+ }
4880
+ function mutablesFor(path) {
4881
+ const ancestors = ancestorsOf(path);
4882
+ const context = toMutatorContext(ancestors);
4883
+ const line = getNodeLocation(path.node).start.line;
4884
+ return mutatorEntries.flatMap(([mutatorName, mutate]) => [...mutate(path.node, context)].map((replacement) => mutableFor(path.node, ancestors, mutatorName, replacement, line)));
4885
+ }
4886
+ function mutableFor(node, ancestors, mutatorName, replacement, line) {
4887
+ const mutableEntry = {
4888
+ replacement,
4889
+ mutatorName
4890
+ };
4891
+ const ignoreReason = ignoreReasonFor(node, ancestors, mutatorName, line);
4892
+ if (ignoreReason !== void 0) mutableEntry.ignoreReason = ignoreReason;
4893
+ return mutableEntry;
4894
+ }
4895
+ function ignoreReasonFor(node, ancestors, mutatorName, line) {
4896
+ return directiveOrExclusion(mutatorName, line) ?? ignoreMessageFor(node, ancestors);
4897
+ }
4898
+ function directiveOrExclusion(mutatorName, line) {
4899
+ return findIgnoreReason(directiveRule, mutatorName, line) ?? findExcludedMutatorIgnoreReason(mutatorName);
4900
+ }
4901
+ function findExcludedMutatorIgnoreReason(mutatorName) {
4902
+ if (options.excludedMutations.includes(mutatorName)) return `Ignored because of excluded mutation "${mutatorName}"`;
4903
+ else return;
4904
+ }
4905
+ });
5120
4906
  };
5121
- function toMutatorContext(path) {
5122
- const ancestors = [];
5123
- let current = path.parentPath;
5124
- while (current !== null) {
5125
- ancestors.push(current.node);
5126
- current = current.parentPath;
5127
- }
4907
+ function toMutatorContext(ancestors) {
5128
4908
  return {
5129
4909
  parent: ancestors[0],
5130
4910
  grandParent: ancestors[1],
5131
- ancestors
4911
+ ancestors: [...ancestors]
5132
4912
  };
5133
4913
  }
5134
4914
  function toError(value) {
@@ -5140,18 +4920,22 @@ function toError(value) {
5140
4920
  const commentDirectiveRegEx = /^(\s*)@(ts-[a-z-]+).*$/;
5141
4921
  const tsDirectiveLikeRegEx = /@(ts-[a-z-]+)/;
5142
4922
  const STARTING_COMMENT = /^\s*\/\*[\s\S]*?\*\//;
5143
- async function disableTypeChecks(file) {
4923
+ const disableTypeChecks = (file) => {
5144
4924
  const format = getFormat(file.name);
5145
- if (format === void 0) return file;
4925
+ if (format === void 0) return Effect.succeed(file);
5146
4926
  return disableTypeChecksFor(file, format);
5147
- }
5148
- async function disableTypeChecksFor(file, format) {
5149
- if (isJSFileWithoutTSDirectives(file, format)) return {
4927
+ };
4928
+ const disableTypeChecksFor = (file, format) => {
4929
+ if (isJSFileWithoutTSDirectives(file, format)) return Effect.succeed({
5150
4930
  ...file,
5151
4931
  content: prefixWithNoCheck(file.content)
5152
- };
5153
- return withDisabledTypeChecking(file, await createParser()(file.content, file.name));
5154
- }
4932
+ });
4933
+ const parse = createParser();
4934
+ return Effect.map(parse(file.content, file.name).pipe(Effect.mapError((cause) => InstrumentError.make({
4935
+ message: `Failed to parse ${file.name}`,
4936
+ cause
4937
+ }))), (ast) => withDisabledTypeChecking(file, ast));
4938
+ };
5155
4939
  function withDisabledTypeChecking(file, ast) {
5156
4940
  switch (ast.format) {
5157
4941
  case "js":
@@ -5276,13 +5060,13 @@ function toOneBasedLineNumber(range) {
5276
5060
  }
5277
5061
  }));
5278
5062
  }
5279
- function isIgnorerService(value) {
5063
+ function isIgnorer(value) {
5280
5064
  return Predicate.isObject(value) && typeof value["shouldIgnore"] === "function";
5281
5065
  }
5282
5066
  function toTransformerOptions(options) {
5283
5067
  const base = {
5284
5068
  excludedMutations: [...options.excludedMutations],
5285
- ignorers: options.ignorers.filter(isIgnorerService)
5069
+ ignorers: options.ignorers.filter(isIgnorer)
5286
5070
  };
5287
5071
  if (options.noHeader !== void 0) return {
5288
5072
  ...base,
@@ -5294,54 +5078,6 @@ const AST_SHAPE = ["format", "root"];
5294
5078
  function isAst(value) {
5295
5079
  return Predicate.isObject(value) && AST_SHAPE.every((key) => key in value);
5296
5080
  }
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
5081
  function printedFile(file, ast) {
5346
5082
  if (!isAst(ast)) return [];
5347
5083
  return [{
@@ -5350,28 +5086,47 @@ function printedFile(file, ast) {
5350
5086
  content: print(ast)
5351
5087
  }];
5352
5088
  }
5353
- const decideInstrument = (decoded) => InstrumentDecision.make({
5354
- files: decoded.files,
5355
- mutants: decoded.mutants,
5356
- asts: decoded.asts
5357
- });
5358
- const instrument = (files, options) => Effect.gen(function* () {
5089
+ const instrument = (files, options, basePath) => Effect.gen(function* () {
5359
5090
  const schemaFiles = files.map((file) => ({
5360
5091
  name: file.name,
5361
5092
  content: file.content,
5362
5093
  mutate: file.mutate
5363
5094
  }));
5364
- const collected = yield* readCollected(InstrumentCommand.make({
5365
- files: schemaFiles,
5366
- options
5367
- }));
5368
- const decision = decideInstrument(InstrumentDecoded.make({
5369
- files: collected.files,
5370
- options: collected.options,
5371
- asts: collected.asts,
5372
- mutants: collected.mutants
5373
- }));
5374
- return yield* printDecision(decision);
5095
+ const parse = createParser();
5096
+ const parsed = yield* Effect.forEach(schemaFiles, (file) => Effect.map(parse(file.content, file.name).pipe(Effect.mapError((cause) => InstrumentError.make({
5097
+ message: `Failed to parse ${file.name}`,
5098
+ cause
5099
+ }))), (ast) => ({
5100
+ file,
5101
+ ast
5102
+ })));
5103
+ const collector = createMutantCollector();
5104
+ yield* Effect.forEach(parsed, ({ file, ast }) => transform(ast, collector, {
5105
+ options: toTransformerOptions(options),
5106
+ mutateDescription: toOneBasedLineNumber(file.mutate),
5107
+ basePath
5108
+ }).pipe(Effect.mapError((cause) => InstrumentError.make({
5109
+ message: `Failed to transform ${file.name}`,
5110
+ cause
5111
+ }))));
5112
+ const mutants = yield* Effect.try({
5113
+ try: () => collector.map(toApiMutant),
5114
+ catch: (cause) => InstrumentError.make({
5115
+ message: "Failed to instrument",
5116
+ cause
5117
+ })
5118
+ });
5119
+ const printed = yield* Effect.try({
5120
+ try: () => parsed.flatMap(({ file, ast }) => printedFile(file, ast)),
5121
+ catch: (cause) => InstrumentError.make({
5122
+ message: "Failed to print",
5123
+ cause
5124
+ })
5125
+ });
5126
+ return InstrumentResult.make({
5127
+ files: printed,
5128
+ mutants
5129
+ });
5375
5130
  });
5376
5131
  //#endregion
5377
- export { angularIgnorer, disableTypeChecks, frameworkPluginsFileUrl, instrument, strykerPlugins };
5132
+ export { ERROR_CODES, INSTRUMENTER_CONSTANTS, InstrumenterOptionsSchema, LocationSchema, Mutant, MutantActivationSchema, MutantRunOptionsSchema, MutantStatusSchema, OpenEndLocationSchema, PositionSchema, RunOptionsFields, causeText, disableTypeChecks, errorToString, instrument, isErrnoException, isMutant, normalizeFileName };