@systemfsoftware/stryker-js-instrumenter 6.0.0 → 7.0.0

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