@systemfsoftware/stryker-js-instrumenter 6.0.1 → 7.0.0

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