@mark1russell7/rigor-mutation 0.1.7 → 0.1.8

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/README.md CHANGED
@@ -77,7 +77,7 @@ A run of mutation tests is long and it uses much memory. Start it in CI, and on
77
77
  Two options make a run shorter:
78
78
 
79
79
  - `config --dry-run` gives a config that starts only the tests without mutants. Stryker does not stop at the first failed test. Use it to see if the tests pass under Stryker before a long run.
80
- - `--changed <file>` reads a file with one changed path on each line, from the folder of the lane file. Make the file with `git diff --name-only`. Then `list --runs` gives only the runs with a changed file, and `config` mutates only the changed files of the selection. `config` fails for a selection with no changed file.
80
+ - `--changed <file>` reads a file with one changed path on each line, from the folder of the lane file. Make the file with `git diff --name-only`. Then `list --runs` gives only the runs with a changed file, and `config` mutates only the changed files of the selection. A changed test file, for example `src/a.test.ts`, selects its source file `src/a.ts` when the selection takes it. `config` fails for a selection with no changed file.
81
81
 
82
82
  ## The score
83
83
 
@@ -98,6 +98,12 @@ A selection fails in these conditions:
98
98
 
99
99
  The gate of a package with parts applies to each part. Each part must have a score at the gate or above it. A part under the gate fails, also when the score of all the parts together is above the gate.
100
100
 
101
+ With `"gateOver": "package"`, the gate reads all the parts together. `scores` sums the mutants of the parts of the package, and gives one more line for the package. A part has no gate of its own, but a part that fails for another reason makes the package a no read.
102
+
103
+ - Give `scores` all the parts in one command, so that the sum reads each part. `--reports <dir>` reads `<dir>/mutation-<selection>/mutation.json` for each selection.
104
+ - A read of some of the parts only makes the package a no read, and its line names the missing parts. A run of the changed files is usually report only, so this does not fail it.
105
+ - `--alone` gives no line for the package. The job of one part uses it, and the part then fails only for a no read.
106
+
101
107
  ## The tests that a run read
102
108
 
103
109
  A score is a read of the tests only when the run read all of them. A run that read half of the tests gives a score with no meaning. Two options of `scores` find such a run. They need the field `testFiles` of the report, which the Vitest runner gives.
package/build/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as runCli } from "./run-DmIghD19.js";
2
+ import { n as runCli } from "./run-DhfS-8gc.js";
3
3
  // src/cli.ts
4
4
  try {
5
5
  process.exitCode = runCli(process.argv.slice(2), {
package/build/index.d.ts CHANGED
@@ -19,6 +19,11 @@ interface PackageLane {
19
19
  readonly parts?: Readonly<Record<string, readonly string[]>>;
20
20
  /** This field gives the lowest mutation score in percent that passes. Without a gate, the lane only reports the score. */
21
21
  readonly gate?: number;
22
+ /**
23
+ * This field tells what the gate of a package with parts reads. With `part`, the default, each part must have a score
24
+ * at the gate. With `package`, the sum of the mutants of the parts must have a score at the gate.
25
+ */
26
+ readonly gateOver?: "part" | "package";
22
27
  /** This field gives the Vitest config file, from `dir`. Without it, Vitest finds its config in `dir`. */
23
28
  readonly vitestConfig?: string;
24
29
  /**
@@ -85,10 +90,12 @@ export declare function select(lane: Lane, name: string): Selection;
85
90
  /**
86
91
  * This function gives the changed files of a selection, from the folder of its package. The globs of the selection
87
92
  * select the files. A file that the selection takes in line ranges gives one entry for each range, `src/a.ts:1-300`.
93
+ * A changed test file gives its source file of the same name, when the selection takes it and `exists` finds it.
88
94
  *
89
95
  * @param changed - the changed paths, from the folder of the lane file, with `/`
96
+ * @param exists - this function tells if a file, from the folder of the package, exists. The default finds each file.
90
97
  */
91
- export declare function changedFiles(selection: Selection, changed: readonly string[]): string[];
98
+ export declare function changedFiles(selection: Selection, changed: readonly string[], exists?: (file: string) => boolean): string[];
92
99
  /**
93
100
  * This function examines the parts of a package against its files. It gives an error for each file of `mutate` in no
94
101
  * part. It also gives an error for each file in two parts, and for each file of a part that is not in `mutate`. A
@@ -253,6 +260,14 @@ export declare function scoreReport(report: MutationReport, selection: {
253
260
  readonly name: string;
254
261
  readonly gate: number | undefined;
255
262
  }): Score;
263
+ /**
264
+ * This function gives the score of a package from the scores of its parts, and applies the gate of the package. It sums
265
+ * the mutants of the parts. A part that fails makes the package a no read: a part has no gate of its own here.
266
+ * A missing part also makes the package a no read, because the sum does not count its mutants.
267
+ *
268
+ * @param missing - the parts of the package that have no score in this read
269
+ */
270
+ export declare function packageScore(name: string, gate: number | undefined, parts: readonly Score[], missing?: readonly string[]): Score;
256
271
  /** This function gives one line for a score, with the name of the selection and its result. The time-outs are in it when the report has some. */
257
272
  export declare function formatScore(s: Score): string;
258
273
  /** This function gives a Markdown table of scores, for the summary of a CI job. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/lane.ts","../src/config.ts","../src/score.ts","../src/disables.ts","../src/load.ts","../src/run.ts"],"mappings":";;;;;UAQiB;;WAEN;;;;;WAKA;;;;;;WAMA,QAAQ,SAAS;;WAEjB;;WAEA;;;;;WAKA;;WAEA;;;;;WAKA,UAAU,SAAS;;;;;WAKnB,UAAU,SAAS;;;qBAIjB;;UAGI;WACN,UAAU,SAAS,eAAe;;WAElC;;;;;WAKA;;WAEA,eAAe,SAAS;;;UAOlB;WACN;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,SAAS,SAAS;;;;;;;wBAsDb,UAAU,gBAAgB;;wBAkB1B,eAAe,MAAM;;wBAKrB,cAAc,MAAM;;;;;;wBASpB,OAAO,MAAM,MAAM,eAAe;;;;;;;wBA+DlC,aAAa,WAAW,WAAW;;;;;;;;;;;;wBA4CnC,WAAW,MAAM,MAAM,aAAa,0BAA0B,SAAS;;UCzQtE;;WAEN;;WAEA;;;;;WAKA;;;;;WAKA;;;UAIM;;WAEN;WACA;WACA;aAAoB;;WACpB;WACA;WACA;WACA;aAAyB;;WACzB;aAAyB;;WACzB;aAAuB;aAAuB;aAAsB;;WACpE;WACA;WACA;WACA;WACA;WACA;;;qBAIE;;;;;qBAMA;;;;;qBAMA;;;;;;wBAOG,iBAAiB;;qBAKpB;;;;;;wBAOG,cAAc,WAAW,WAAW,UAAS,gBAAqB;;;;;;;;;;UC9DjE;WACN;WACA;;WAEA;WACA;aAAqB;eAAkB;;;;;UAIjC;WACN,OAAO,SAAS;aAA0B,kBAAkB;;;WAE5D,YAAY,SAAS;aAA0B;eAA2B;;;;;;;;KAOzE;;UAGK;WACN;WACA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;;WAEA;;WAEA,UAAU;;;qBAMR,aAAc,GAAG;;;;;;wBAOd,YAAY,gBAAgB;;;;;;wBAkE5B,YAAY,QAAQ,gBAAgB;WAAsB;WAAuB;IAA6B;;wBA0C9G,YAAY,GAAG;;wBASf,gBAAgB,iBAAiB;;;;;;;UClLhC;WACN;WACA;;;UAIM;;WAEN;;WAEA;;WAEA,mBAAmB;WACnB;;;wBAIK,aAAa;WAA2B;WAAuB;MAAmB;;wBA+BlF,gBAAgB,gBAAgB,WAAW,iBAAiB,YAAY;;UC9CvE;;WAEN;;WAEA;;WAEA;;;UAIM;;WAEN;WACA;;;;;;;;wBAoBK,aAAa,cAAc;;;;;;;;;;wBAsC3B,aAAa,gBAAgB,eAAe,wBAAwB;;;;;;;;;wBAqCpE,iBAAiB,gBAAgB,eAAe,WAAW;;UCvG1D;WACN;WACA,SAAS;WACT,SAAS;;WAET,MAAM,SAAS;;;qBAIb;;wBAoSG,OAAO,yBAAyB,IAAI"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/lane.ts","../src/config.ts","../src/score.ts","../src/disables.ts","../src/load.ts","../src/run.ts"],"mappings":";;;;;UAQiB;;WAEN;;;;;WAKA;;;;;;WAMA,QAAQ,SAAS;;WAEjB;;;;;WAKA;;WAEA;;;;;WAKA;;WAEA;;;;;WAKA,UAAU,SAAS;;;;;WAKnB,UAAU,SAAS;;;qBAIjB;;UAGI;WACN,UAAU,SAAS,eAAe;;WAElC;;;;;WAKA;;WAEA,eAAe,SAAS;;;UAOlB;WACN;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,SAAS,SAAS;;;;;;;wBAyDb,UAAU,gBAAgB;;wBAkB1B,eAAe,MAAM;;wBAKrB,cAAc,MAAM;;;;;;wBASpB,OAAO,MAAM,MAAM,eAAe;;;;;;;;;wBAoElC,aAAa,WAAW,WAAW,4BAA4B,UAAS;;;;;;;;;;;;wBAkDxE,WAAW,MAAM,MAAM,aAAa,0BAA0B,SAAS;;UC5RtE;;WAEN;;WAEA;;;;;WAKA;;;;;WAKA;;;UAIM;;WAEN;WACA;WACA;aAAoB;;WACpB;WACA;WACA;WACA;aAAyB;;WACzB;aAAyB;;WACzB;aAAuB;aAAuB;aAAsB;;WACpE;WACA;WACA;WACA;WACA;WACA;;;qBAIE;;;;;qBAMA;;;;;qBAMA;;;;;;wBAOG,iBAAiB;;qBAKpB;;;;;;wBAOG,cAAc,WAAW,WAAW,UAAS,gBAAqB;;;;;;;;;;UC9DjE;WACN;WACA;;WAEA;WACA;aAAqB;eAAkB;;;;;UAIjC;WACN,OAAO,SAAS;aAA0B,kBAAkB;;;WAE5D,YAAY,SAAS;aAA0B;eAA2B;;;;;;;;KAOzE;;UAGK;WACN;WACA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;;WAEA;;WAEA,UAAU;;;qBAMR,aAAc,GAAG;;;;;;wBAOd,YAAY,gBAAgB;;;;;;wBAkE5B,YAAY,QAAQ,gBAAgB;WAAsB;WAAuB;IAA6B;;;;;;;;wBA4C9G,aAAa,cAAc,0BAA0B,gBAAgB,SAAS,8BAAkC;;wBA2BhH,YAAY,GAAG;;wBASf,gBAAgB,iBAAiB;;;;;;;UC/MhC;WACN;WACA;;;UAIM;;WAEN;;WAEA;;WAEA,mBAAmB;WACnB;;;wBAIK,aAAa;WAA2B;WAAuB;MAAmB;;wBA+BlF,gBAAgB,gBAAgB,WAAW,iBAAiB,YAAY;;UC9CvE;;WAEN;;WAEA;;WAEA;;;UAIM;;WAEN;WACA;;;;;;;;wBAoBK,aAAa,cAAc;;;;;;;;;;wBAsC3B,aAAa,gBAAgB,eAAe,wBAAwB;;;;;;;;;wBAqCpE,iBAAiB,gBAAgB,eAAe,WAAW;;UCvG1D;WACN;WACA,SAAS;WACT,SAAS;;WAET,MAAM,SAAS;;;qBAIb;;wBAuUG,OAAO,yBAAyB,IAAI"}
package/build/index.js CHANGED
@@ -1 +1 @@
1
- export { p as DRY_RUN_TIMEOUT_MINUTES, t as HELP, m as NO_TSCONFIG, h as REPORT_DIR, y as STRYKER_OWNED, g as TIMEOUT_MS, b as changedFiles, o as compareDisables, s as findDisables, c as formatScore, r as isConfigFile, l as isHitLimit, i as leavingPaths, x as parseLane, u as parseReport, S as partErrors, a as relatedTestFiles, _ as rewritesTsconfig, n as runCli, C as runSelections, d as scoreReport, w as select, T as selectionNames, v as strykerConfig, f as summaryMarkdown } from "./run-DmIghD19.js";
1
+ export { m as DRY_RUN_TIMEOUT_MINUTES, t as HELP, h as NO_TSCONFIG, g as REPORT_DIR, b as STRYKER_OWNED, _ as TIMEOUT_MS, x as changedFiles, o as compareDisables, s as findDisables, c as formatScore, r as isConfigFile, l as isHitLimit, i as leavingPaths, u as packageScore, S as parseLane, d as parseReport, C as partErrors, a as relatedTestFiles, v as rewritesTsconfig, n as runCli, w as runSelections, f as scoreReport, T as select, E as selectionNames, y as strykerConfig, p as summaryMarkdown } from "./run-DhfS-8gc.js";
@@ -26,6 +26,9 @@ function packageErrors(name, p) {
26
26
  if (!isGlobs(p["mutate"])) errors.push(`${name}: "mutate" is not a list of globs`);
27
27
  else if (p["mutate"].every((g) => g.startsWith("!"))) errors.push(`${name}: "mutate" has only "!" globs`);
28
28
  const gate = p["gate"];
29
+ const gateOver = p["gateOver"];
30
+ if (gateOver !== void 0 && gateOver !== "part" && gateOver !== "package") errors.push(`${name}: "gateOver" is not "part" or "package"`);
31
+ else if (gateOver === "package" && p["parts"] === void 0) errors.push(`${name}: "gateOver" is "package", but the package has no parts`);
29
32
  if (gate !== void 0 && (typeof gate !== "number" || !(gate >= 0 && gate <= 100))) errors.push(`${name}: "gate" is not a percent from 0 to 100`);
30
33
  if (p["vitestConfig"] !== void 0 && typeof p["vitestConfig"] !== "string") errors.push(`${name}: "vitestConfig" is not a file name`);
31
34
  for (const field of ["timeoutMS", "dryRunTimeoutMinutes"]) {
@@ -138,15 +141,25 @@ function coverOf(globs, file) {
138
141
  if (adds.some((g) => rangeOf(g) === void 0)) return "all";
139
142
  return adds.flatMap((g) => rangeOf(g) ?? []);
140
143
  }
144
+ /** A test file and its source file of the same name: `src/a.test.ts` tests `src/a.ts`. */
145
+ const TEST_FILE = /^(.+)\.(?:test|spec)(\.[^./]+)$/;
141
146
  /**
142
147
  * This function gives the changed files of a selection, from the folder of its package. The globs of the selection
143
148
  * select the files. A file that the selection takes in line ranges gives one entry for each range, `src/a.ts:1-300`.
149
+ * A changed test file gives its source file of the same name, when the selection takes it and `exists` finds it.
144
150
  *
145
151
  * @param changed - the changed paths, from the folder of the lane file, with `/`
152
+ * @param exists - this function tells if a file, from the folder of the package, exists. The default finds each file.
146
153
  */
147
- function changedFiles(selection, changed) {
154
+ function changedFiles(selection, changed, exists = () => true) {
148
155
  const dir = posix.normalize(selection.dir.replaceAll("\\", "/"));
149
- return changed.map((f) => posix.relative(dir, posix.normalize(f.replaceAll("\\", "/")))).filter((f) => f !== "" && !f.startsWith("../") && !posix.isAbsolute(f) && globsSelect(selection.mutate, f)).flatMap((f) => {
156
+ const sourceOf = (f) => {
157
+ if (globsSelect(selection.mutate, f)) return f;
158
+ const source = f.replace(TEST_FILE, "$1$2");
159
+ return source !== f && globsSelect(selection.mutate, source) && exists(source) ? source : void 0;
160
+ };
161
+ const files = changed.map((f) => posix.relative(dir, posix.normalize(f.replaceAll("\\", "/")))).flatMap((f) => f === "" || f.startsWith("../") || posix.isAbsolute(f) ? [] : sourceOf(f) ?? []);
162
+ return [...new Set(files)].flatMap((f) => {
150
163
  const cover = coverOf(selection.mutate, f);
151
164
  return cover === "all" ? [f] : cover.map((r) => `${f}${r.entry.slice(r.glob.length)}`);
152
165
  });
@@ -382,6 +395,39 @@ function scoreReport(report, selection) {
382
395
  outcome
383
396
  };
384
397
  }
398
+ /**
399
+ * This function gives the score of a package from the scores of its parts, and applies the gate of the package. It sums
400
+ * the mutants of the parts. A part that fails makes the package a no read: a part has no gate of its own here.
401
+ * A missing part also makes the package a no read, because the sum does not count its mutants.
402
+ *
403
+ * @param missing - the parts of the package that have no score in this read
404
+ */
405
+ function packageScore(name, gate, parts, missing = []) {
406
+ const sum = (count) => parts.reduce((total, s) => total + count(s), 0);
407
+ const detected = sum((s) => s.detected);
408
+ const valid = sum((s) => s.valid);
409
+ const clockTimeouts = sum((s) => s.clockTimeouts);
410
+ const percent = valid === 0 ? 0 : 100 * detected / valid;
411
+ const percentWithClock = valid === 0 ? 0 : 100 * (detected + clockTimeouts) / valid;
412
+ const failed = parts.filter((s) => !s.pass).map((s) => s.name);
413
+ const [outcome, reason] = parts.length === 0 ? ["no read", "the package has no scores of its parts"] : missing.length > 0 ? ["no read", `the read has no score of the parts ${missing.join(", ")}, so the sum does not count their mutants`] : failed.length > 0 ? ["no read", `the parts ${failed.join(", ")} fail, so the sum of the parts has no meaning`] : gate !== void 0 && percent < gate ? ["block", `the score ${percent.toFixed(2)} % of all the parts is under the gate ${String(gate)} %`] : ["pass", void 0];
414
+ const tests = parts.every((s) => s.tests !== void 0) ? sum((s) => s.tests ?? 0) : void 0;
415
+ return {
416
+ name,
417
+ gate,
418
+ detected,
419
+ hitLimit: sum((s) => s.hitLimit),
420
+ clockTimeouts,
421
+ valid,
422
+ survived: parts.flatMap((s) => s.survived),
423
+ percent,
424
+ percentWithClock,
425
+ tests,
426
+ pass: reason === void 0,
427
+ reason,
428
+ outcome
429
+ };
430
+ }
385
431
  /** This function gives the time-outs of a score as text: the count of each kind, and the score that counts the clock time-outs as detected. */
386
432
  const timeouts = (s) => `time-outs: ${String(s.hitLimit)} hit limit, ${String(s.clockTimeouts)} clock (${s.percentWithClock.toFixed(2)} % with the clock time-outs as detected)`;
387
433
  /** This function gives one line for a score, with the name of the selection and its result. The time-outs are in it when the report has some. */
@@ -577,10 +623,14 @@ const HELP = `rigor-mutation: the mutation tests of a repository, with Stryker a
577
623
  the Stryker config of a selection, as JSON. With --dry-run,
578
624
  Stryker starts only the tests. With --changed, it mutates only
579
625
  the changed files of the selection.
580
- rigor-mutation scores <selection>... [--report <file>] [--summary <file>] [--last <file>]
581
- [--write-last <file>] [--test-files]
626
+ rigor-mutation scores <selection>... [--report <file> | --reports <dir>] [--summary <file>]
627
+ [--last <file>] [--write-last <file>] [--test-files] [--alone]
582
628
  the score of each selection, with its gate and its count
583
- of tests. With --last, a fall of the count of more than
629
+ of tests. --reports reads <dir>/mutation-<selection>/mutation.json.
630
+ A package with "gateOver": "package" also gets
631
+ the score of its parts together, a no read without all its parts.
632
+ --alone gives no line for the package: the job of one part
633
+ then fails only for a no read. With --last, a fall of the count of more than
584
634
  maxTestFall % (default 20) against the file fails. With
585
635
  --write-last, the counts of the passed selections go in
586
636
  the file. With --test-files, a test file that the run
@@ -592,7 +642,8 @@ const HELP = `rigor-mutation: the mutation tests of a repository, with Stryker a
592
642
 
593
643
  --lane <file> the lane file. The default is mutation.json.
594
644
  --changed <file> a file with one changed path on each line, from the folder of the lane file,
595
- for example the output of git diff --name-only.
645
+ for example the output of git diff --name-only. A changed test file selects
646
+ its source file of the same name.
596
647
 
597
648
  A selection is a package ("collections") or a part of a package ("collections.impl").
598
649
  Each file of a package with parts must be in exactly one part. list --runs, and config and scores
@@ -665,6 +716,8 @@ function typescriptMajor(dir) {
665
716
  */
666
717
  /** This function gives the number of lines of a text. A last line break does not start a line. */
667
718
  const lineCount = (text) => text === "" ? 0 : text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
719
+ /** This function tells if a file of the package of a selection, from its folder, exists. */
720
+ const existsIn = (laneDir, s) => (file) => existsSync(resolve(laneDir, s.dir, file));
668
721
  function checkParts(lane, laneDir, pkgs) {
669
722
  const errors = pkgs.flatMap((pkg) => {
670
723
  const p = lane.packages[pkg];
@@ -713,6 +766,7 @@ function disables(lane, laneDir, write, io) {
713
766
  function scores(lane, laneDir, names, o, io) {
714
767
  if (names.length === 0) throw new Error(`"scores" takes one or more selections`);
715
768
  if (o.report !== void 0 && names.length > 1) throw new Error(`--report takes one selection`);
769
+ if (o.report !== void 0 && o.reports !== void 0) throw new Error(`"scores" takes --report or --reports, not both`);
716
770
  checkPartsOf(lane, laneDir, names);
717
771
  const lastFile = o.last === void 0 ? void 0 : resolve(io.cwd, o.last);
718
772
  const last = lastFile === void 0 || !existsSync(lastFile) ? {} : readCounts(lastFile);
@@ -721,9 +775,15 @@ function scores(lane, laneDir, names, o, io) {
721
775
  const notes = new Map(names.map((n) => [n, []]));
722
776
  const note = (name, line) => void notes.get(name)?.push(line);
723
777
  const falls = [];
778
+ const byPackage = (s) => s.name !== s.pkg && lane.packages[s.pkg]?.gateOver === "package";
724
779
  const results = names.map((name) => {
725
- const s = select(lane, name);
726
- const file = o.report === void 0 ? resolve(laneDir, s.dir, REPORT_DIR, "mutation.json") : resolve(io.cwd, o.report);
780
+ const all = select(lane, name);
781
+ const s = byPackage(all) ? {
782
+ ...all,
783
+ gate: void 0
784
+ } : all;
785
+ if (s !== all) note(name, ` the gate of ${s.pkg} reads all its parts together`);
786
+ const file = o.reports !== void 0 ? resolve(io.cwd, o.reports, `mutation-${name}`, "mutation.json") : o.report === void 0 ? resolve(laneDir, s.dir, REPORT_DIR, "mutation.json") : resolve(io.cwd, o.report);
727
787
  if (!existsSync(file)) {
728
788
  const reason = `the report ${relative(io.cwd, file)} does not exist`;
729
789
  return {
@@ -764,7 +824,15 @@ function scores(lane, laneDir, names, o, io) {
764
824
  if (o.testFiles) score = checkTestFiles(lane, laneDir, s, report, score, (line) => note(name, line));
765
825
  return score;
766
826
  });
767
- for (const s of results) {
827
+ const packages = o.alone === true ? [] : names.map((n) => select(lane, n)).filter(byPackage).map((s) => s.pkg);
828
+ const totals = [...new Set(packages)].map((pkg) => {
829
+ const p = lane.packages[pkg];
830
+ const parts = results.filter((r) => select(lane, r.name).pkg === pkg && r.name !== pkg);
831
+ const missing = Object.keys(p?.parts ?? {}).map((part) => `${pkg}.${part}`).filter((n) => !names.includes(n));
832
+ return packageScore(pkg, p?.gate, parts, missing);
833
+ });
834
+ const shown = [...results, ...totals];
835
+ for (const s of shown) {
768
836
  io.stdout(`${formatScore(s)}
769
837
  `);
770
838
  for (const line of notes.get(s.name) ?? []) io.stdout(`${line}
@@ -774,7 +842,7 @@ function scores(lane, laneDir, names, o, io) {
774
842
  }
775
843
  if (o.summary !== void 0) appendFileSync(resolve(io.cwd, o.summary), `### Mutation scores
776
844
 
777
- ${summaryMarkdown(results)}
845
+ ${summaryMarkdown(shown)}
778
846
  `);
779
847
  if (o.writeLast !== void 0) {
780
848
  const out = resolve(io.cwd, o.writeLast);
@@ -784,9 +852,9 @@ ${summaryMarkdown(results)}
784
852
  writeFileSync(out, `${JSON.stringify(Object.fromEntries(Object.entries(counts).toSorted(([a], [b]) => a < b ? -1 : 1)), null, 2)}
785
853
  `);
786
854
  }
787
- if (io.env?.["GITHUB_ACTIONS"] === "true") for (const line of annotations(results, falls)) io.stdout(`${line}
855
+ if (io.env?.["GITHUB_ACTIONS"] === "true") for (const line of annotations(shown, falls)) io.stdout(`${line}
788
856
  `);
789
- const failed = results.filter((s) => !s.pass).map((s) => s.name);
857
+ const failed = shown.filter((s) => !s.pass).map((s) => s.name);
790
858
  if (failed.length > 0) io.stderr(`The gate failed for ${failed.join(", ")}.
791
859
  `);
792
860
  return failed.length > 0 ? 1 : 0;
@@ -854,6 +922,7 @@ function runCli(argv, io) {
854
922
  out: { type: "string" },
855
923
  concurrency: { type: "string" },
856
924
  report: { type: "string" },
925
+ reports: { type: "string" },
857
926
  summary: { type: "string" },
858
927
  write: {
859
928
  type: "boolean",
@@ -874,6 +943,10 @@ function runCli(argv, io) {
874
943
  type: "boolean",
875
944
  default: false
876
945
  },
946
+ alone: {
947
+ type: "boolean",
948
+ default: false
949
+ },
877
950
  help: {
878
951
  type: "boolean",
879
952
  default: false
@@ -898,7 +971,7 @@ function runCli(argv, io) {
898
971
  if (values.runs) checkParts(lane, laneDir, Object.keys(lane.packages));
899
972
  if (changed !== void 0 && !values.runs) throw new Error(`--changed of "list" takes --runs`);
900
973
  const runs = values.runs ? runSelections(lane) : selectionNames(lane);
901
- const shown = changed === void 0 ? runs : runs.filter((n) => changedFiles(select(lane, n), changed).length > 0);
974
+ const shown = changed === void 0 ? runs : runs.filter((n) => changedFiles(select(lane, n), changed, existsIn(laneDir, select(lane, n))).length > 0);
902
975
  io.stdout(shown.length === 0 ? "" : `${shown.join("\n")}\n`);
903
976
  return 0;
904
977
  }
@@ -910,7 +983,7 @@ function runCli(argv, io) {
910
983
  if (concurrency !== void 0 && !(Number.isInteger(concurrency) && concurrency > 0)) throw new Error(`--concurrency is not a positive integer`);
911
984
  checkPartsOf(lane, laneDir, [one()]);
912
985
  const all = select(lane, one());
913
- const files = changed === void 0 ? void 0 : changedFiles(all, changed);
986
+ const files = changed === void 0 ? void 0 : changedFiles(all, changed, existsIn(laneDir, all));
914
987
  if (files?.length === 0) throw new Error(`the selection ${all.name} has no changed file`);
915
988
  const selection = files === void 0 ? all : {
916
989
  ...all,
@@ -932,10 +1005,12 @@ function runCli(argv, io) {
932
1005
  }
933
1006
  case "scores": return scores(lane, laneDir, names, {
934
1007
  report: values.report,
1008
+ reports: values.reports,
935
1009
  summary: values.summary,
936
1010
  last: values.last,
937
1011
  writeLast: values["write-last"],
938
- testFiles: values["test-files"]
1012
+ testFiles: values["test-files"],
1013
+ alone: values.alone
939
1014
  }, io);
940
1015
  case "disables": return disables(lane, laneDir, values.write, io);
941
1016
  case "load-check": return loadCheck(lane, laneDir, names, io);
@@ -944,6 +1019,6 @@ function runCli(argv, io) {
944
1019
  return 1;
945
1020
  }
946
1021
  }
947
- export { runSelections as C, partErrors as S, selectionNames as T, rewritesTsconfig as _, relatedTestFiles as a, changedFiles as b, formatScore as c, scoreReport as d, summaryMarkdown as f, TIMEOUT_MS as g, REPORT_DIR as h, leavingPaths as i, isHitLimit as l, NO_TSCONFIG as m, runCli as n, compareDisables as o, DRY_RUN_TIMEOUT_MINUTES as p, isConfigFile as r, findDisables as s, HELP as t, parseReport as u, strykerConfig as v, select as w, parseLane as x, STRYKER_OWNED as y };
1022
+ export { partErrors as C, selectionNames as E, parseLane as S, select as T, TIMEOUT_MS as _, relatedTestFiles as a, STRYKER_OWNED as b, formatScore as c, parseReport as d, scoreReport as f, REPORT_DIR as g, NO_TSCONFIG as h, leavingPaths as i, isHitLimit as l, DRY_RUN_TIMEOUT_MINUTES as m, runCli as n, compareDisables as o, summaryMarkdown as p, isConfigFile as r, findDisables as s, HELP as t, packageScore as u, rewritesTsconfig as v, runSelections as w, changedFiles as x, strykerConfig as y };
948
1023
 
949
- //# sourceMappingURL=run-DmIghD19.js.map
1024
+ //# sourceMappingURL=run-DhfS-8gc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-DhfS-8gc.js","names":["TEST"],"sources":["../src/lane.ts","../src/config.ts","../src/score.ts","../src/disables.ts","../src/load.ts","../src/run.ts"],"sourcesContent":["import { matchesGlob, posix } from \"node:path\";\n\n/**\n * The lane file of a repository (`mutation.json`) names the packages that the mutation tests mutate. A package has\n * its folder, its globs and an optional gate. A big package has parts, so that each part has its own runner.\n */\n\n/** The mutation tests of one package. */\nexport interface PackageLane {\n /** This field gives the folder of the package, from the folder of the lane file. Stryker starts in this folder. */\n readonly dir: string;\n /**\n * These globs give the files to mutate, from `dir`. A glob with `!` removes the files of the globs before it. A glob\n * with the suffix `:<from>-<to>` gives only those lines of its files, as Stryker reads it.\n */\n readonly mutate: readonly string[];\n /**\n * Each part has its own globs. The `!` globs of `mutate` also apply to each part. Each file of `mutate` must be in\n * exactly one part, so that a full run mutates each file one time. Line ranges can cut one file into parts: then the\n * ranges of the parts must cover each line of the file one time. `partErrors` examines this.\n */\n readonly parts?: Readonly<Record<string, readonly string[]>>;\n /** This field gives the lowest mutation score in percent that passes. Without a gate, the lane only reports the score. */\n readonly gate?: number;\n /**\n * This field tells what the gate of a package with parts reads. With `part`, the default, each part must have a score\n * at the gate. With `package`, the sum of the mutants of the parts must have a score at the gate.\n */\n readonly gateOver?: \"part\" | \"package\";\n /** This field gives the Vitest config file, from `dir`. Without it, Vitest finds its config in `dir`. */\n readonly vitestConfig?: string;\n /**\n * This field gives the time in milliseconds that the clock adds to the time of the tests for each mutant. The\n * default is 120000. A short time on a loaded runner stops mutants that the tests detect later.\n */\n readonly timeoutMS?: number;\n /** This field gives the time in minutes for the run of the tests without mutants. The default is 15. */\n readonly dryRunTimeoutMinutes?: number;\n /**\n * These options go into the Stryker config of each selection of the package, for example `ignoreStatic`. The lane\n * owns the keys of `STRYKER_OWNED`, so the field cannot have them.\n */\n readonly stryker?: Readonly<Record<string, unknown>>;\n /**\n * Each test file of this field is on the disk, and no report reads it. The value gives the reason. `scores\n * --test-files` fails for each other test file on the disk that the report does not read. The file is from `dir`.\n */\n readonly notRead?: Readonly<Record<string, string>>;\n}\n\n/** The keys of the Stryker config that the lane owns. The field `stryker` of a package cannot have them. */\nexport const STRYKER_OWNED: readonly string[] = [\"mutate\", \"thresholds\", \"jsonReporter\", \"htmlReporter\", \"timeoutMS\", \"dryRunTimeoutMinutes\"];\n\n/** The lane file: the packages of the mutation tests, and the list of the disabled mutants. */\nexport interface Lane {\n readonly packages: Readonly<Record<string, PackageLane>>;\n /** This field gives the list of the disabled mutants, from the folder of the lane file. The default is `mutation-disables.json`. */\n readonly disables?: string;\n /**\n * This field gives the highest fall of the test count in percent against the last good count. The default is 20.\n * `scores --last` fails a selection with a higher fall: the report did not read all the tests.\n */\n readonly maxTestFall?: number;\n /** Each selection of this field can have a higher fall of its test count. The value gives the reason. */\n readonly plannedFalls?: Readonly<Record<string, string>>;\n}\n\n/** The default of `maxTestFall` of the lane, in percent. */\nexport const MAX_TEST_FALL = 20;\n\n/** A selection is one Stryker run: a package (`collections`) or a part of a package (`collections.impl`). */\nexport interface Selection {\n readonly name: string;\n readonly pkg: string;\n readonly dir: string;\n readonly mutate: readonly string[];\n readonly gate: number | undefined;\n readonly vitestConfig: string | undefined;\n readonly timeoutMS: number | undefined;\n readonly dryRunTimeoutMinutes: number | undefined;\n readonly stryker: Readonly<Record<string, unknown>> | undefined;\n}\n\nconst NAME = /^[\\w-]+$/;\n\nconst isRecord = (x: unknown): x is Record<string, unknown> => typeof x === \"object\" && x !== null && !Array.isArray(x);\n\n/** This function tells if a value is an object of names, each with a reason that is not empty. */\nconst isReasons = (x: unknown): x is Record<string, string> => isRecord(x) && Object.values(x).every((r) => typeof r === \"string\" && r.trim() !== \"\");\n\nconst isGlobs = (x: unknown): x is string[] => Array.isArray(x) && x.length > 0 && x.every((g) => typeof g === \"string\" && g !== \"\");\n\n/** This function examines a package of the lane file. It gives the errors, with the name of the package. */\nfunction packageErrors(name: string, p: unknown): string[] {\n if (!NAME.test(name)) return [`the package name \"${name}\" has a character that is not a letter, a digit, \"_\" or \"-\"`];\n if (!isRecord(p)) return [`${name}: the package is not an object`];\n const errors: string[] = [];\n if (typeof p[\"dir\"] !== \"string\" || p[\"dir\"] === \"\") errors.push(`${name}: \"dir\" is not a folder name`);\n if (!isGlobs(p[\"mutate\"])) errors.push(`${name}: \"mutate\" is not a list of globs`);\n else if (p[\"mutate\"].every((g) => g.startsWith(\"!\"))) errors.push(`${name}: \"mutate\" has only \"!\" globs`);\n const gate = p[\"gate\"];\n const gateOver = p[\"gateOver\"];\n if (gateOver !== undefined && gateOver !== \"part\" && gateOver !== \"package\") errors.push(`${name}: \"gateOver\" is not \"part\" or \"package\"`);\n else if (gateOver === \"package\" && p[\"parts\"] === undefined) errors.push(`${name}: \"gateOver\" is \"package\", but the package has no parts`);\n if (gate !== undefined && (typeof gate !== \"number\" || !(gate >= 0 && gate <= 100))) errors.push(`${name}: \"gate\" is not a percent from 0 to 100`);\n if (p[\"vitestConfig\"] !== undefined && typeof p[\"vitestConfig\"] !== \"string\") errors.push(`${name}: \"vitestConfig\" is not a file name`);\n for (const field of [\"timeoutMS\", \"dryRunTimeoutMinutes\"]) {\n const v = p[field];\n if (v !== undefined && !(typeof v === \"number\" && Number.isInteger(v) && v > 0)) errors.push(`${name}: \"${field}\" is not a positive integer`);\n }\n const stryker = p[\"stryker\"];\n if (stryker !== undefined) {\n if (!isRecord(stryker)) errors.push(`${name}: \"stryker\" is not an object`);\n else {\n const owned = Object.keys(stryker).filter((k) => STRYKER_OWNED.includes(k));\n if (owned.length > 0) errors.push(`${name}: \"stryker\" has ${owned.map((k) => `\"${k}\"`).join(\", \")}, but the lane owns these keys`);\n }\n }\n if (p[\"notRead\"] !== undefined && !isReasons(p[\"notRead\"])) errors.push(`${name}: \"notRead\" is not an object of files, each with a reason`);\n const parts = p[\"parts\"];\n if (parts !== undefined) {\n if (!isRecord(parts) || Object.keys(parts).length === 0) errors.push(`${name}: \"parts\" is not an object with parts`);\n else {\n for (const [part, globs] of Object.entries(parts)) {\n if (!NAME.test(part)) errors.push(`${name}: the part name \"${part}\" has a character that is not a letter, a digit, \"_\" or \"-\"`);\n if (!isGlobs(globs) || globs.some((g) => g.startsWith(\"!\"))) errors.push(`${name}.${part}: the part is not a list of globs without \"!\"`);\n }\n }\n }\n return errors;\n}\n\n/**\n * This function examines the JSON of a lane file and gives the lane.\n *\n * @throws Error with each problem of the file\n */\nexport function parseLane(json: unknown): Lane {\n if (!isRecord(json) || !isRecord(json[\"packages\"])) throw new Error(`the lane has no object \"packages\"`);\n const errors = Object.entries(json[\"packages\"]).flatMap(([name, p]) => packageErrors(name, p));\n if (Object.keys(json[\"packages\"]).length === 0) errors.push(`the lane has no packages`);\n if (json[\"disables\"] !== undefined && typeof json[\"disables\"] !== \"string\") errors.push(`\"disables\" is not a file name`);\n const fall = json[\"maxTestFall\"];\n if (fall !== undefined && (typeof fall !== \"number\" || !(fall >= 0 && fall <= 100))) errors.push(`\"maxTestFall\" is not a percent from 0 to 100`);\n const planned = json[\"plannedFalls\"];\n if (planned !== undefined && !isReasons(planned)) errors.push(`\"plannedFalls\" is not an object of selections, each with a reason`);\n if (errors.length > 0) throw new Error(`the lane is not valid:\\n ${errors.join(\"\\n \")}`);\n const lane = json as unknown as Lane;\n const names = new Set(selectionNames(lane));\n const unknown = Object.keys(lane.plannedFalls ?? {}).filter((n) => !names.has(n));\n if (unknown.length > 0) throw new Error(`the lane is not valid:\\n \"plannedFalls\" names no selection of the lane: ${unknown.join(\", \")}`);\n return lane;\n}\n\n/** This function gives the names of all the selections of a lane: each package, then each part of the package. */\nexport function selectionNames(lane: Lane): string[] {\n return Object.entries(lane.packages).flatMap(([name, p]) => [name, ...Object.keys(p.parts ?? {}).map((part) => `${name}.${part}`)]);\n}\n\n/** This function gives the selections of a full run: the parts of each package with parts, else the package. Each file is in one run. */\nexport function runSelections(lane: Lane): string[] {\n return Object.entries(lane.packages).flatMap(([name, p]) => (p.parts === undefined ? [name] : Object.keys(p.parts).map((part) => `${name}.${part}`)));\n}\n\n/**\n * This function gives the selection of a name: a package, or a part of a package.\n *\n * @throws Error when the lane has no package or part of that name\n */\nexport function select(lane: Lane, name: string): Selection {\n const [pkg = \"\", part, ...rest] = name.split(\".\");\n const p = lane.packages[pkg];\n const globs = part === undefined ? undefined : p?.parts?.[part];\n if (p === undefined || rest.length > 0 || (part !== undefined && globs === undefined)) {\n throw new Error(`the lane has no package or part \"${name}\". It has: ${selectionNames(lane).join(\", \")}`);\n }\n // Stryker applies a \"!\" glob to the globs before it, so the \"!\" globs of the package go after the globs of the part.\n const mutate = globs === undefined ? p.mutate : [...globs, ...p.mutate.filter((g) => g.startsWith(\"!\"))];\n return { name, pkg, dir: p.dir, mutate, gate: p.gate, vitestConfig: p.vitestConfig, timeoutMS: p.timeoutMS, dryRunTimeoutMinutes: p.dryRunTimeoutMinutes, stryker: p.stryker };\n}\n\n/** A `mutate` entry with a range, as Stryker reads it: `src/a.ts:1-300`, or `src/a.ts:1:4-300:2` with columns. */\nconst RANGE = /^(.+?):(\\d+)(?::(\\d+))?-(\\d+)(?::(\\d+))?$/;\n\n/** This type is a `mutate` entry with a range of lines. */\ninterface LineRange {\n readonly entry: string;\n readonly glob: string;\n readonly from: number;\n readonly to: number;\n readonly columns: boolean;\n}\n\nfunction rangeOf(entry: string): LineRange | undefined {\n const m = RANGE.exec(entry);\n if (m?.[1] === undefined) return undefined;\n return { entry, glob: m[1], from: Number(m[2]), to: Number(m[4]), columns: m[3] !== undefined || m[5] !== undefined };\n}\n\n/** This function gives the glob of a `mutate` entry, with no range. */\nconst globOf = (entry: string): string => rangeOf(entry)?.glob ?? entry;\n\n/**\n * This function tells if globs select a file. It reads the globs as Stryker does. A glob adds its files. A glob with\n * `!` removes its files from the files of the globs before it. A glob with a line range selects its files.\n */\nexport function globsSelect(globs: readonly string[], file: string): boolean {\n let selected = false;\n for (const g of globs) {\n if (g.startsWith(\"!\")) {\n if (selected && matchesGlob(file, globOf(g.slice(1)))) selected = false;\n } else if (!selected && matchesGlob(file, globOf(g))) selected = true;\n }\n return selected;\n}\n\n/**\n * This function gives what globs select of a selected file. The value is \"all\" when a glob with no range selects the\n * file. Otherwise it is the line ranges of the file.\n */\nfunction coverOf(globs: readonly string[], file: string): \"all\" | LineRange[] {\n const adds = globs.filter((g) => !g.startsWith(\"!\") && matchesGlob(file, globOf(g)));\n if (adds.some((g) => rangeOf(g) === undefined)) return \"all\";\n return adds.flatMap((g) => rangeOf(g) ?? []);\n}\n\n/** A test file and its source file of the same name: `src/a.test.ts` tests `src/a.ts`. */\nconst TEST_FILE = /^(.+)\\.(?:test|spec)(\\.[^./]+)$/;\n\n/**\n * This function gives the changed files of a selection, from the folder of its package. The globs of the selection\n * select the files. A file that the selection takes in line ranges gives one entry for each range, `src/a.ts:1-300`.\n * A changed test file gives its source file of the same name, when the selection takes it and `exists` finds it.\n *\n * @param changed - the changed paths, from the folder of the lane file, with `/`\n * @param exists - this function tells if a file, from the folder of the package, exists. The default finds each file.\n */\nexport function changedFiles(selection: Selection, changed: readonly string[], exists: (file: string) => boolean = () => true): string[] {\n const dir = posix.normalize(selection.dir.replaceAll(\"\\\\\", \"/\"));\n const sourceOf = (f: string): string | undefined => {\n if (globsSelect(selection.mutate, f)) return f;\n const source = f.replace(TEST_FILE, \"$1$2\");\n return source !== f && globsSelect(selection.mutate, source) && exists(source) ? source : undefined;\n };\n const files = changed\n .map((f) => posix.relative(dir, posix.normalize(f.replaceAll(\"\\\\\", \"/\"))))\n .flatMap((f) => (f === \"\" || f.startsWith(\"../\") || posix.isAbsolute(f) ? [] : (sourceOf(f) ?? [])));\n return [...new Set(files)]\n .flatMap((f) => {\n const cover = coverOf(selection.mutate, f);\n return cover === \"all\" ? [f] : cover.map((r) => `${f}${r.entry.slice(r.glob.length)}`);\n });\n}\n\n/** This function gives the errors of the line ranges of one file in the parts of a package. */\nfunction rangeErrors(pkg: string, file: string, ranges: readonly { part: string; range: LineRange }[], lines: number | undefined): string[] {\n const errors: string[] = [];\n for (const { part, range } of ranges) {\n if (range.columns) errors.push(`${pkg}: the range ${range.entry} of the part ${part} has columns. A part can cut a file only by lines`);\n else if (range.from < 1 || range.from > range.to) errors.push(`${pkg}: the range ${range.entry} of the part ${part} has no lines`);\n }\n if (errors.length > 0) return errors;\n let next = 1;\n let last = \"\";\n for (const { part, range } of ranges.toSorted((x, y) => x.range.from - y.range.from || x.range.to - y.range.to)) {\n if (range.from > next) errors.push(`${pkg}: the lines ${String(next)}-${String(range.from - 1)} of ${file} are in no part`);\n else if (range.from < next) errors.push(`${pkg}: the lines ${String(range.from)}-${String(Math.min(range.to, next - 1))} of ${file} are in the parts ${last} and ${part}`);\n if (range.to >= next) {\n next = range.to + 1;\n last = part;\n }\n }\n if (lines !== undefined && next <= lines) errors.push(`${pkg}: the lines ${String(next)}-${String(lines)} of ${file} are in no part`);\n return errors;\n}\n\n/**\n * This function examines the parts of a package against its files. It gives an error for each file of `mutate` in no\n * part. It also gives an error for each file in two parts, and for each file of a part that is not in `mutate`. A\n * package with no parts has no errors.\n *\n * Parts can cut one file by line ranges. Then the function gives an error for each gap and each overlap of the\n * ranges. With `lines`, it also gives an error for the lines after the last range.\n *\n * @param files - the source files of the package, from its folder, with `/`\n * @param lines - this function gives the number of lines of a file of `files`\n */\nexport function partErrors(lane: Lane, pkg: string, files: readonly string[], lines?: (file: string) => number): string[] {\n const p = lane.packages[pkg];\n if (p?.parts === undefined) return [];\n const parts = Object.keys(p.parts).map((part) => ({ part, mutate: select(lane, `${pkg}.${part}`).mutate }));\n const errors: string[] = [];\n for (const file of files) {\n const inMutate = globsSelect(p.mutate, file);\n const inParts = parts.filter((x) => globsSelect(x.mutate, file)).map((x) => x.part);\n const covers = parts.filter((x) => inParts.includes(x.part)).map((x) => ({ part: x.part, cover: coverOf(x.mutate, file) }));\n const ranged = covers.every((x) => x.cover !== \"all\");\n if (inMutate && inParts.length === 0) errors.push(`${pkg}: the file ${file} is in no part, so a full run does not mutate it`);\n else if (inParts.length > 1 && !ranged) errors.push(`${pkg}: the file ${file} is in more than one part: ${inParts.join(\", \")}`);\n else if (!inMutate && inParts.length > 0) errors.push(`${pkg}: the file ${file} is in the part ${inParts.join(\", \")}, but not in \"mutate\"`);\n else if (inParts.length > 0 && ranged) {\n const ranges = covers.flatMap((x) => (x.cover === \"all\" ? [] : x.cover.map((range) => ({ part: x.part, range }))));\n errors.push(...rangeErrors(pkg, file, ranges, lines?.(file)));\n }\n }\n return errors;\n}\n","import type { Selection } from \"./lane.ts\";\n\n/** The options of `strykerConfig`. */\nexport interface ConfigOptions {\n /** This option gives the number of test processes. The default is 2. */\n readonly concurrency?: number;\n /** This option gives the folder of the reports, from the folder of the package. The default is `reports/mutation`. */\n readonly reportDir?: string;\n /**\n * When this option is true, Stryker starts only the tests without mutants, and it does not stop at the first failed\n * test. Use it to see if the tests pass under Stryker before a long run.\n */\n readonly dryRun?: boolean;\n /**\n * When this option is false, Stryker does not rewrite the tsconfig of the package in its sandbox. The default is true.\n * The rewrite uses `parseConfigFileTextToJson`, and TypeScript 7 does not have it. Refer to `rewritesTsconfig`.\n */\n readonly tsconfigRewrite?: boolean;\n}\n\n/** The Stryker config of one selection, as JSON. Stryker starts in the folder of the package. The field `stryker` of the lane adds keys. */\nexport interface StrykerConfig {\n readonly [key: string]: unknown;\n readonly testRunner: \"vitest\";\n readonly plugins: readonly string[];\n readonly vitest?: { readonly configFile: string };\n readonly mutate: readonly string[];\n readonly coverageAnalysis: \"perTest\";\n readonly reporters: readonly string[];\n readonly htmlReporter: { readonly fileName: string };\n readonly jsonReporter: { readonly fileName: string };\n readonly thresholds: { readonly high: number; readonly low: number; readonly break: null };\n readonly concurrency: number;\n readonly timeoutMS: number;\n readonly dryRunTimeoutMinutes: number;\n readonly tsconfigFile?: string;\n readonly dryRunOnly?: true;\n readonly disableBail?: true;\n}\n\n/** The default folder of the reports, from the folder of the package. */\nexport const REPORT_DIR = \"reports/mutation\";\n\n/**\n * The default time in milliseconds that the clock adds to the time of the tests for each mutant. The default of\n * Stryker is 5000. On a loaded CI runner that time stopped mutants that the tests detected later.\n */\nexport const TIMEOUT_MS = 120_000;\n\n/**\n * The value of `tsconfigFile` when the rewrite of the tsconfig is off. No project has this file, so Stryker finds no\n * tsconfig to rewrite.\n */\nexport const NO_TSCONFIG = \"tsconfig.no-stryker-rewrite.json\";\n\n/**\n * This function tells if Stryker can rewrite a tsconfig with a TypeScript of the major version `major`. Stryker 10.1\n * parses the tsconfig with `parseConfigFileTextToJson`, and TypeScript 7 removed it. When no TypeScript is found, the\n * answer is true, and the config keeps the default of Stryker.\n */\nexport function rewritesTsconfig(major: number | undefined): boolean {\n return major === undefined || major < 7;\n}\n\n/** The default time in minutes for the run of the tests without mutants. The default of Stryker is 5. */\nexport const DRY_RUN_TIMEOUT_MINUTES = 15;\n\n/**\n * This function gives the Stryker config of a selection. The break of Stryker is off, because the gate of each\n * package is in `scoreReport`. Stryker 10.1.0 or later is necessary with Vitest 5: version 10.0 started no test on each\n * mutant (stryker-js issue 6210).\n */\nexport function strykerConfig(selection: Selection, options: ConfigOptions = {}): StrykerConfig {\n const reportDir = options.reportDir ?? REPORT_DIR;\n const low = selection.gate ?? 60;\n return {\n testRunner: \"vitest\",\n plugins: [\"@stryker-mutator/vitest-runner\"],\n ...(selection.vitestConfig === undefined ? {} : { vitest: { configFile: selection.vitestConfig } }),\n mutate: selection.mutate,\n coverageAnalysis: \"perTest\",\n reporters: [\"clear-text\", \"progress\", \"html\", \"json\"],\n htmlReporter: { fileName: `${reportDir}/index.html` },\n jsonReporter: { fileName: `${reportDir}/mutation.json` },\n thresholds: { high: Math.max(low, 90), low, break: null },\n concurrency: options.concurrency ?? 2,\n timeoutMS: selection.timeoutMS ?? TIMEOUT_MS,\n dryRunTimeoutMinutes: selection.dryRunTimeoutMinutes ?? DRY_RUN_TIMEOUT_MINUTES,\n ...(options.tsconfigRewrite === false ? { tsconfigFile: NO_TSCONFIG } : {}),\n // The keys of the lane field \"stryker\" replace the keys above, but \"--concurrency\" replaces its \"concurrency\".\n ...selection.stryker,\n ...(options.concurrency === undefined ? {} : { concurrency: options.concurrency }),\n ...(options.dryRun === true ? { dryRunOnly: true, disableBail: true } : {}),\n };\n}\n","/**\n * The score of a Stryker report, with the gate of the package. The score counts the detected mutants, out of the\n * mutants that a test covers or that survive. Compile errors, runtime errors and ignored mutants do not count.\n *\n * Stryker gives the status `Timeout` for two events. The hit limit stops a mutant with an endless loop: its\n * `statusReason` starts with `Hit limit`, and the mutant is detected. The clock stops a mutant that took too long. The\n * load of the runner can cause this. Thus the mutant is not detected for certain, and it counts as not detected.\n */\n\n/** A mutant of the JSON report of Stryker (the schema of mutation-testing-elements). */\nexport interface Mutant {\n readonly status: string;\n readonly mutatorName: string;\n /** Stryker gives the reason of some statuses here. A `Timeout` of the hit limit has a reason that starts with `Hit limit`. */\n readonly statusReason?: string | undefined;\n readonly location: { readonly start: { readonly line: number } };\n}\n\n/** The JSON report of Stryker: the mutants of each mutated file, and the tests of each test file that the run read. */\nexport interface MutationReport {\n readonly files: Readonly<Record<string, { readonly mutants: readonly Mutant[] }>>;\n /** Stryker gives this field when the test runner tells the tests, as the Vitest runner does. */\n readonly testFiles?: Readonly<Record<string, { readonly tests: readonly { readonly name: string }[] }>> | undefined;\n}\n\n/**\n * The three reads of a score. A `block` is a score under its gate. A `no read` is a score that does not read the tests.\n * Its cause is no report, no mutant that counts, no detected mutant, or a run that did not read all the tests. A no read is not a pass.\n */\nexport type ScoreOutcome = \"pass\" | \"block\" | \"no read\";\n\n/** The score of one selection. */\nexport interface Score {\n readonly name: string;\n readonly gate: number | undefined;\n /** The mutants with the status `Killed`, and the mutants that the hit limit stopped. */\n readonly detected: number;\n /** The mutants that the hit limit stopped. They are in `detected`. */\n readonly hitLimit: number;\n /** The mutants that the clock stopped. They count as not detected, and they are in `survived`. */\n readonly clockTimeouts: number;\n /** The mutants that count: detected, survived or with no coverage. */\n readonly valid: number;\n /** Each mutant that survived, had no coverage or was stopped by the clock, as `file:line Mutator`. */\n readonly survived: readonly string[];\n /** The score in percent. It is 0 when no mutant counts. */\n readonly percent: number;\n /** The score in percent with the clock time-outs counted as detected, as Stryker counts them. The gate does not read it. */\n readonly percentWithClock: number;\n /** The count of the tests that the run read, from `testFiles` of the report. It is undefined when the report has no `testFiles`. */\n readonly tests: number | undefined;\n readonly pass: boolean;\n /** The reason of a failure. */\n readonly reason: string | undefined;\n /** The read of the score. The functions of this package always give it. A score from an older version has no outcome. */\n readonly outcome?: ScoreOutcome;\n}\n\nconst UNDETECTED = new Set([\"Survived\", \"NoCoverage\"]);\n\n/** This function tells if the hit limit of Stryker stopped a mutant. Then the mutant has an endless loop, and it is detected. */\nexport const isHitLimit = (m: Mutant): boolean => m.status === \"Timeout\" && (m.statusReason ?? \"\").startsWith(\"Hit limit\");\n\n/**\n * This function examines the JSON of a Stryker report and gives the report.\n *\n * @throws Error when the JSON has no files with mutants\n */\nexport function parseReport(json: unknown): MutationReport {\n const files = typeof json === \"object\" && json !== null ? (json as { files?: unknown }).files : undefined;\n if (typeof files !== \"object\" || files === null) throw new Error(`the report has no object \"files\"`);\n for (const [file, data] of Object.entries(files)) {\n if (!Array.isArray((data as { mutants?: unknown } | null)?.mutants)) throw new Error(`the report has no list \"mutants\" for ${file}`);\n }\n const testFiles = (json as { testFiles?: unknown }).testFiles;\n if (testFiles !== undefined) {\n if (typeof testFiles !== \"object\" || testFiles === null) throw new Error(`the field \"testFiles\" of the report is not an object`);\n for (const [file, data] of Object.entries(testFiles)) {\n if (!Array.isArray((data as { tests?: unknown } | null)?.tests)) throw new Error(`the report has no list \"tests\" for the test file ${file}`);\n }\n }\n return json as MutationReport;\n}\n\n/** This function gives the count of the tests of a report, or undefined when the report has no `testFiles`. */\nexport function testCount(report: MutationReport): number | undefined {\n if (report.testFiles === undefined) return undefined;\n return Object.values(report.testFiles).reduce((sum, f) => sum + f.tests.length, 0);\n}\n\n/**\n * This function compares a test count with the last good count. It gives the reason of a failure when the count fell\n * by more than `maxFall` percent, else undefined. A report that reads fewer tests is no read of the score.\n *\n * @param maxFall - the highest fall in percent that passes\n */\nexport function testFall(tests: number, last: number, maxFall: number): string | undefined {\n if (last <= 0 || tests >= last) return undefined;\n const fall = (100 * (last - tests)) / last;\n if (fall <= maxFall) return undefined;\n return `the run read ${String(tests)} tests, ${fall.toFixed(1)} % fewer than the last good count ${String(last)} (the limit is ${String(maxFall)} %), so the score is no read`;\n}\n\n/**\n * This function gives each test file on the disk that the report does not read, and that `notRead` does not name.\n * The files of the report and of the disk are from the folder of the package.\n *\n * @param onDisk - the test files of the package, from its folder, with `/`\n * @param dir - the folder of the package, to make a full path of the report relative\n */\nexport function unreadTestFiles(report: MutationReport, onDisk: readonly string[], notRead: Readonly<Record<string, string>> = {}, dir = \"\"): string[] {\n const root = dir.replaceAll(\"\\\\\", \"/\").replace(/\\/?$/, \"/\");\n const read = new Set(\n Object.keys(report.testFiles ?? {}).map((f) => {\n const file = f.replaceAll(\"\\\\\", \"/\");\n return dir !== \"\" && file.startsWith(root) ? file.slice(root.length) : file.replace(/^\\.\\//, \"\");\n }),\n );\n return onDisk.filter((f) => !read.has(f) && notRead[f] === undefined);\n}\n\n/**\n * This function gives a score that fails for a reason, with the outcome `no read`. A score that failed already keeps its\n * first reason, and gets the new one after it. A score under its gate with a second reason is also a no read.\n */\nexport function failScore(score: Score, reason: string): Score {\n return { ...score, pass: false, outcome: \"no read\", reason: score.reason === undefined ? reason : `${score.reason}. Also ${reason}` };\n}\n\n/**\n * This function gives the score of a report and applies the gate. A report with no mutants that count fails, also\n * without a gate: Stryker found no files. A report with mutants that count and none detected also fails: the test\n * runner started no test on the mutants. Stryker 10.0 with Vitest 5 gave this result.\n */\nexport function scoreReport(report: MutationReport, selection: { readonly name: string; readonly gate: number | undefined }): Score {\n let detected = 0;\n let valid = 0;\n let hitLimit = 0;\n let clockTimeouts = 0;\n const survived: string[] = [];\n for (const [file, data] of Object.entries(report.files)) {\n for (const m of data.mutants) {\n const at = `${file}:${String(m.location.start.line)} ${m.mutatorName}`;\n if (m.status === \"Killed\" || isHitLimit(m)) {\n detected++;\n valid++;\n if (m.status === \"Timeout\") hitLimit++;\n } else if (m.status === \"Timeout\") {\n clockTimeouts++;\n valid++;\n survived.push(`${at} (the clock stopped it)`);\n } else if (UNDETECTED.has(m.status)) {\n valid++;\n survived.push(at);\n }\n }\n }\n const percent = valid === 0 ? 0 : (100 * detected) / valid;\n const percentWithClock = valid === 0 ? 0 : (100 * (detected + clockTimeouts)) / valid;\n const { name, gate } = selection;\n const [outcome, reason]: [ScoreOutcome, string | undefined] =\n valid === 0\n ? [\"no read\", \"the report has no mutants that count: Stryker found no files to mutate, or it did not start\"]\n : detected === 0\n ? [\"no read\", `the tests detected none of the ${String(valid)} mutants: the test runner started no test on the mutants`]\n : gate !== undefined && percent < gate\n ? [\"block\", `the score ${percent.toFixed(2)} % is under the gate ${String(gate)} %`]\n : [\"pass\", undefined];\n return { name, gate, detected, hitLimit, clockTimeouts, valid, survived, percent, percentWithClock, tests: testCount(report), pass: reason === undefined, reason, outcome };\n}\n\n/**\n * This function gives the score of a package from the scores of its parts, and applies the gate of the package. It sums\n * the mutants of the parts. A part that fails makes the package a no read: a part has no gate of its own here.\n * A missing part also makes the package a no read, because the sum does not count its mutants.\n *\n * @param missing - the parts of the package that have no score in this read\n */\nexport function packageScore(name: string, gate: number | undefined, parts: readonly Score[], missing: readonly string[] = []): Score {\n const sum = (count: (s: Score) => number): number => parts.reduce((total, s) => total + count(s), 0);\n const detected = sum((s) => s.detected);\n const valid = sum((s) => s.valid);\n const clockTimeouts = sum((s) => s.clockTimeouts);\n const percent = valid === 0 ? 0 : (100 * detected) / valid;\n const percentWithClock = valid === 0 ? 0 : (100 * (detected + clockTimeouts)) / valid;\n const failed = parts.filter((s) => !s.pass).map((s) => s.name);\n const [outcome, reason]: [ScoreOutcome, string | undefined] =\n parts.length === 0\n ? [\"no read\", \"the package has no scores of its parts\"]\n : missing.length > 0\n ? [\"no read\", `the read has no score of the parts ${missing.join(\", \")}, so the sum does not count their mutants`]\n : failed.length > 0\n ? [\"no read\", `the parts ${failed.join(\", \")} fail, so the sum of the parts has no meaning`]\n : gate !== undefined && percent < gate\n ? [\"block\", `the score ${percent.toFixed(2)} % of all the parts is under the gate ${String(gate)} %`]\n : [\"pass\", undefined];\n const tests = parts.every((s) => s.tests !== undefined) ? sum((s) => s.tests ?? 0) : undefined;\n return { name, gate, detected, hitLimit: sum((s) => s.hitLimit), clockTimeouts, valid, survived: parts.flatMap((s) => s.survived), percent, percentWithClock, tests, pass: reason === undefined, reason, outcome };\n}\n\n/** This function gives the time-outs of a score as text: the count of each kind, and the score that counts the clock time-outs as detected. */\nconst timeouts = (s: Score): string =>\n `time-outs: ${String(s.hitLimit)} hit limit, ${String(s.clockTimeouts)} clock (${s.percentWithClock.toFixed(2)} % with the clock time-outs as detected)`;\n\n/** This function gives one line for a score, with the name of the selection and its result. The time-outs are in it when the report has some. */\nexport function formatScore(s: Score): string {\n const gate = s.gate === undefined ? \"no gate\" : `gate ${String(s.gate)} %`;\n const result = s.pass ? \"pass\" : `FAIL: ${s.reason ?? \"\"}`;\n const time = s.hitLimit + s.clockTimeouts === 0 ? \"\" : `, ${timeouts(s)}`;\n const tests = s.tests === undefined ? \"\" : `, ${String(s.tests)} tests`;\n return `${s.name}: ${s.percent.toFixed(2)} % (${String(s.detected)} of ${String(s.valid)}, ${String(s.survived.length)} survived${time}${tests}), ${gate}: ${result}`;\n}\n\n/** This function gives a Markdown table of scores, for the summary of a CI job. */\nexport function summaryMarkdown(scores: readonly Score[]): string {\n const rows = scores.map(\n (s) =>\n `| ${s.name} | ${s.percent.toFixed(2)} % | ${String(s.detected)} | ${String(s.valid)} | ${String(s.survived.length)} | ${String(s.clockTimeouts)} | ${s.percentWithClock.toFixed(2)} % | ${s.gate === undefined ? \"none\" : `${String(s.gate)} %`} | ${s.pass ? \"pass\" : `fail: ${s.reason ?? \"\"}`} | ${s.tests === undefined ? \"?\" : String(s.tests)} |`,\n );\n return [\n \"| Selection | Score | Detected | Valid | Survived | Clock time-outs | Score with them | Gate | Result | Tests |\",\n \"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | ---: |\",\n ...rows,\n \"\",\n ].join(\"\\n\");\n}\n","/**\n * A comment `// Stryker disable next-line <Mutator>: <reason>` disables a mutant that is equivalent. The disable\n * raises the score, so each one is also in a list with its reason. These functions find the comments in the\n * sources and compare them with the list.\n */\n\n/** One disable comment of a source file. */\nexport interface Disable {\n readonly file: string;\n readonly comment: string;\n}\n\n/** The result of `compareDisables`. */\nexport interface DisableCheck {\n /** The comments of the sources that are not in the list, as `file: comment`. */\n readonly added: readonly string[];\n /** The comments of the list that are not in the sources, as `file: comment`. */\n readonly removed: readonly string[];\n /** The comments with no reason after a colon. */\n readonly noReason: readonly Disable[];\n readonly ok: boolean;\n}\n\n/** This function finds each `Stryker disable` comment of the files. A file name uses `/`. */\nexport function findDisables(files: readonly { readonly file: string; readonly text: string }[]): Disable[] {\n return files.flatMap(({ file, text }) =>\n text\n .split(\"\\n\")\n .filter((line) => line.includes(\"Stryker disable\"))\n .map((line) => ({ file, comment: line.trim() })),\n );\n}\n\nconst counts = (xs: readonly Disable[]): Map<string, number> => {\n const m = new Map<string, number>();\n for (const x of xs) {\n const k = `${x.file}: ${x.comment}`;\n m.set(k, (m.get(k) ?? 0) + 1);\n }\n return m;\n};\n\n/**\n * This function tells if a comment has a reason: a mutator name, a colon, a space and a text. It reads the text by\n * index, so its time is linear in the length of the comment (a regular expression here was quadratic).\n */\nfunction hasReason(comment: string): boolean {\n const start = comment.indexOf(\"Stryker disable \");\n if (start < 0) return false;\n const rest = comment.slice(start + \"Stryker disable \".length);\n const colon = rest.indexOf(\":\");\n return colon > 0 && rest[colon + 1] === \" \" && /\\S/.test(rest[colon + 2] ?? \"\");\n}\n\n/** This function compares the comments of the sources with the list. A file with the same comment two times needs it two times in the list. */\nexport function compareDisables(found: readonly Disable[], listed: readonly Disable[]): DisableCheck {\n const noReason = found.filter((d) => !hasReason(d.comment));\n const a = counts(found);\n const b = counts(listed);\n const added = [...a].filter(([k, n]) => n > (b.get(k) ?? 0)).map(([k]) => k);\n const removed = [...b].filter(([k, n]) => n > (a.get(k) ?? 0)).map(([k]) => k);\n return { added, removed, noReason, ok: added.length === 0 && removed.length === 0 && noReason.length === 0 };\n}\n","/**\n * The load check. Stryker copies the folder of a package to `<dir>/.stryker-tmp/sandbox-*` and starts the tests there.\n * A relative path that leaves the folder then finds no file. A test file that does not load gives no failed test, so\n * each mutant that it detects survives with no error (V-072 of Vex). This check finds these paths before Stryker. It\n * reads only the files that the run loads, so a script of the folder that no test loads can leave the folder.\n */\nimport { posix } from \"node:path\";\n\n/** A relative path in a file of a package that leaves the folder of the package. */\nexport interface LeavingPath {\n /** The file, from the folder of the package, with `/`. */\n readonly file: string;\n /** The line of the path, from 1. */\n readonly line: number;\n /** The path as the file writes it. */\n readonly path: string;\n}\n\n/** A file of a package and its text. */\nexport interface PackageFile {\n /** The file, from the folder of the package, with `/`. */\n readonly file: string;\n readonly text: string;\n}\n\n// The paths that a module loads: import and export from, import(), require(), vi.mock() and the other vi functions,\n// and new URL(path, import.meta.url).\n// The optional \"(\" and its spaces are one group, so that each space has one match (no slow backtracking).\nconst LOADED = /(?:\\bfrom|\\bimport|\\brequire|\\bvi\\.\\w+|\\bnew\\s+URL)\\s*(?:\\(\\s*)?([\"'`])([^\"'`\\r\\n]*)\\1/g;\n// Each relative path string of a config file, for example setupFiles: [\"../testkit/setup.ts\"].\nconst CONFIG_PATH = /([\"'`])(\\.\\.?\\/[^\"'`\\r\\n]*)\\1/g;\n// A type import or export: the test runner removes it, so it loads no file.\nconst TYPE_ONLY = /^\\s*(?:import|export)\\s+type\\b/;\nconst COMMENT = /^\\s*(?:\\/\\/|\\/\\*|\\*)/;\nconst CONFIG_FILE = /(?:^|\\/)vite(?:st)?\\.(?:config|workspace)\\.[cm]?[jt]s$/;\n\n/**\n * This function tells if a file is a config file of Vitest or Vite. Each relative path string of a config file must\n * stay in the folder.\n *\n * @param vitestConfig - the field `vitestConfig` of the lane, from the folder of the package\n */\nexport function isConfigFile(file: string, vitestConfig?: string): boolean {\n return CONFIG_FILE.test(file) || (vitestConfig !== undefined && posix.normalize(vitestConfig.replaceAll(\"\\\\\", \"/\")) === file);\n}\n\nfunction leaves(file: string, path: string): boolean {\n if (!(path === \".\" || path === \"..\" || path.startsWith(\"./\") || path.startsWith(\"../\")) || path.includes(\"${\")) return false;\n const target = posix.normalize(posix.join(posix.dirname(file), path));\n return target === \"..\" || target.startsWith(\"../\");\n}\n\nconst TEST = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/;\nconst EXTENSIONS = [\"\", \".ts\", \".tsx\", \".mts\", \".cts\", \".js\", \".mjs\", \".cjs\", \"/index.ts\", \"/index.js\"];\n\n/** This function gives each relative path of one file, with its line. It does not read comments and type imports. */\nfunction pathsOf(file: string, text: string, vitestConfig: string | undefined): { line: number; path: string }[] {\n const pattern = isConfigFile(file, vitestConfig) ? CONFIG_PATH : LOADED;\n return text.split(\"\\n\").flatMap((lineText, i) => {\n if (COMMENT.test(lineText) || TYPE_ONLY.test(lineText)) return [];\n return [...lineText.matchAll(pattern)].map((m) => ({ line: i + 1, path: m[2] ?? \"\" })).filter((p) => p.path.startsWith(\".\"));\n });\n}\n\n/** This function gives the file of the package that a relative path in the folder loads, or undefined. */\nfunction target(file: string, path: string, known: ReadonlySet<string>): string | undefined {\n const base = posix.normalize(posix.join(posix.dirname(file), path));\n const stem = base.replace(/\\.(?:[cm]?js|jsx)$/, \"\");\n return [...EXTENSIONS.map((e) => base + e), ...EXTENSIONS.slice(1).map((e) => stem + e)].find((f) => known.has(f));\n}\n\n/**\n * This function gives each relative path of the files that leaves the folder of the package. It reads the files that\n * the run loads. These are the test files, the config files, and each file that they load in the folder.\n * In a config file it reads each relative path string, for example a setup file. It does not read comments and type\n * imports.\n *\n * @param files - the files of the package, from its folder\n * @param vitestConfig - the field `vitestConfig` of the lane\n */\nexport function leavingPaths(files: readonly PackageFile[], vitestConfig?: string): LeavingPath[] {\n const texts = new Map(files.map((f) => [f.file, f.text]));\n const known = new Set(texts.keys());\n const queue = files.map((f) => f.file).filter((f) => TEST.test(f) || isConfigFile(f, vitestConfig));\n const loaded = new Set(queue);\n const found: LeavingPath[] = [];\n for (let next = queue.shift(); next !== undefined; next = queue.shift()) {\n for (const { line, path } of pathsOf(next, texts.get(next) ?? \"\", vitestConfig)) {\n if (leaves(next, path)) found.push({ file: next, line, path });\n else {\n const t = target(next, path, known);\n if (t !== undefined && !loaded.has(t)) {\n loaded.add(t);\n queue.push(t);\n }\n }\n }\n }\n return found.toSorted((a, b) => (a.file === b.file ? a.line - b.line : a.file < b.file ? -1 : 1));\n}\n\n// A type import or export to its semicolon, also on more than one line. The test runner removes it.\nconst TYPE_STATEMENT = /^[ \\t]*(?:import|export)[ \\t]+type\\b[^;]*;/gm;\n\n/** This function replaces each type import and export with its line ends, so the lines of the other paths stay. */\nfunction withoutTypeStatements(text: string): string {\n return text.replace(TYPE_STATEMENT, (statement) => statement.replace(/[^\\n]/g, \"\"));\n}\n\n/**\n * This function gives the test files that the related mode of the Vitest runner starts for a selection. A test file\n * is related when it loads a file of the selection, directly or through other files of the package. The function\n * does not read comments and type imports. The order is the order of `files`.\n *\n * @param files - the files of the package, from its folder\n * @param selected - the function that tells if a file is a file of the selection\n */\nexport function relatedTestFiles(files: readonly PackageFile[], selected: (file: string) => boolean): string[] {\n const texts = new Map(files.map((f) => [f.file, withoutTypeStatements(f.text)]));\n const known = new Set(texts.keys());\n const loads = (file: string): string[] =>\n pathsOf(file, texts.get(file) ?? \"\", undefined).flatMap(({ path }) => {\n const t = target(file, path, known);\n return t === undefined ? [] : [t];\n });\n const reaches = (test: string): boolean => {\n const queue = [test];\n const loaded = new Set(queue);\n for (let next = queue.shift(); next !== undefined; next = queue.shift()) {\n for (const t of loads(next)) {\n if (!TEST.test(t) && selected(t)) return true;\n if (!loaded.has(t)) {\n loaded.add(t);\n queue.push(t);\n }\n }\n }\n return false;\n };\n return files.map((f) => f.file).filter((f) => TEST.test(f) && reaches(f));\n}\n","/**\n * The CLI `rigor-mutation`. The work is in `runCli`, so a test can start the CLI in a fixture folder.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, appendFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { REPORT_DIR, rewritesTsconfig, strykerConfig } from \"./config.ts\";\nimport { compareDisables, findDisables, type Disable } from \"./disables.ts\";\nimport { leavingPaths, relatedTestFiles } from \"./load.ts\";\nimport { changedFiles, globsSelect, MAX_TEST_FALL, parseLane, partErrors, runSelections, select, selectionNames, type Lane, type Selection } from \"./lane.ts\";\nimport { failScore, formatScore, packageScore, parseReport, scoreReport, summaryMarkdown, testFall, unreadTestFiles, type MutationReport, type Score } from \"./score.ts\";\n\n/** The input and the output of the CLI. */\nexport interface CliIo {\n readonly cwd: string;\n readonly stdout: (text: string) => void;\n readonly stderr: (text: string) => void;\n /** The environment. With `GITHUB_ACTIONS` set to `true`, `scores` writes an annotation for each score that does not pass and each planned fall. */\n readonly env?: Readonly<Record<string, string | undefined>>;\n}\n\n/** The help text of the CLI. */\nexport const HELP: string = `rigor-mutation: the mutation tests of a repository, with Stryker and a gate for each package.\n\n rigor-mutation list [--runs] [--changed <file>]\n the packages and the parts of the lane. With --runs, the\n selections of a full run: the parts of a package with parts.\n With --changed, only the runs with a changed file.\n rigor-mutation dir <selection> the folder of the package of a selection\n rigor-mutation config <selection> [--out <file>] [--concurrency <n>] [--dry-run] [--changed <file>]\n the Stryker config of a selection, as JSON. With --dry-run,\n Stryker starts only the tests. With --changed, it mutates only\n the changed files of the selection.\n rigor-mutation scores <selection>... [--report <file> | --reports <dir>] [--summary <file>]\n [--last <file>] [--write-last <file>] [--test-files] [--alone]\n the score of each selection, with its gate and its count\n of tests. --reports reads <dir>/mutation-<selection>/mutation.json.\n A package with \"gateOver\": \"package\" also gets\n the score of its parts together, a no read without all its parts.\n --alone gives no line for the package: the job of one part\n then fails only for a no read. With --last, a fall of the count of more than\n maxTestFall % (default 20) against the file fails. With\n --write-last, the counts of the passed selections go in\n the file. With --test-files, a test file that the run\n starts and that the report does not read fails.\n rigor-mutation disables [--write] compare the disable comments with their list\n rigor-mutation load-check [<selection>...] refuse each relative path of a package that leaves its folder.\n Stryker starts the tests in a copy of the folder, so such a\n path finds no file. No selection checks each package.\n\n --lane <file> the lane file. The default is mutation.json.\n --changed <file> a file with one changed path on each line, from the folder of the lane file,\n for example the output of git diff --name-only. A changed test file selects\n its source file of the same name.\n\nA selection is a package (\"collections\") or a part of a package (\"collections.impl\").\nEach file of a package with parts must be in exactly one part. list --runs, and config and scores\nof a part, fail when it is not.\nThe score of a selection reads <dir>/${REPORT_DIR}/mutation.json, or the file of --report.\n`;\n\nconst SOURCE = /\\.(?:[cm]?[jt]s|tsx)$/;\nconst TEST = /\\.(?:test|spec)\\.[^.]+$/;\nconst SKIP = new Set([\"node_modules\", \"build\", \"dist\", \"reports\", \"coverage\"]);\n\n/**\n * This function gives each source file of a folder, from `root`, with `/`. It skips the outputs and the dot folders,\n * and the tests when `tests` is false.\n */\nfunction sourcesOf(root: string, dir: string, tests = false): string[] {\n return readdirSync(dir, { withFileTypes: true })\n .toSorted((x, y) => x.name.localeCompare(y.name))\n .flatMap((e) => {\n const path = resolve(dir, e.name);\n if (e.isDirectory()) return e.name.startsWith(\".\") || SKIP.has(e.name) ? [] : sourcesOf(root, path, tests);\n return e.isFile() && SOURCE.test(e.name) && (tests || !TEST.test(e.name)) ? [relative(root, path).replaceAll(\"\\\\\", \"/\")] : [];\n });\n}\n\n/** This function checks the relative paths of the package of each selection (`load-check`). */\nfunction loadCheck(lane: Lane, laneDir: string, names: readonly string[], io: CliIo): number {\n const pkgs = [...new Set((names.length === 0 ? Object.keys(lane.packages) : names.map((n) => select(lane, n).pkg)))];\n let failed = 0;\n for (const pkg of pkgs) {\n const s = select(lane, pkg);\n const dir = resolve(laneDir, s.dir);\n if (!existsSync(dir)) throw new Error(`${pkg}: the folder ${s.dir} does not exist`);\n const files = sourcesOf(dir, dir, true)\n .filter((f) => !f.endsWith(\".d.ts\"))\n .map((file) => ({ file, text: readFileSync(resolve(dir, file), \"utf8\") }));\n const found = leavingPaths(files, s.vitestConfig);\n for (const p of found) {\n io.stderr(`${s.dir}/${p.file}:${String(p.line)}: \"${p.path}\" leaves the folder ${s.dir}. In the copy of Stryker it finds no file.\n`);\n }\n if (found.length === 0) io.stdout(`load-check ${pkg}: ${String(files.length)} files, no relative path leaves ${s.dir}\n`);\n else failed += 1;\n }\n if (failed > 0) io.stderr(`load-check: ${String(failed)} packages have a relative path that leaves their folder. Import the file from its package, or move it into the folder.\n`);\n return failed > 0 ? 1 : 0;\n}\n\nconst readJson = (file: string): unknown => JSON.parse(readFileSync(file, \"utf8\"));\n\n/**\n * This function gives the major version of the `typescript` that the folder `dir` resolves, or undefined when the\n * folder resolves none. In a usual install, Stryker resolves the same version, because it starts in that folder.\n */\nfunction typescriptMajor(dir: string): number | undefined {\n let file: string;\n try {\n file = createRequire(join(dir, \"package.json\")).resolve(\"typescript/package.json\");\n } catch {\n return undefined;\n }\n const version: unknown = (readJson(file) as { version?: unknown }).version;\n const major = typeof version === \"string\" ? Number.parseInt(version, 10) : Number.NaN;\n return Number.isInteger(major) ? major : undefined;\n}\n\n/**\n * This function examines the parts of the packages against their source files.\n *\n * @throws Error with each file that is in no part, in more than one part, or in a part and not in `mutate`\n */\n/** This function gives the number of lines of a text. A last line break does not start a line. */\nconst lineCount = (text: string): number => (text === \"\" ? 0 : text.split(\"\\n\").length - (text.endsWith(\"\\n\") ? 1 : 0));\n\n/** This function tells if a file of the package of a selection, from its folder, exists. */\nconst existsIn =\n (laneDir: string, s: Selection) =>\n (file: string): boolean =>\n existsSync(resolve(laneDir, s.dir, file));\n\nfunction checkParts(lane: Lane, laneDir: string, pkgs: readonly string[]): void {\n const errors = pkgs.flatMap((pkg) => {\n const p = lane.packages[pkg];\n if (p?.parts === undefined) return [];\n const dir = resolve(laneDir, p.dir);\n if (!existsSync(dir)) return [`${pkg}: the folder ${p.dir} does not exist`];\n return partErrors(lane, pkg, sourcesOf(dir, dir), (file) => lineCount(readFileSync(resolve(dir, file), \"utf8\")));\n });\n if (errors.length > 0) throw new Error(`the parts do not cover each file exactly one time:\\n ${errors.join(\"\\n \")}`);\n}\n\n/** This function examines the parts of the package of each selection that is a part. */\nconst checkPartsOf = (lane: Lane, laneDir: string, names: readonly string[]): void =>\n checkParts(lane, laneDir, [...new Set(names.map((n) => select(lane, n)).filter((s) => s.name !== s.pkg).map((s) => s.pkg))]);\n\nfunction disables(lane: Lane, laneDir: string, write: boolean, io: CliIo): number {\n const files = new Set<string>();\n for (const [name, p] of Object.entries(lane.packages)) {\n const dir = resolve(laneDir, p.dir);\n if (!existsSync(dir)) throw new Error(`${name}: the folder ${p.dir} does not exist`);\n for (const f of sourcesOf(laneDir, dir)) files.add(f);\n }\n const found = findDisables([...files].map((file) => ({ file, text: readFileSync(resolve(laneDir, file), \"utf8\") })));\n const listFile = resolve(laneDir, lane.disables ?? \"mutation-disables.json\");\n const listed = existsSync(listFile) ? (readJson(listFile) as Disable[]) : [];\n const check = compareDisables(found, listed);\n for (const d of check.noReason) io.stderr(`a disable without a reason after a colon: ${d.file}: ${d.comment}\\n`);\n if (write) {\n if (check.noReason.length > 0) return 1;\n writeFileSync(listFile, `${JSON.stringify(found, null, 2)}\\n`);\n io.stdout(`disables: wrote ${String(found.length)} comments to ${relative(io.cwd, listFile).replaceAll(\"\\\\\", \"/\")}\\n`);\n return 0;\n }\n const perFile = new Map<string, number>();\n for (const d of found) perFile.set(d.file, (perFile.get(d.file) ?? 0) + 1);\n io.stdout(`disables: ${String(found.length)} in ${String(perFile.size)} files\\n`);\n for (const [file, n] of perFile) io.stdout(` ${file}: ${String(n)}\\n`);\n for (const k of check.added) io.stderr(`not in the list: ${k}\\n`);\n for (const k of check.removed) io.stderr(`in the list, not in the sources: ${k}\\n`);\n if (check.added.length > 0 || check.removed.length > 0) {\n io.stderr(\"disables: the sources and the list are not the same. Add each new disable with its reason, or start with --write and examine the diff.\\n\");\n }\n return check.ok ? 0 : 1;\n}\n\n/** The options of `scores`. */\ninterface ScoresOptions {\n readonly report: string | undefined;\n readonly reports: string | undefined;\n readonly summary: string | undefined;\n readonly last: string | undefined;\n readonly writeLast: string | undefined;\n readonly testFiles: boolean;\n /** This field tells if the command gives no score of a package from its parts, for the job of one part. */\n readonly alone?: boolean;\n}\n\n/**\n * This function gives the score of each selection (`scores`). With `last`, it compares the test count with the last\n * good count (LANE.TESTS of Vex). With `testFiles`, it compares the test files that the run starts with the report (LANE.FILES).\n */\nfunction scores(lane: Lane, laneDir: string, names: readonly string[], o: ScoresOptions, io: CliIo): number {\n if (names.length === 0) throw new Error(`\"scores\" takes one or more selections`);\n if (o.report !== undefined && names.length > 1) throw new Error(`--report takes one selection`);\n if (o.report !== undefined && o.reports !== undefined) throw new Error(`\"scores\" takes --report or --reports, not both`);\n checkPartsOf(lane, laneDir, names);\n const lastFile = o.last === undefined ? undefined : resolve(io.cwd, o.last);\n const last = lastFile === undefined || !existsSync(lastFile) ? {} : readCounts(lastFile);\n if (lastFile !== undefined && !existsSync(lastFile)) io.stdout(`scores: the file ${o.last ?? \"\"} does not exist, so no count is compared\n`);\n const notes = new Map<string, string[]>(names.map((n) => [n, []]));\n const note = (name: string, line: string): void => void notes.get(name)?.push(line);\n const falls: PlannedFall[] = [];\n // The gate of a package with \"gateOver\": \"package\" reads the sum of its parts, so a part has no gate of its own.\n const byPackage = (s: Selection): boolean => s.name !== s.pkg && lane.packages[s.pkg]?.gateOver === \"package\";\n const results: Score[] = names.map((name) => {\n const all = select(lane, name);\n const s = byPackage(all) ? { ...all, gate: undefined } : all;\n if (s !== all) note(name, ` the gate of ${s.pkg} reads all its parts together`);\n const file =\n o.reports !== undefined\n ? resolve(io.cwd, o.reports, `mutation-${name}`, \"mutation.json\")\n : o.report === undefined\n ? resolve(laneDir, s.dir, REPORT_DIR, \"mutation.json\")\n : resolve(io.cwd, o.report);\n if (!existsSync(file)) {\n const reason = `the report ${relative(io.cwd, file)} does not exist`;\n return { name, gate: s.gate, detected: 0, hitLimit: 0, clockTimeouts: 0, valid: 0, survived: [], percent: 0, percentWithClock: 0, tests: undefined, pass: false, reason, outcome: \"no read\" };\n }\n const report = parseReport(readJson(file));\n let score = scoreReport(report, s);\n const before = last[name];\n if (lastFile !== undefined && before !== undefined) {\n if (score.tests === undefined) score = failScore(score, `the report has no \"testFiles\", so the count of the tests is not known`);\n else {\n const fall = testFall(score.tests, before, lane.maxTestFall ?? MAX_TEST_FALL);\n const planned = lane.plannedFalls?.[name];\n if (fall !== undefined && planned === undefined) score = failScore(score, fall);\n else if (fall !== undefined) {\n const text = `${fall.replace(/, so the score is no read$/, \"\")}. The reason: ${planned ?? \"\"}`;\n note(name, ` a planned fall: ${text}`);\n falls.push({ name, text });\n }\n }\n }\n if (o.testFiles) score = checkTestFiles(lane, laneDir, s, report, score, (line) => note(name, line));\n return score;\n });\n const packages = o.alone === true ? [] : names.map((n) => select(lane, n)).filter(byPackage).map((s) => s.pkg);\n const totals = [...new Set(packages)].map((pkg) => {\n const p = lane.packages[pkg];\n const parts = results.filter((r) => select(lane, r.name).pkg === pkg && r.name !== pkg);\n // A no read is never a pass: a part that the command does not name makes the package a no read.\n const missing = Object.keys(p?.parts ?? {})\n .map((part) => `${pkg}.${part}`)\n .filter((n) => !names.includes(n));\n return packageScore(pkg, p?.gate, parts, missing);\n });\n const shown = [...results, ...totals];\n for (const s of shown) {\n io.stdout(`${formatScore(s)}\n`);\n for (const line of notes.get(s.name) ?? []) io.stdout(`${line}\n`);\n if (!s.pass) for (const m of s.survived) io.stdout(` survived: ${m}\n`);\n }\n if (o.summary !== undefined) appendFileSync(resolve(io.cwd, o.summary), `### Mutation scores\n\n${summaryMarkdown(shown)}\n`);\n if (o.writeLast !== undefined) {\n const out = resolve(io.cwd, o.writeLast);\n const counts = { ...(existsSync(out) ? readCounts(out) : {}) };\n for (const s of results) if (s.pass && s.tests !== undefined) counts[s.name] = s.tests;\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, `${JSON.stringify(Object.fromEntries(Object.entries(counts).toSorted(([a], [b]) => (a < b ? -1 : 1))), null, 2)}\n`);\n }\n if (io.env?.[\"GITHUB_ACTIONS\"] === \"true\") for (const line of annotations(shown, falls)) io.stdout(`${line}\n`);\n const failed = shown.filter((s) => !s.pass).map((s) => s.name);\n if (failed.length > 0) io.stderr(`The gate failed for ${failed.join(\", \")}.\n`);\n return failed.length > 0 ? 1 : 0;\n}\n\n/** A fall of the test count that the lane plans, with its text. The score passes, and its annotation tells the fall. */\ninterface PlannedFall {\n readonly name: string;\n readonly text: string;\n}\n\n/** This function escapes the text of a workflow command of GitHub Actions. A property escapes also `:` and `,`. */\nconst escapeCommand = (text: string, property = false): string => {\n const data = text.replaceAll(\"%\", \"%25\").replaceAll(\"\\r\", \"%0D\").replaceAll(\"\\n\", \"%0A\");\n return property ? data.replaceAll(\":\", \"%3A\").replaceAll(\",\", \"%2C\") : data;\n};\n\n/**\n * This function gives a warning annotation for each score that does not pass and each planned fall. The annotation is on\n * the check line, so a no read is not a green check with the reason only in the log. This is true also for a run that\n * only reports. The title of a no read gives the count of the no reads and of the selections.\n */\nfunction annotations(results: readonly Score[], falls: readonly PlannedFall[]): string[] {\n const noReads = results.filter((s) => !s.pass && s.outcome !== \"block\");\n const line = (title: string, message: string): string => `::warning title=${escapeCommand(title, true)}::${escapeCommand(message)}`;\n return [\n ...noReads.map((s) => line(`Mutation gate: no read, ${String(noReads.length)} of ${String(results.length)} selections`, `${s.name}: ${s.reason ?? \"\"}`)),\n ...results.filter((s) => !s.pass && s.outcome === \"block\").map((s) => line(\"Mutation gate: under the gate\", `${s.name}: ${s.reason ?? \"\"}`)),\n ...falls.map((f) => line(\"Mutation gate: a planned fall of the tests\", `${f.name}: ${f.text}`)),\n ];\n}\n\n/** This function reads a file of test counts: an object from each selection to its count. */\nfunction readCounts(file: string): Record<string, number> {\n const json = readJson(file);\n const ok = typeof json === \"object\" && json !== null && !Array.isArray(json) && Object.values(json).every((n) => Number.isInteger(n) && (n as number) >= 0);\n if (!ok) throw new Error(`the file ${file} is not an object of test counts`);\n return json as Record<string, number>;\n}\n\n/** This function tells if the Vitest runner of a selection starts all the tests: the lane sets `vitest.related` to false. */\nfunction runsAllTests(s: Selection): boolean {\n const vitest = s.stryker?.[\"vitest\"];\n return typeof vitest === \"object\" && vitest !== null && (vitest as Record<string, unknown>)[\"related\"] === false;\n}\n\n/**\n * This function fails a score when the report does not read a test file that the run starts. The related mode of the\n * Vitest runner starts each test file that loads a file of the selection (LANE.FILES). So a part does not start the\n * test files of the other parts. With `vitest.related` false, the run starts each test file on the disk.\n */\nfunction checkTestFiles(lane: Lane, laneDir: string, s: Selection, report: MutationReport, score: Score, note: (line: string) => void): Score {\n const p = lane.packages[s.pkg];\n if (p === undefined) return score;\n const dir = resolve(laneDir, p.dir);\n if (report.testFiles === undefined) return failScore(score, `the report has no \"testFiles\", so the test files that it read are not known`);\n const files = sourcesOf(dir, dir, true).filter((f) => !f.endsWith(\".d.ts\"));\n const onDisk = files.filter((f) => TEST.test(f));\n const started = runsAllTests(s)\n ? onDisk\n : relatedTestFiles(\n files.map((file) => ({ file, text: readFileSync(resolve(dir, file), \"utf8\") })),\n (file) => globsSelect(s.mutate, file),\n );\n const unread = unreadTestFiles(report, started, p.notRead, dir);\n for (const f of unread) note(` not read: ${p.dir}/${f}`);\n if (unread.length === 0) return score;\n return failScore(score, `the report does not read ${String(unread.length)} test files that the run starts. Each one is no read, unless \"notRead\" of the package gives its reason`);\n}\n\n/** This function starts the CLI with its arguments and gives the exit code. */\nexport function runCli(argv: readonly string[], io: CliIo): number {\n const { values, positionals } = parseArgs({\n args: [...argv],\n allowPositionals: true,\n options: {\n lane: { type: \"string\", default: \"mutation.json\" },\n out: { type: \"string\" },\n concurrency: { type: \"string\" },\n report: { type: \"string\" },\n reports: { type: \"string\" },\n summary: { type: \"string\" },\n write: { type: \"boolean\", default: false },\n runs: { type: \"boolean\", default: false },\n \"dry-run\": { type: \"boolean\", default: false },\n changed: { type: \"string\" },\n last: { type: \"string\" },\n \"write-last\": { type: \"string\" },\n \"test-files\": { type: \"boolean\", default: false },\n alone: { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n },\n });\n const [command, ...names] = positionals;\n if (values.help || command === undefined) {\n io.stdout(HELP);\n return command === undefined && !values.help ? 1 : 0;\n }\n const laneFile = resolve(io.cwd, values.lane);\n const laneDir = dirname(laneFile);\n const lane = parseLane(readJson(laneFile));\n const changed =\n values.changed === undefined\n ? undefined\n : readFileSync(resolve(io.cwd, values.changed), \"utf8\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\");\n const one = (): string => {\n if (names.length !== 1 || names[0] === undefined) throw new Error(`\"${command}\" takes one selection`);\n return names[0];\n };\n switch (command) {\n case \"list\": {\n if (values.runs) checkParts(lane, laneDir, Object.keys(lane.packages));\n if (changed !== undefined && !values.runs) throw new Error(`--changed of \"list\" takes --runs`);\n const runs = values.runs ? runSelections(lane) : selectionNames(lane);\n const shown = changed === undefined ? runs : runs.filter((n) => changedFiles(select(lane, n), changed, existsIn(laneDir, select(lane, n))).length > 0);\n io.stdout(shown.length === 0 ? \"\" : `${shown.join(\"\\n\")}\\n`);\n return 0;\n }\n case \"dir\":\n io.stdout(`${relative(io.cwd, resolve(laneDir, select(lane, one()).dir)).replaceAll(\"\\\\\", \"/\") || \".\"}\\n`);\n return 0;\n case \"config\": {\n const concurrency = values.concurrency === undefined ? undefined : Number(values.concurrency);\n if (concurrency !== undefined && !(Number.isInteger(concurrency) && concurrency > 0)) throw new Error(`--concurrency is not a positive integer`);\n checkPartsOf(lane, laneDir, [one()]);\n const all = select(lane, one());\n const files = changed === undefined ? undefined : changedFiles(all, changed, existsIn(laneDir, all));\n if (files?.length === 0) throw new Error(`the selection ${all.name} has no changed file`);\n const selection = files === undefined ? all : { ...all, mutate: files };\n const tsconfigRewrite = rewritesTsconfig(typescriptMajor(resolve(laneDir, all.dir)));\n const options = { ...(concurrency === undefined ? {} : { concurrency }), dryRun: values[\"dry-run\"], tsconfigRewrite };\n const text = `${JSON.stringify(strykerConfig(selection, options), null, 2)}\\n`;\n if (values.out === undefined) io.stdout(text);\n else {\n mkdirSync(dirname(resolve(io.cwd, values.out)), { recursive: true });\n writeFileSync(resolve(io.cwd, values.out), text);\n }\n return 0;\n }\n case \"scores\":\n return scores(lane, laneDir, names, { report: values.report, reports: values.reports, summary: values.summary, last: values.last, writeLast: values[\"write-last\"], testFiles: values[\"test-files\"], alone: values.alone }, io);\n case \"disables\":\n return disables(lane, laneDir, values.write, io);\n case \"load-check\":\n return loadCheck(lane, laneDir, names, io);\n default:\n io.stderr(`unknown command \"${command}\"\\n\\n${HELP}`);\n return 1;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/rigor-mutation",
4
- "version": "0.1.7",
4
+ "version": "0.1.8",
5
5
  "description": "Mutation tests with Stryker and Vitest for each package of a repository: the Stryker config of each package or part, a score with a gate for each package, and a check of the disabled mutants.",
6
6
  "keywords": [
7
7
  "mutation",
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-DmIghD19.js","names":["TEST"],"sources":["../src/lane.ts","../src/config.ts","../src/score.ts","../src/disables.ts","../src/load.ts","../src/run.ts"],"sourcesContent":["import { matchesGlob, posix } from \"node:path\";\n\n/**\n * The lane file of a repository (`mutation.json`) names the packages that the mutation tests mutate. A package has\n * its folder, its globs and an optional gate. A big package has parts, so that each part has its own runner.\n */\n\n/** The mutation tests of one package. */\nexport interface PackageLane {\n /** This field gives the folder of the package, from the folder of the lane file. Stryker starts in this folder. */\n readonly dir: string;\n /**\n * These globs give the files to mutate, from `dir`. A glob with `!` removes the files of the globs before it. A glob\n * with the suffix `:<from>-<to>` gives only those lines of its files, as Stryker reads it.\n */\n readonly mutate: readonly string[];\n /**\n * Each part has its own globs. The `!` globs of `mutate` also apply to each part. Each file of `mutate` must be in\n * exactly one part, so that a full run mutates each file one time. Line ranges can cut one file into parts: then the\n * ranges of the parts must cover each line of the file one time. `partErrors` examines this.\n */\n readonly parts?: Readonly<Record<string, readonly string[]>>;\n /** This field gives the lowest mutation score in percent that passes. Without a gate, the lane only reports the score. */\n readonly gate?: number;\n /** This field gives the Vitest config file, from `dir`. Without it, Vitest finds its config in `dir`. */\n readonly vitestConfig?: string;\n /**\n * This field gives the time in milliseconds that the clock adds to the time of the tests for each mutant. The\n * default is 120000. A short time on a loaded runner stops mutants that the tests detect later.\n */\n readonly timeoutMS?: number;\n /** This field gives the time in minutes for the run of the tests without mutants. The default is 15. */\n readonly dryRunTimeoutMinutes?: number;\n /**\n * These options go into the Stryker config of each selection of the package, for example `ignoreStatic`. The lane\n * owns the keys of `STRYKER_OWNED`, so the field cannot have them.\n */\n readonly stryker?: Readonly<Record<string, unknown>>;\n /**\n * Each test file of this field is on the disk, and no report reads it. The value gives the reason. `scores\n * --test-files` fails for each other test file on the disk that the report does not read. The file is from `dir`.\n */\n readonly notRead?: Readonly<Record<string, string>>;\n}\n\n/** The keys of the Stryker config that the lane owns. The field `stryker` of a package cannot have them. */\nexport const STRYKER_OWNED: readonly string[] = [\"mutate\", \"thresholds\", \"jsonReporter\", \"htmlReporter\", \"timeoutMS\", \"dryRunTimeoutMinutes\"];\n\n/** The lane file: the packages of the mutation tests, and the list of the disabled mutants. */\nexport interface Lane {\n readonly packages: Readonly<Record<string, PackageLane>>;\n /** This field gives the list of the disabled mutants, from the folder of the lane file. The default is `mutation-disables.json`. */\n readonly disables?: string;\n /**\n * This field gives the highest fall of the test count in percent against the last good count. The default is 20.\n * `scores --last` fails a selection with a higher fall: the report did not read all the tests.\n */\n readonly maxTestFall?: number;\n /** Each selection of this field can have a higher fall of its test count. The value gives the reason. */\n readonly plannedFalls?: Readonly<Record<string, string>>;\n}\n\n/** The default of `maxTestFall` of the lane, in percent. */\nexport const MAX_TEST_FALL = 20;\n\n/** A selection is one Stryker run: a package (`collections`) or a part of a package (`collections.impl`). */\nexport interface Selection {\n readonly name: string;\n readonly pkg: string;\n readonly dir: string;\n readonly mutate: readonly string[];\n readonly gate: number | undefined;\n readonly vitestConfig: string | undefined;\n readonly timeoutMS: number | undefined;\n readonly dryRunTimeoutMinutes: number | undefined;\n readonly stryker: Readonly<Record<string, unknown>> | undefined;\n}\n\nconst NAME = /^[\\w-]+$/;\n\nconst isRecord = (x: unknown): x is Record<string, unknown> => typeof x === \"object\" && x !== null && !Array.isArray(x);\n\n/** This function tells if a value is an object of names, each with a reason that is not empty. */\nconst isReasons = (x: unknown): x is Record<string, string> => isRecord(x) && Object.values(x).every((r) => typeof r === \"string\" && r.trim() !== \"\");\n\nconst isGlobs = (x: unknown): x is string[] => Array.isArray(x) && x.length > 0 && x.every((g) => typeof g === \"string\" && g !== \"\");\n\n/** This function examines a package of the lane file. It gives the errors, with the name of the package. */\nfunction packageErrors(name: string, p: unknown): string[] {\n if (!NAME.test(name)) return [`the package name \"${name}\" has a character that is not a letter, a digit, \"_\" or \"-\"`];\n if (!isRecord(p)) return [`${name}: the package is not an object`];\n const errors: string[] = [];\n if (typeof p[\"dir\"] !== \"string\" || p[\"dir\"] === \"\") errors.push(`${name}: \"dir\" is not a folder name`);\n if (!isGlobs(p[\"mutate\"])) errors.push(`${name}: \"mutate\" is not a list of globs`);\n else if (p[\"mutate\"].every((g) => g.startsWith(\"!\"))) errors.push(`${name}: \"mutate\" has only \"!\" globs`);\n const gate = p[\"gate\"];\n if (gate !== undefined && (typeof gate !== \"number\" || !(gate >= 0 && gate <= 100))) errors.push(`${name}: \"gate\" is not a percent from 0 to 100`);\n if (p[\"vitestConfig\"] !== undefined && typeof p[\"vitestConfig\"] !== \"string\") errors.push(`${name}: \"vitestConfig\" is not a file name`);\n for (const field of [\"timeoutMS\", \"dryRunTimeoutMinutes\"]) {\n const v = p[field];\n if (v !== undefined && !(typeof v === \"number\" && Number.isInteger(v) && v > 0)) errors.push(`${name}: \"${field}\" is not a positive integer`);\n }\n const stryker = p[\"stryker\"];\n if (stryker !== undefined) {\n if (!isRecord(stryker)) errors.push(`${name}: \"stryker\" is not an object`);\n else {\n const owned = Object.keys(stryker).filter((k) => STRYKER_OWNED.includes(k));\n if (owned.length > 0) errors.push(`${name}: \"stryker\" has ${owned.map((k) => `\"${k}\"`).join(\", \")}, but the lane owns these keys`);\n }\n }\n if (p[\"notRead\"] !== undefined && !isReasons(p[\"notRead\"])) errors.push(`${name}: \"notRead\" is not an object of files, each with a reason`);\n const parts = p[\"parts\"];\n if (parts !== undefined) {\n if (!isRecord(parts) || Object.keys(parts).length === 0) errors.push(`${name}: \"parts\" is not an object with parts`);\n else {\n for (const [part, globs] of Object.entries(parts)) {\n if (!NAME.test(part)) errors.push(`${name}: the part name \"${part}\" has a character that is not a letter, a digit, \"_\" or \"-\"`);\n if (!isGlobs(globs) || globs.some((g) => g.startsWith(\"!\"))) errors.push(`${name}.${part}: the part is not a list of globs without \"!\"`);\n }\n }\n }\n return errors;\n}\n\n/**\n * This function examines the JSON of a lane file and gives the lane.\n *\n * @throws Error with each problem of the file\n */\nexport function parseLane(json: unknown): Lane {\n if (!isRecord(json) || !isRecord(json[\"packages\"])) throw new Error(`the lane has no object \"packages\"`);\n const errors = Object.entries(json[\"packages\"]).flatMap(([name, p]) => packageErrors(name, p));\n if (Object.keys(json[\"packages\"]).length === 0) errors.push(`the lane has no packages`);\n if (json[\"disables\"] !== undefined && typeof json[\"disables\"] !== \"string\") errors.push(`\"disables\" is not a file name`);\n const fall = json[\"maxTestFall\"];\n if (fall !== undefined && (typeof fall !== \"number\" || !(fall >= 0 && fall <= 100))) errors.push(`\"maxTestFall\" is not a percent from 0 to 100`);\n const planned = json[\"plannedFalls\"];\n if (planned !== undefined && !isReasons(planned)) errors.push(`\"plannedFalls\" is not an object of selections, each with a reason`);\n if (errors.length > 0) throw new Error(`the lane is not valid:\\n ${errors.join(\"\\n \")}`);\n const lane = json as unknown as Lane;\n const names = new Set(selectionNames(lane));\n const unknown = Object.keys(lane.plannedFalls ?? {}).filter((n) => !names.has(n));\n if (unknown.length > 0) throw new Error(`the lane is not valid:\\n \"plannedFalls\" names no selection of the lane: ${unknown.join(\", \")}`);\n return lane;\n}\n\n/** This function gives the names of all the selections of a lane: each package, then each part of the package. */\nexport function selectionNames(lane: Lane): string[] {\n return Object.entries(lane.packages).flatMap(([name, p]) => [name, ...Object.keys(p.parts ?? {}).map((part) => `${name}.${part}`)]);\n}\n\n/** This function gives the selections of a full run: the parts of each package with parts, else the package. Each file is in one run. */\nexport function runSelections(lane: Lane): string[] {\n return Object.entries(lane.packages).flatMap(([name, p]) => (p.parts === undefined ? [name] : Object.keys(p.parts).map((part) => `${name}.${part}`)));\n}\n\n/**\n * This function gives the selection of a name: a package, or a part of a package.\n *\n * @throws Error when the lane has no package or part of that name\n */\nexport function select(lane: Lane, name: string): Selection {\n const [pkg = \"\", part, ...rest] = name.split(\".\");\n const p = lane.packages[pkg];\n const globs = part === undefined ? undefined : p?.parts?.[part];\n if (p === undefined || rest.length > 0 || (part !== undefined && globs === undefined)) {\n throw new Error(`the lane has no package or part \"${name}\". It has: ${selectionNames(lane).join(\", \")}`);\n }\n // Stryker applies a \"!\" glob to the globs before it, so the \"!\" globs of the package go after the globs of the part.\n const mutate = globs === undefined ? p.mutate : [...globs, ...p.mutate.filter((g) => g.startsWith(\"!\"))];\n return { name, pkg, dir: p.dir, mutate, gate: p.gate, vitestConfig: p.vitestConfig, timeoutMS: p.timeoutMS, dryRunTimeoutMinutes: p.dryRunTimeoutMinutes, stryker: p.stryker };\n}\n\n/** A `mutate` entry with a range, as Stryker reads it: `src/a.ts:1-300`, or `src/a.ts:1:4-300:2` with columns. */\nconst RANGE = /^(.+?):(\\d+)(?::(\\d+))?-(\\d+)(?::(\\d+))?$/;\n\n/** This type is a `mutate` entry with a range of lines. */\ninterface LineRange {\n readonly entry: string;\n readonly glob: string;\n readonly from: number;\n readonly to: number;\n readonly columns: boolean;\n}\n\nfunction rangeOf(entry: string): LineRange | undefined {\n const m = RANGE.exec(entry);\n if (m?.[1] === undefined) return undefined;\n return { entry, glob: m[1], from: Number(m[2]), to: Number(m[4]), columns: m[3] !== undefined || m[5] !== undefined };\n}\n\n/** This function gives the glob of a `mutate` entry, with no range. */\nconst globOf = (entry: string): string => rangeOf(entry)?.glob ?? entry;\n\n/**\n * This function tells if globs select a file. It reads the globs as Stryker does. A glob adds its files. A glob with\n * `!` removes its files from the files of the globs before it. A glob with a line range selects its files.\n */\nexport function globsSelect(globs: readonly string[], file: string): boolean {\n let selected = false;\n for (const g of globs) {\n if (g.startsWith(\"!\")) {\n if (selected && matchesGlob(file, globOf(g.slice(1)))) selected = false;\n } else if (!selected && matchesGlob(file, globOf(g))) selected = true;\n }\n return selected;\n}\n\n/**\n * This function gives what globs select of a selected file. The value is \"all\" when a glob with no range selects the\n * file. Otherwise it is the line ranges of the file.\n */\nfunction coverOf(globs: readonly string[], file: string): \"all\" | LineRange[] {\n const adds = globs.filter((g) => !g.startsWith(\"!\") && matchesGlob(file, globOf(g)));\n if (adds.some((g) => rangeOf(g) === undefined)) return \"all\";\n return adds.flatMap((g) => rangeOf(g) ?? []);\n}\n\n/**\n * This function gives the changed files of a selection, from the folder of its package. The globs of the selection\n * select the files. A file that the selection takes in line ranges gives one entry for each range, `src/a.ts:1-300`.\n *\n * @param changed - the changed paths, from the folder of the lane file, with `/`\n */\nexport function changedFiles(selection: Selection, changed: readonly string[]): string[] {\n const dir = posix.normalize(selection.dir.replaceAll(\"\\\\\", \"/\"));\n return changed\n .map((f) => posix.relative(dir, posix.normalize(f.replaceAll(\"\\\\\", \"/\"))))\n .filter((f) => f !== \"\" && !f.startsWith(\"../\") && !posix.isAbsolute(f) && globsSelect(selection.mutate, f))\n .flatMap((f) => {\n const cover = coverOf(selection.mutate, f);\n return cover === \"all\" ? [f] : cover.map((r) => `${f}${r.entry.slice(r.glob.length)}`);\n });\n}\n\n/** This function gives the errors of the line ranges of one file in the parts of a package. */\nfunction rangeErrors(pkg: string, file: string, ranges: readonly { part: string; range: LineRange }[], lines: number | undefined): string[] {\n const errors: string[] = [];\n for (const { part, range } of ranges) {\n if (range.columns) errors.push(`${pkg}: the range ${range.entry} of the part ${part} has columns. A part can cut a file only by lines`);\n else if (range.from < 1 || range.from > range.to) errors.push(`${pkg}: the range ${range.entry} of the part ${part} has no lines`);\n }\n if (errors.length > 0) return errors;\n let next = 1;\n let last = \"\";\n for (const { part, range } of ranges.toSorted((x, y) => x.range.from - y.range.from || x.range.to - y.range.to)) {\n if (range.from > next) errors.push(`${pkg}: the lines ${String(next)}-${String(range.from - 1)} of ${file} are in no part`);\n else if (range.from < next) errors.push(`${pkg}: the lines ${String(range.from)}-${String(Math.min(range.to, next - 1))} of ${file} are in the parts ${last} and ${part}`);\n if (range.to >= next) {\n next = range.to + 1;\n last = part;\n }\n }\n if (lines !== undefined && next <= lines) errors.push(`${pkg}: the lines ${String(next)}-${String(lines)} of ${file} are in no part`);\n return errors;\n}\n\n/**\n * This function examines the parts of a package against its files. It gives an error for each file of `mutate` in no\n * part. It also gives an error for each file in two parts, and for each file of a part that is not in `mutate`. A\n * package with no parts has no errors.\n *\n * Parts can cut one file by line ranges. Then the function gives an error for each gap and each overlap of the\n * ranges. With `lines`, it also gives an error for the lines after the last range.\n *\n * @param files - the source files of the package, from its folder, with `/`\n * @param lines - this function gives the number of lines of a file of `files`\n */\nexport function partErrors(lane: Lane, pkg: string, files: readonly string[], lines?: (file: string) => number): string[] {\n const p = lane.packages[pkg];\n if (p?.parts === undefined) return [];\n const parts = Object.keys(p.parts).map((part) => ({ part, mutate: select(lane, `${pkg}.${part}`).mutate }));\n const errors: string[] = [];\n for (const file of files) {\n const inMutate = globsSelect(p.mutate, file);\n const inParts = parts.filter((x) => globsSelect(x.mutate, file)).map((x) => x.part);\n const covers = parts.filter((x) => inParts.includes(x.part)).map((x) => ({ part: x.part, cover: coverOf(x.mutate, file) }));\n const ranged = covers.every((x) => x.cover !== \"all\");\n if (inMutate && inParts.length === 0) errors.push(`${pkg}: the file ${file} is in no part, so a full run does not mutate it`);\n else if (inParts.length > 1 && !ranged) errors.push(`${pkg}: the file ${file} is in more than one part: ${inParts.join(\", \")}`);\n else if (!inMutate && inParts.length > 0) errors.push(`${pkg}: the file ${file} is in the part ${inParts.join(\", \")}, but not in \"mutate\"`);\n else if (inParts.length > 0 && ranged) {\n const ranges = covers.flatMap((x) => (x.cover === \"all\" ? [] : x.cover.map((range) => ({ part: x.part, range }))));\n errors.push(...rangeErrors(pkg, file, ranges, lines?.(file)));\n }\n }\n return errors;\n}\n","import type { Selection } from \"./lane.ts\";\n\n/** The options of `strykerConfig`. */\nexport interface ConfigOptions {\n /** This option gives the number of test processes. The default is 2. */\n readonly concurrency?: number;\n /** This option gives the folder of the reports, from the folder of the package. The default is `reports/mutation`. */\n readonly reportDir?: string;\n /**\n * When this option is true, Stryker starts only the tests without mutants, and it does not stop at the first failed\n * test. Use it to see if the tests pass under Stryker before a long run.\n */\n readonly dryRun?: boolean;\n /**\n * When this option is false, Stryker does not rewrite the tsconfig of the package in its sandbox. The default is true.\n * The rewrite uses `parseConfigFileTextToJson`, and TypeScript 7 does not have it. Refer to `rewritesTsconfig`.\n */\n readonly tsconfigRewrite?: boolean;\n}\n\n/** The Stryker config of one selection, as JSON. Stryker starts in the folder of the package. The field `stryker` of the lane adds keys. */\nexport interface StrykerConfig {\n readonly [key: string]: unknown;\n readonly testRunner: \"vitest\";\n readonly plugins: readonly string[];\n readonly vitest?: { readonly configFile: string };\n readonly mutate: readonly string[];\n readonly coverageAnalysis: \"perTest\";\n readonly reporters: readonly string[];\n readonly htmlReporter: { readonly fileName: string };\n readonly jsonReporter: { readonly fileName: string };\n readonly thresholds: { readonly high: number; readonly low: number; readonly break: null };\n readonly concurrency: number;\n readonly timeoutMS: number;\n readonly dryRunTimeoutMinutes: number;\n readonly tsconfigFile?: string;\n readonly dryRunOnly?: true;\n readonly disableBail?: true;\n}\n\n/** The default folder of the reports, from the folder of the package. */\nexport const REPORT_DIR = \"reports/mutation\";\n\n/**\n * The default time in milliseconds that the clock adds to the time of the tests for each mutant. The default of\n * Stryker is 5000. On a loaded CI runner that time stopped mutants that the tests detected later.\n */\nexport const TIMEOUT_MS = 120_000;\n\n/**\n * The value of `tsconfigFile` when the rewrite of the tsconfig is off. No project has this file, so Stryker finds no\n * tsconfig to rewrite.\n */\nexport const NO_TSCONFIG = \"tsconfig.no-stryker-rewrite.json\";\n\n/**\n * This function tells if Stryker can rewrite a tsconfig with a TypeScript of the major version `major`. Stryker 10.1\n * parses the tsconfig with `parseConfigFileTextToJson`, and TypeScript 7 removed it. When no TypeScript is found, the\n * answer is true, and the config keeps the default of Stryker.\n */\nexport function rewritesTsconfig(major: number | undefined): boolean {\n return major === undefined || major < 7;\n}\n\n/** The default time in minutes for the run of the tests without mutants. The default of Stryker is 5. */\nexport const DRY_RUN_TIMEOUT_MINUTES = 15;\n\n/**\n * This function gives the Stryker config of a selection. The break of Stryker is off, because the gate of each\n * package is in `scoreReport`. Stryker 10.1.0 or later is necessary with Vitest 5: version 10.0 started no test on each\n * mutant (stryker-js issue 6210).\n */\nexport function strykerConfig(selection: Selection, options: ConfigOptions = {}): StrykerConfig {\n const reportDir = options.reportDir ?? REPORT_DIR;\n const low = selection.gate ?? 60;\n return {\n testRunner: \"vitest\",\n plugins: [\"@stryker-mutator/vitest-runner\"],\n ...(selection.vitestConfig === undefined ? {} : { vitest: { configFile: selection.vitestConfig } }),\n mutate: selection.mutate,\n coverageAnalysis: \"perTest\",\n reporters: [\"clear-text\", \"progress\", \"html\", \"json\"],\n htmlReporter: { fileName: `${reportDir}/index.html` },\n jsonReporter: { fileName: `${reportDir}/mutation.json` },\n thresholds: { high: Math.max(low, 90), low, break: null },\n concurrency: options.concurrency ?? 2,\n timeoutMS: selection.timeoutMS ?? TIMEOUT_MS,\n dryRunTimeoutMinutes: selection.dryRunTimeoutMinutes ?? DRY_RUN_TIMEOUT_MINUTES,\n ...(options.tsconfigRewrite === false ? { tsconfigFile: NO_TSCONFIG } : {}),\n // The keys of the lane field \"stryker\" replace the keys above, but \"--concurrency\" replaces its \"concurrency\".\n ...selection.stryker,\n ...(options.concurrency === undefined ? {} : { concurrency: options.concurrency }),\n ...(options.dryRun === true ? { dryRunOnly: true, disableBail: true } : {}),\n };\n}\n","/**\n * The score of a Stryker report, with the gate of the package. The score counts the detected mutants, out of the\n * mutants that a test covers or that survive. Compile errors, runtime errors and ignored mutants do not count.\n *\n * Stryker gives the status `Timeout` for two events. The hit limit stops a mutant with an endless loop: its\n * `statusReason` starts with `Hit limit`, and the mutant is detected. The clock stops a mutant that took too long. The\n * load of the runner can cause this. Thus the mutant is not detected for certain, and it counts as not detected.\n */\n\n/** A mutant of the JSON report of Stryker (the schema of mutation-testing-elements). */\nexport interface Mutant {\n readonly status: string;\n readonly mutatorName: string;\n /** Stryker gives the reason of some statuses here. A `Timeout` of the hit limit has a reason that starts with `Hit limit`. */\n readonly statusReason?: string | undefined;\n readonly location: { readonly start: { readonly line: number } };\n}\n\n/** The JSON report of Stryker: the mutants of each mutated file, and the tests of each test file that the run read. */\nexport interface MutationReport {\n readonly files: Readonly<Record<string, { readonly mutants: readonly Mutant[] }>>;\n /** Stryker gives this field when the test runner tells the tests, as the Vitest runner does. */\n readonly testFiles?: Readonly<Record<string, { readonly tests: readonly { readonly name: string }[] }>> | undefined;\n}\n\n/**\n * The three reads of a score. A `block` is a score under its gate. A `no read` is a score that does not read the tests.\n * Its cause is no report, no mutant that counts, no detected mutant, or a run that did not read all the tests. A no read is not a pass.\n */\nexport type ScoreOutcome = \"pass\" | \"block\" | \"no read\";\n\n/** The score of one selection. */\nexport interface Score {\n readonly name: string;\n readonly gate: number | undefined;\n /** The mutants with the status `Killed`, and the mutants that the hit limit stopped. */\n readonly detected: number;\n /** The mutants that the hit limit stopped. They are in `detected`. */\n readonly hitLimit: number;\n /** The mutants that the clock stopped. They count as not detected, and they are in `survived`. */\n readonly clockTimeouts: number;\n /** The mutants that count: detected, survived or with no coverage. */\n readonly valid: number;\n /** Each mutant that survived, had no coverage or was stopped by the clock, as `file:line Mutator`. */\n readonly survived: readonly string[];\n /** The score in percent. It is 0 when no mutant counts. */\n readonly percent: number;\n /** The score in percent with the clock time-outs counted as detected, as Stryker counts them. The gate does not read it. */\n readonly percentWithClock: number;\n /** The count of the tests that the run read, from `testFiles` of the report. It is undefined when the report has no `testFiles`. */\n readonly tests: number | undefined;\n readonly pass: boolean;\n /** The reason of a failure. */\n readonly reason: string | undefined;\n /** The read of the score. The functions of this package always give it. A score from an older version has no outcome. */\n readonly outcome?: ScoreOutcome;\n}\n\nconst UNDETECTED = new Set([\"Survived\", \"NoCoverage\"]);\n\n/** This function tells if the hit limit of Stryker stopped a mutant. Then the mutant has an endless loop, and it is detected. */\nexport const isHitLimit = (m: Mutant): boolean => m.status === \"Timeout\" && (m.statusReason ?? \"\").startsWith(\"Hit limit\");\n\n/**\n * This function examines the JSON of a Stryker report and gives the report.\n *\n * @throws Error when the JSON has no files with mutants\n */\nexport function parseReport(json: unknown): MutationReport {\n const files = typeof json === \"object\" && json !== null ? (json as { files?: unknown }).files : undefined;\n if (typeof files !== \"object\" || files === null) throw new Error(`the report has no object \"files\"`);\n for (const [file, data] of Object.entries(files)) {\n if (!Array.isArray((data as { mutants?: unknown } | null)?.mutants)) throw new Error(`the report has no list \"mutants\" for ${file}`);\n }\n const testFiles = (json as { testFiles?: unknown }).testFiles;\n if (testFiles !== undefined) {\n if (typeof testFiles !== \"object\" || testFiles === null) throw new Error(`the field \"testFiles\" of the report is not an object`);\n for (const [file, data] of Object.entries(testFiles)) {\n if (!Array.isArray((data as { tests?: unknown } | null)?.tests)) throw new Error(`the report has no list \"tests\" for the test file ${file}`);\n }\n }\n return json as MutationReport;\n}\n\n/** This function gives the count of the tests of a report, or undefined when the report has no `testFiles`. */\nexport function testCount(report: MutationReport): number | undefined {\n if (report.testFiles === undefined) return undefined;\n return Object.values(report.testFiles).reduce((sum, f) => sum + f.tests.length, 0);\n}\n\n/**\n * This function compares a test count with the last good count. It gives the reason of a failure when the count fell\n * by more than `maxFall` percent, else undefined. A report that reads fewer tests is no read of the score.\n *\n * @param maxFall - the highest fall in percent that passes\n */\nexport function testFall(tests: number, last: number, maxFall: number): string | undefined {\n if (last <= 0 || tests >= last) return undefined;\n const fall = (100 * (last - tests)) / last;\n if (fall <= maxFall) return undefined;\n return `the run read ${String(tests)} tests, ${fall.toFixed(1)} % fewer than the last good count ${String(last)} (the limit is ${String(maxFall)} %), so the score is no read`;\n}\n\n/**\n * This function gives each test file on the disk that the report does not read, and that `notRead` does not name.\n * The files of the report and of the disk are from the folder of the package.\n *\n * @param onDisk - the test files of the package, from its folder, with `/`\n * @param dir - the folder of the package, to make a full path of the report relative\n */\nexport function unreadTestFiles(report: MutationReport, onDisk: readonly string[], notRead: Readonly<Record<string, string>> = {}, dir = \"\"): string[] {\n const root = dir.replaceAll(\"\\\\\", \"/\").replace(/\\/?$/, \"/\");\n const read = new Set(\n Object.keys(report.testFiles ?? {}).map((f) => {\n const file = f.replaceAll(\"\\\\\", \"/\");\n return dir !== \"\" && file.startsWith(root) ? file.slice(root.length) : file.replace(/^\\.\\//, \"\");\n }),\n );\n return onDisk.filter((f) => !read.has(f) && notRead[f] === undefined);\n}\n\n/**\n * This function gives a score that fails for a reason, with the outcome `no read`. A score that failed already keeps its\n * first reason, and gets the new one after it. A score under its gate with a second reason is also a no read.\n */\nexport function failScore(score: Score, reason: string): Score {\n return { ...score, pass: false, outcome: \"no read\", reason: score.reason === undefined ? reason : `${score.reason}. Also ${reason}` };\n}\n\n/**\n * This function gives the score of a report and applies the gate. A report with no mutants that count fails, also\n * without a gate: Stryker found no files. A report with mutants that count and none detected also fails: the test\n * runner started no test on the mutants. Stryker 10.0 with Vitest 5 gave this result.\n */\nexport function scoreReport(report: MutationReport, selection: { readonly name: string; readonly gate: number | undefined }): Score {\n let detected = 0;\n let valid = 0;\n let hitLimit = 0;\n let clockTimeouts = 0;\n const survived: string[] = [];\n for (const [file, data] of Object.entries(report.files)) {\n for (const m of data.mutants) {\n const at = `${file}:${String(m.location.start.line)} ${m.mutatorName}`;\n if (m.status === \"Killed\" || isHitLimit(m)) {\n detected++;\n valid++;\n if (m.status === \"Timeout\") hitLimit++;\n } else if (m.status === \"Timeout\") {\n clockTimeouts++;\n valid++;\n survived.push(`${at} (the clock stopped it)`);\n } else if (UNDETECTED.has(m.status)) {\n valid++;\n survived.push(at);\n }\n }\n }\n const percent = valid === 0 ? 0 : (100 * detected) / valid;\n const percentWithClock = valid === 0 ? 0 : (100 * (detected + clockTimeouts)) / valid;\n const { name, gate } = selection;\n const [outcome, reason]: [ScoreOutcome, string | undefined] =\n valid === 0\n ? [\"no read\", \"the report has no mutants that count: Stryker found no files to mutate, or it did not start\"]\n : detected === 0\n ? [\"no read\", `the tests detected none of the ${String(valid)} mutants: the test runner started no test on the mutants`]\n : gate !== undefined && percent < gate\n ? [\"block\", `the score ${percent.toFixed(2)} % is under the gate ${String(gate)} %`]\n : [\"pass\", undefined];\n return { name, gate, detected, hitLimit, clockTimeouts, valid, survived, percent, percentWithClock, tests: testCount(report), pass: reason === undefined, reason, outcome };\n}\n\n/** This function gives the time-outs of a score as text: the count of each kind, and the score that counts the clock time-outs as detected. */\nconst timeouts = (s: Score): string =>\n `time-outs: ${String(s.hitLimit)} hit limit, ${String(s.clockTimeouts)} clock (${s.percentWithClock.toFixed(2)} % with the clock time-outs as detected)`;\n\n/** This function gives one line for a score, with the name of the selection and its result. The time-outs are in it when the report has some. */\nexport function formatScore(s: Score): string {\n const gate = s.gate === undefined ? \"no gate\" : `gate ${String(s.gate)} %`;\n const result = s.pass ? \"pass\" : `FAIL: ${s.reason ?? \"\"}`;\n const time = s.hitLimit + s.clockTimeouts === 0 ? \"\" : `, ${timeouts(s)}`;\n const tests = s.tests === undefined ? \"\" : `, ${String(s.tests)} tests`;\n return `${s.name}: ${s.percent.toFixed(2)} % (${String(s.detected)} of ${String(s.valid)}, ${String(s.survived.length)} survived${time}${tests}), ${gate}: ${result}`;\n}\n\n/** This function gives a Markdown table of scores, for the summary of a CI job. */\nexport function summaryMarkdown(scores: readonly Score[]): string {\n const rows = scores.map(\n (s) =>\n `| ${s.name} | ${s.percent.toFixed(2)} % | ${String(s.detected)} | ${String(s.valid)} | ${String(s.survived.length)} | ${String(s.clockTimeouts)} | ${s.percentWithClock.toFixed(2)} % | ${s.gate === undefined ? \"none\" : `${String(s.gate)} %`} | ${s.pass ? \"pass\" : `fail: ${s.reason ?? \"\"}`} | ${s.tests === undefined ? \"?\" : String(s.tests)} |`,\n );\n return [\n \"| Selection | Score | Detected | Valid | Survived | Clock time-outs | Score with them | Gate | Result | Tests |\",\n \"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | ---: |\",\n ...rows,\n \"\",\n ].join(\"\\n\");\n}\n","/**\n * A comment `// Stryker disable next-line <Mutator>: <reason>` disables a mutant that is equivalent. The disable\n * raises the score, so each one is also in a list with its reason. These functions find the comments in the\n * sources and compare them with the list.\n */\n\n/** One disable comment of a source file. */\nexport interface Disable {\n readonly file: string;\n readonly comment: string;\n}\n\n/** The result of `compareDisables`. */\nexport interface DisableCheck {\n /** The comments of the sources that are not in the list, as `file: comment`. */\n readonly added: readonly string[];\n /** The comments of the list that are not in the sources, as `file: comment`. */\n readonly removed: readonly string[];\n /** The comments with no reason after a colon. */\n readonly noReason: readonly Disable[];\n readonly ok: boolean;\n}\n\n/** This function finds each `Stryker disable` comment of the files. A file name uses `/`. */\nexport function findDisables(files: readonly { readonly file: string; readonly text: string }[]): Disable[] {\n return files.flatMap(({ file, text }) =>\n text\n .split(\"\\n\")\n .filter((line) => line.includes(\"Stryker disable\"))\n .map((line) => ({ file, comment: line.trim() })),\n );\n}\n\nconst counts = (xs: readonly Disable[]): Map<string, number> => {\n const m = new Map<string, number>();\n for (const x of xs) {\n const k = `${x.file}: ${x.comment}`;\n m.set(k, (m.get(k) ?? 0) + 1);\n }\n return m;\n};\n\n/**\n * This function tells if a comment has a reason: a mutator name, a colon, a space and a text. It reads the text by\n * index, so its time is linear in the length of the comment (a regular expression here was quadratic).\n */\nfunction hasReason(comment: string): boolean {\n const start = comment.indexOf(\"Stryker disable \");\n if (start < 0) return false;\n const rest = comment.slice(start + \"Stryker disable \".length);\n const colon = rest.indexOf(\":\");\n return colon > 0 && rest[colon + 1] === \" \" && /\\S/.test(rest[colon + 2] ?? \"\");\n}\n\n/** This function compares the comments of the sources with the list. A file with the same comment two times needs it two times in the list. */\nexport function compareDisables(found: readonly Disable[], listed: readonly Disable[]): DisableCheck {\n const noReason = found.filter((d) => !hasReason(d.comment));\n const a = counts(found);\n const b = counts(listed);\n const added = [...a].filter(([k, n]) => n > (b.get(k) ?? 0)).map(([k]) => k);\n const removed = [...b].filter(([k, n]) => n > (a.get(k) ?? 0)).map(([k]) => k);\n return { added, removed, noReason, ok: added.length === 0 && removed.length === 0 && noReason.length === 0 };\n}\n","/**\n * The load check. Stryker copies the folder of a package to `<dir>/.stryker-tmp/sandbox-*` and starts the tests there.\n * A relative path that leaves the folder then finds no file. A test file that does not load gives no failed test, so\n * each mutant that it detects survives with no error (V-072 of Vex). This check finds these paths before Stryker. It\n * reads only the files that the run loads, so a script of the folder that no test loads can leave the folder.\n */\nimport { posix } from \"node:path\";\n\n/** A relative path in a file of a package that leaves the folder of the package. */\nexport interface LeavingPath {\n /** The file, from the folder of the package, with `/`. */\n readonly file: string;\n /** The line of the path, from 1. */\n readonly line: number;\n /** The path as the file writes it. */\n readonly path: string;\n}\n\n/** A file of a package and its text. */\nexport interface PackageFile {\n /** The file, from the folder of the package, with `/`. */\n readonly file: string;\n readonly text: string;\n}\n\n// The paths that a module loads: import and export from, import(), require(), vi.mock() and the other vi functions,\n// and new URL(path, import.meta.url).\n// The optional \"(\" and its spaces are one group, so that each space has one match (no slow backtracking).\nconst LOADED = /(?:\\bfrom|\\bimport|\\brequire|\\bvi\\.\\w+|\\bnew\\s+URL)\\s*(?:\\(\\s*)?([\"'`])([^\"'`\\r\\n]*)\\1/g;\n// Each relative path string of a config file, for example setupFiles: [\"../testkit/setup.ts\"].\nconst CONFIG_PATH = /([\"'`])(\\.\\.?\\/[^\"'`\\r\\n]*)\\1/g;\n// A type import or export: the test runner removes it, so it loads no file.\nconst TYPE_ONLY = /^\\s*(?:import|export)\\s+type\\b/;\nconst COMMENT = /^\\s*(?:\\/\\/|\\/\\*|\\*)/;\nconst CONFIG_FILE = /(?:^|\\/)vite(?:st)?\\.(?:config|workspace)\\.[cm]?[jt]s$/;\n\n/**\n * This function tells if a file is a config file of Vitest or Vite. Each relative path string of a config file must\n * stay in the folder.\n *\n * @param vitestConfig - the field `vitestConfig` of the lane, from the folder of the package\n */\nexport function isConfigFile(file: string, vitestConfig?: string): boolean {\n return CONFIG_FILE.test(file) || (vitestConfig !== undefined && posix.normalize(vitestConfig.replaceAll(\"\\\\\", \"/\")) === file);\n}\n\nfunction leaves(file: string, path: string): boolean {\n if (!(path === \".\" || path === \"..\" || path.startsWith(\"./\") || path.startsWith(\"../\")) || path.includes(\"${\")) return false;\n const target = posix.normalize(posix.join(posix.dirname(file), path));\n return target === \"..\" || target.startsWith(\"../\");\n}\n\nconst TEST = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/;\nconst EXTENSIONS = [\"\", \".ts\", \".tsx\", \".mts\", \".cts\", \".js\", \".mjs\", \".cjs\", \"/index.ts\", \"/index.js\"];\n\n/** This function gives each relative path of one file, with its line. It does not read comments and type imports. */\nfunction pathsOf(file: string, text: string, vitestConfig: string | undefined): { line: number; path: string }[] {\n const pattern = isConfigFile(file, vitestConfig) ? CONFIG_PATH : LOADED;\n return text.split(\"\\n\").flatMap((lineText, i) => {\n if (COMMENT.test(lineText) || TYPE_ONLY.test(lineText)) return [];\n return [...lineText.matchAll(pattern)].map((m) => ({ line: i + 1, path: m[2] ?? \"\" })).filter((p) => p.path.startsWith(\".\"));\n });\n}\n\n/** This function gives the file of the package that a relative path in the folder loads, or undefined. */\nfunction target(file: string, path: string, known: ReadonlySet<string>): string | undefined {\n const base = posix.normalize(posix.join(posix.dirname(file), path));\n const stem = base.replace(/\\.(?:[cm]?js|jsx)$/, \"\");\n return [...EXTENSIONS.map((e) => base + e), ...EXTENSIONS.slice(1).map((e) => stem + e)].find((f) => known.has(f));\n}\n\n/**\n * This function gives each relative path of the files that leaves the folder of the package. It reads the files that\n * the run loads. These are the test files, the config files, and each file that they load in the folder.\n * In a config file it reads each relative path string, for example a setup file. It does not read comments and type\n * imports.\n *\n * @param files - the files of the package, from its folder\n * @param vitestConfig - the field `vitestConfig` of the lane\n */\nexport function leavingPaths(files: readonly PackageFile[], vitestConfig?: string): LeavingPath[] {\n const texts = new Map(files.map((f) => [f.file, f.text]));\n const known = new Set(texts.keys());\n const queue = files.map((f) => f.file).filter((f) => TEST.test(f) || isConfigFile(f, vitestConfig));\n const loaded = new Set(queue);\n const found: LeavingPath[] = [];\n for (let next = queue.shift(); next !== undefined; next = queue.shift()) {\n for (const { line, path } of pathsOf(next, texts.get(next) ?? \"\", vitestConfig)) {\n if (leaves(next, path)) found.push({ file: next, line, path });\n else {\n const t = target(next, path, known);\n if (t !== undefined && !loaded.has(t)) {\n loaded.add(t);\n queue.push(t);\n }\n }\n }\n }\n return found.toSorted((a, b) => (a.file === b.file ? a.line - b.line : a.file < b.file ? -1 : 1));\n}\n\n// A type import or export to its semicolon, also on more than one line. The test runner removes it.\nconst TYPE_STATEMENT = /^[ \\t]*(?:import|export)[ \\t]+type\\b[^;]*;/gm;\n\n/** This function replaces each type import and export with its line ends, so the lines of the other paths stay. */\nfunction withoutTypeStatements(text: string): string {\n return text.replace(TYPE_STATEMENT, (statement) => statement.replace(/[^\\n]/g, \"\"));\n}\n\n/**\n * This function gives the test files that the related mode of the Vitest runner starts for a selection. A test file\n * is related when it loads a file of the selection, directly or through other files of the package. The function\n * does not read comments and type imports. The order is the order of `files`.\n *\n * @param files - the files of the package, from its folder\n * @param selected - the function that tells if a file is a file of the selection\n */\nexport function relatedTestFiles(files: readonly PackageFile[], selected: (file: string) => boolean): string[] {\n const texts = new Map(files.map((f) => [f.file, withoutTypeStatements(f.text)]));\n const known = new Set(texts.keys());\n const loads = (file: string): string[] =>\n pathsOf(file, texts.get(file) ?? \"\", undefined).flatMap(({ path }) => {\n const t = target(file, path, known);\n return t === undefined ? [] : [t];\n });\n const reaches = (test: string): boolean => {\n const queue = [test];\n const loaded = new Set(queue);\n for (let next = queue.shift(); next !== undefined; next = queue.shift()) {\n for (const t of loads(next)) {\n if (!TEST.test(t) && selected(t)) return true;\n if (!loaded.has(t)) {\n loaded.add(t);\n queue.push(t);\n }\n }\n }\n return false;\n };\n return files.map((f) => f.file).filter((f) => TEST.test(f) && reaches(f));\n}\n","/**\n * The CLI `rigor-mutation`. The work is in `runCli`, so a test can start the CLI in a fixture folder.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, appendFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, relative, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { REPORT_DIR, rewritesTsconfig, strykerConfig } from \"./config.ts\";\nimport { compareDisables, findDisables, type Disable } from \"./disables.ts\";\nimport { leavingPaths, relatedTestFiles } from \"./load.ts\";\nimport { changedFiles, globsSelect, MAX_TEST_FALL, parseLane, partErrors, runSelections, select, selectionNames, type Lane, type Selection } from \"./lane.ts\";\nimport { failScore, formatScore, parseReport, scoreReport, summaryMarkdown, testFall, unreadTestFiles, type MutationReport, type Score } from \"./score.ts\";\n\n/** The input and the output of the CLI. */\nexport interface CliIo {\n readonly cwd: string;\n readonly stdout: (text: string) => void;\n readonly stderr: (text: string) => void;\n /** The environment. With `GITHUB_ACTIONS` set to `true`, `scores` writes an annotation for each score that does not pass and each planned fall. */\n readonly env?: Readonly<Record<string, string | undefined>>;\n}\n\n/** The help text of the CLI. */\nexport const HELP: string = `rigor-mutation: the mutation tests of a repository, with Stryker and a gate for each package.\n\n rigor-mutation list [--runs] [--changed <file>]\n the packages and the parts of the lane. With --runs, the\n selections of a full run: the parts of a package with parts.\n With --changed, only the runs with a changed file.\n rigor-mutation dir <selection> the folder of the package of a selection\n rigor-mutation config <selection> [--out <file>] [--concurrency <n>] [--dry-run] [--changed <file>]\n the Stryker config of a selection, as JSON. With --dry-run,\n Stryker starts only the tests. With --changed, it mutates only\n the changed files of the selection.\n rigor-mutation scores <selection>... [--report <file>] [--summary <file>] [--last <file>]\n [--write-last <file>] [--test-files]\n the score of each selection, with its gate and its count\n of tests. With --last, a fall of the count of more than\n maxTestFall % (default 20) against the file fails. With\n --write-last, the counts of the passed selections go in\n the file. With --test-files, a test file that the run\n starts and that the report does not read fails.\n rigor-mutation disables [--write] compare the disable comments with their list\n rigor-mutation load-check [<selection>...] refuse each relative path of a package that leaves its folder.\n Stryker starts the tests in a copy of the folder, so such a\n path finds no file. No selection checks each package.\n\n --lane <file> the lane file. The default is mutation.json.\n --changed <file> a file with one changed path on each line, from the folder of the lane file,\n for example the output of git diff --name-only.\n\nA selection is a package (\"collections\") or a part of a package (\"collections.impl\").\nEach file of a package with parts must be in exactly one part. list --runs, and config and scores\nof a part, fail when it is not.\nThe score of a selection reads <dir>/${REPORT_DIR}/mutation.json, or the file of --report.\n`;\n\nconst SOURCE = /\\.(?:[cm]?[jt]s|tsx)$/;\nconst TEST = /\\.(?:test|spec)\\.[^.]+$/;\nconst SKIP = new Set([\"node_modules\", \"build\", \"dist\", \"reports\", \"coverage\"]);\n\n/**\n * This function gives each source file of a folder, from `root`, with `/`. It skips the outputs and the dot folders,\n * and the tests when `tests` is false.\n */\nfunction sourcesOf(root: string, dir: string, tests = false): string[] {\n return readdirSync(dir, { withFileTypes: true })\n .toSorted((x, y) => x.name.localeCompare(y.name))\n .flatMap((e) => {\n const path = resolve(dir, e.name);\n if (e.isDirectory()) return e.name.startsWith(\".\") || SKIP.has(e.name) ? [] : sourcesOf(root, path, tests);\n return e.isFile() && SOURCE.test(e.name) && (tests || !TEST.test(e.name)) ? [relative(root, path).replaceAll(\"\\\\\", \"/\")] : [];\n });\n}\n\n/** This function checks the relative paths of the package of each selection (`load-check`). */\nfunction loadCheck(lane: Lane, laneDir: string, names: readonly string[], io: CliIo): number {\n const pkgs = [...new Set((names.length === 0 ? Object.keys(lane.packages) : names.map((n) => select(lane, n).pkg)))];\n let failed = 0;\n for (const pkg of pkgs) {\n const s = select(lane, pkg);\n const dir = resolve(laneDir, s.dir);\n if (!existsSync(dir)) throw new Error(`${pkg}: the folder ${s.dir} does not exist`);\n const files = sourcesOf(dir, dir, true)\n .filter((f) => !f.endsWith(\".d.ts\"))\n .map((file) => ({ file, text: readFileSync(resolve(dir, file), \"utf8\") }));\n const found = leavingPaths(files, s.vitestConfig);\n for (const p of found) {\n io.stderr(`${s.dir}/${p.file}:${String(p.line)}: \"${p.path}\" leaves the folder ${s.dir}. In the copy of Stryker it finds no file.\n`);\n }\n if (found.length === 0) io.stdout(`load-check ${pkg}: ${String(files.length)} files, no relative path leaves ${s.dir}\n`);\n else failed += 1;\n }\n if (failed > 0) io.stderr(`load-check: ${String(failed)} packages have a relative path that leaves their folder. Import the file from its package, or move it into the folder.\n`);\n return failed > 0 ? 1 : 0;\n}\n\nconst readJson = (file: string): unknown => JSON.parse(readFileSync(file, \"utf8\"));\n\n/**\n * This function gives the major version of the `typescript` that the folder `dir` resolves, or undefined when the\n * folder resolves none. In a usual install, Stryker resolves the same version, because it starts in that folder.\n */\nfunction typescriptMajor(dir: string): number | undefined {\n let file: string;\n try {\n file = createRequire(join(dir, \"package.json\")).resolve(\"typescript/package.json\");\n } catch {\n return undefined;\n }\n const version: unknown = (readJson(file) as { version?: unknown }).version;\n const major = typeof version === \"string\" ? Number.parseInt(version, 10) : Number.NaN;\n return Number.isInteger(major) ? major : undefined;\n}\n\n/**\n * This function examines the parts of the packages against their source files.\n *\n * @throws Error with each file that is in no part, in more than one part, or in a part and not in `mutate`\n */\n/** This function gives the number of lines of a text. A last line break does not start a line. */\nconst lineCount = (text: string): number => (text === \"\" ? 0 : text.split(\"\\n\").length - (text.endsWith(\"\\n\") ? 1 : 0));\n\nfunction checkParts(lane: Lane, laneDir: string, pkgs: readonly string[]): void {\n const errors = pkgs.flatMap((pkg) => {\n const p = lane.packages[pkg];\n if (p?.parts === undefined) return [];\n const dir = resolve(laneDir, p.dir);\n if (!existsSync(dir)) return [`${pkg}: the folder ${p.dir} does not exist`];\n return partErrors(lane, pkg, sourcesOf(dir, dir), (file) => lineCount(readFileSync(resolve(dir, file), \"utf8\")));\n });\n if (errors.length > 0) throw new Error(`the parts do not cover each file exactly one time:\\n ${errors.join(\"\\n \")}`);\n}\n\n/** This function examines the parts of the package of each selection that is a part. */\nconst checkPartsOf = (lane: Lane, laneDir: string, names: readonly string[]): void =>\n checkParts(lane, laneDir, [...new Set(names.map((n) => select(lane, n)).filter((s) => s.name !== s.pkg).map((s) => s.pkg))]);\n\nfunction disables(lane: Lane, laneDir: string, write: boolean, io: CliIo): number {\n const files = new Set<string>();\n for (const [name, p] of Object.entries(lane.packages)) {\n const dir = resolve(laneDir, p.dir);\n if (!existsSync(dir)) throw new Error(`${name}: the folder ${p.dir} does not exist`);\n for (const f of sourcesOf(laneDir, dir)) files.add(f);\n }\n const found = findDisables([...files].map((file) => ({ file, text: readFileSync(resolve(laneDir, file), \"utf8\") })));\n const listFile = resolve(laneDir, lane.disables ?? \"mutation-disables.json\");\n const listed = existsSync(listFile) ? (readJson(listFile) as Disable[]) : [];\n const check = compareDisables(found, listed);\n for (const d of check.noReason) io.stderr(`a disable without a reason after a colon: ${d.file}: ${d.comment}\\n`);\n if (write) {\n if (check.noReason.length > 0) return 1;\n writeFileSync(listFile, `${JSON.stringify(found, null, 2)}\\n`);\n io.stdout(`disables: wrote ${String(found.length)} comments to ${relative(io.cwd, listFile).replaceAll(\"\\\\\", \"/\")}\\n`);\n return 0;\n }\n const perFile = new Map<string, number>();\n for (const d of found) perFile.set(d.file, (perFile.get(d.file) ?? 0) + 1);\n io.stdout(`disables: ${String(found.length)} in ${String(perFile.size)} files\\n`);\n for (const [file, n] of perFile) io.stdout(` ${file}: ${String(n)}\\n`);\n for (const k of check.added) io.stderr(`not in the list: ${k}\\n`);\n for (const k of check.removed) io.stderr(`in the list, not in the sources: ${k}\\n`);\n if (check.added.length > 0 || check.removed.length > 0) {\n io.stderr(\"disables: the sources and the list are not the same. Add each new disable with its reason, or start with --write and examine the diff.\\n\");\n }\n return check.ok ? 0 : 1;\n}\n\n/** The options of `scores`. */\ninterface ScoresOptions {\n readonly report: string | undefined;\n readonly summary: string | undefined;\n readonly last: string | undefined;\n readonly writeLast: string | undefined;\n readonly testFiles: boolean;\n}\n\n/**\n * This function gives the score of each selection (`scores`). With `last`, it compares the test count with the last\n * good count (LANE.TESTS of Vex). With `testFiles`, it compares the test files that the run starts with the report (LANE.FILES).\n */\nfunction scores(lane: Lane, laneDir: string, names: readonly string[], o: ScoresOptions, io: CliIo): number {\n if (names.length === 0) throw new Error(`\"scores\" takes one or more selections`);\n if (o.report !== undefined && names.length > 1) throw new Error(`--report takes one selection`);\n checkPartsOf(lane, laneDir, names);\n const lastFile = o.last === undefined ? undefined : resolve(io.cwd, o.last);\n const last = lastFile === undefined || !existsSync(lastFile) ? {} : readCounts(lastFile);\n if (lastFile !== undefined && !existsSync(lastFile)) io.stdout(`scores: the file ${o.last ?? \"\"} does not exist, so no count is compared\n`);\n const notes = new Map<string, string[]>(names.map((n) => [n, []]));\n const note = (name: string, line: string): void => void notes.get(name)?.push(line);\n const falls: PlannedFall[] = [];\n const results: Score[] = names.map((name) => {\n const s = select(lane, name);\n const file = o.report === undefined ? resolve(laneDir, s.dir, REPORT_DIR, \"mutation.json\") : resolve(io.cwd, o.report);\n if (!existsSync(file)) {\n const reason = `the report ${relative(io.cwd, file)} does not exist`;\n return { name, gate: s.gate, detected: 0, hitLimit: 0, clockTimeouts: 0, valid: 0, survived: [], percent: 0, percentWithClock: 0, tests: undefined, pass: false, reason, outcome: \"no read\" };\n }\n const report = parseReport(readJson(file));\n let score = scoreReport(report, s);\n const before = last[name];\n if (lastFile !== undefined && before !== undefined) {\n if (score.tests === undefined) score = failScore(score, `the report has no \"testFiles\", so the count of the tests is not known`);\n else {\n const fall = testFall(score.tests, before, lane.maxTestFall ?? MAX_TEST_FALL);\n const planned = lane.plannedFalls?.[name];\n if (fall !== undefined && planned === undefined) score = failScore(score, fall);\n else if (fall !== undefined) {\n const text = `${fall.replace(/, so the score is no read$/, \"\")}. The reason: ${planned ?? \"\"}`;\n note(name, ` a planned fall: ${text}`);\n falls.push({ name, text });\n }\n }\n }\n if (o.testFiles) score = checkTestFiles(lane, laneDir, s, report, score, (line) => note(name, line));\n return score;\n });\n for (const s of results) {\n io.stdout(`${formatScore(s)}\n`);\n for (const line of notes.get(s.name) ?? []) io.stdout(`${line}\n`);\n if (!s.pass) for (const m of s.survived) io.stdout(` survived: ${m}\n`);\n }\n if (o.summary !== undefined) appendFileSync(resolve(io.cwd, o.summary), `### Mutation scores\n\n${summaryMarkdown(results)}\n`);\n if (o.writeLast !== undefined) {\n const out = resolve(io.cwd, o.writeLast);\n const counts = { ...(existsSync(out) ? readCounts(out) : {}) };\n for (const s of results) if (s.pass && s.tests !== undefined) counts[s.name] = s.tests;\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, `${JSON.stringify(Object.fromEntries(Object.entries(counts).toSorted(([a], [b]) => (a < b ? -1 : 1))), null, 2)}\n`);\n }\n if (io.env?.[\"GITHUB_ACTIONS\"] === \"true\") for (const line of annotations(results, falls)) io.stdout(`${line}\n`);\n const failed = results.filter((s) => !s.pass).map((s) => s.name);\n if (failed.length > 0) io.stderr(`The gate failed for ${failed.join(\", \")}.\n`);\n return failed.length > 0 ? 1 : 0;\n}\n\n/** A fall of the test count that the lane plans, with its text. The score passes, and its annotation tells the fall. */\ninterface PlannedFall {\n readonly name: string;\n readonly text: string;\n}\n\n/** This function escapes the text of a workflow command of GitHub Actions. A property escapes also `:` and `,`. */\nconst escapeCommand = (text: string, property = false): string => {\n const data = text.replaceAll(\"%\", \"%25\").replaceAll(\"\\r\", \"%0D\").replaceAll(\"\\n\", \"%0A\");\n return property ? data.replaceAll(\":\", \"%3A\").replaceAll(\",\", \"%2C\") : data;\n};\n\n/**\n * This function gives a warning annotation for each score that does not pass and each planned fall. The annotation is on\n * the check line, so a no read is not a green check with the reason only in the log. This is true also for a run that\n * only reports. The title of a no read gives the count of the no reads and of the selections.\n */\nfunction annotations(results: readonly Score[], falls: readonly PlannedFall[]): string[] {\n const noReads = results.filter((s) => !s.pass && s.outcome !== \"block\");\n const line = (title: string, message: string): string => `::warning title=${escapeCommand(title, true)}::${escapeCommand(message)}`;\n return [\n ...noReads.map((s) => line(`Mutation gate: no read, ${String(noReads.length)} of ${String(results.length)} selections`, `${s.name}: ${s.reason ?? \"\"}`)),\n ...results.filter((s) => !s.pass && s.outcome === \"block\").map((s) => line(\"Mutation gate: under the gate\", `${s.name}: ${s.reason ?? \"\"}`)),\n ...falls.map((f) => line(\"Mutation gate: a planned fall of the tests\", `${f.name}: ${f.text}`)),\n ];\n}\n\n/** This function reads a file of test counts: an object from each selection to its count. */\nfunction readCounts(file: string): Record<string, number> {\n const json = readJson(file);\n const ok = typeof json === \"object\" && json !== null && !Array.isArray(json) && Object.values(json).every((n) => Number.isInteger(n) && (n as number) >= 0);\n if (!ok) throw new Error(`the file ${file} is not an object of test counts`);\n return json as Record<string, number>;\n}\n\n/** This function tells if the Vitest runner of a selection starts all the tests: the lane sets `vitest.related` to false. */\nfunction runsAllTests(s: Selection): boolean {\n const vitest = s.stryker?.[\"vitest\"];\n return typeof vitest === \"object\" && vitest !== null && (vitest as Record<string, unknown>)[\"related\"] === false;\n}\n\n/**\n * This function fails a score when the report does not read a test file that the run starts. The related mode of the\n * Vitest runner starts each test file that loads a file of the selection (LANE.FILES). So a part does not start the\n * test files of the other parts. With `vitest.related` false, the run starts each test file on the disk.\n */\nfunction checkTestFiles(lane: Lane, laneDir: string, s: Selection, report: MutationReport, score: Score, note: (line: string) => void): Score {\n const p = lane.packages[s.pkg];\n if (p === undefined) return score;\n const dir = resolve(laneDir, p.dir);\n if (report.testFiles === undefined) return failScore(score, `the report has no \"testFiles\", so the test files that it read are not known`);\n const files = sourcesOf(dir, dir, true).filter((f) => !f.endsWith(\".d.ts\"));\n const onDisk = files.filter((f) => TEST.test(f));\n const started = runsAllTests(s)\n ? onDisk\n : relatedTestFiles(\n files.map((file) => ({ file, text: readFileSync(resolve(dir, file), \"utf8\") })),\n (file) => globsSelect(s.mutate, file),\n );\n const unread = unreadTestFiles(report, started, p.notRead, dir);\n for (const f of unread) note(` not read: ${p.dir}/${f}`);\n if (unread.length === 0) return score;\n return failScore(score, `the report does not read ${String(unread.length)} test files that the run starts. Each one is no read, unless \"notRead\" of the package gives its reason`);\n}\n\n/** This function starts the CLI with its arguments and gives the exit code. */\nexport function runCli(argv: readonly string[], io: CliIo): number {\n const { values, positionals } = parseArgs({\n args: [...argv],\n allowPositionals: true,\n options: {\n lane: { type: \"string\", default: \"mutation.json\" },\n out: { type: \"string\" },\n concurrency: { type: \"string\" },\n report: { type: \"string\" },\n summary: { type: \"string\" },\n write: { type: \"boolean\", default: false },\n runs: { type: \"boolean\", default: false },\n \"dry-run\": { type: \"boolean\", default: false },\n changed: { type: \"string\" },\n last: { type: \"string\" },\n \"write-last\": { type: \"string\" },\n \"test-files\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n },\n });\n const [command, ...names] = positionals;\n if (values.help || command === undefined) {\n io.stdout(HELP);\n return command === undefined && !values.help ? 1 : 0;\n }\n const laneFile = resolve(io.cwd, values.lane);\n const laneDir = dirname(laneFile);\n const lane = parseLane(readJson(laneFile));\n const changed =\n values.changed === undefined\n ? undefined\n : readFileSync(resolve(io.cwd, values.changed), \"utf8\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line !== \"\");\n const one = (): string => {\n if (names.length !== 1 || names[0] === undefined) throw new Error(`\"${command}\" takes one selection`);\n return names[0];\n };\n switch (command) {\n case \"list\": {\n if (values.runs) checkParts(lane, laneDir, Object.keys(lane.packages));\n if (changed !== undefined && !values.runs) throw new Error(`--changed of \"list\" takes --runs`);\n const runs = values.runs ? runSelections(lane) : selectionNames(lane);\n const shown = changed === undefined ? runs : runs.filter((n) => changedFiles(select(lane, n), changed).length > 0);\n io.stdout(shown.length === 0 ? \"\" : `${shown.join(\"\\n\")}\\n`);\n return 0;\n }\n case \"dir\":\n io.stdout(`${relative(io.cwd, resolve(laneDir, select(lane, one()).dir)).replaceAll(\"\\\\\", \"/\") || \".\"}\\n`);\n return 0;\n case \"config\": {\n const concurrency = values.concurrency === undefined ? undefined : Number(values.concurrency);\n if (concurrency !== undefined && !(Number.isInteger(concurrency) && concurrency > 0)) throw new Error(`--concurrency is not a positive integer`);\n checkPartsOf(lane, laneDir, [one()]);\n const all = select(lane, one());\n const files = changed === undefined ? undefined : changedFiles(all, changed);\n if (files?.length === 0) throw new Error(`the selection ${all.name} has no changed file`);\n const selection = files === undefined ? all : { ...all, mutate: files };\n const tsconfigRewrite = rewritesTsconfig(typescriptMajor(resolve(laneDir, all.dir)));\n const options = { ...(concurrency === undefined ? {} : { concurrency }), dryRun: values[\"dry-run\"], tsconfigRewrite };\n const text = `${JSON.stringify(strykerConfig(selection, options), null, 2)}\\n`;\n if (values.out === undefined) io.stdout(text);\n else {\n mkdirSync(dirname(resolve(io.cwd, values.out)), { recursive: true });\n writeFileSync(resolve(io.cwd, values.out), text);\n }\n return 0;\n }\n case \"scores\":\n return scores(lane, laneDir, names, { report: values.report, summary: values.summary, last: values.last, writeLast: values[\"write-last\"], testFiles: values[\"test-files\"] }, io);\n case \"disables\":\n return disables(lane, laneDir, values.write, io);\n case \"load-check\":\n return loadCheck(lane, laneDir, names, io);\n default:\n io.stderr(`unknown command \"${command}\"\\n\\n${HELP}`);\n return 1;\n }\n}\n"],"mappings":";;;;;;AA8CA,MAAa,gBAAmC;CAAC;CAAU;CAAc;CAAgB;CAAgB;CAAa;AAAsB;AAgC5I,MAAM,OAAO;AAEb,MAAM,YAAY,MAA6C,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;;AAGtH,MAAM,aAAa,MAA4C,SAAS,CAAC,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,MAAM,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,EAAE;AAEpJ,MAAM,WAAW,MAA8B,MAAM,QAAQ,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,OAAO,MAAM,OAAO,MAAM,YAAY,MAAM,EAAE;;AAGnI,SAAS,cAAc,MAAc,GAAsB;CACzD,IAAI,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,qBAAqB,KAAK,4DAA4D;CACpH,IAAI,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,GAAG,KAAK,+BAA+B;CACjE,MAAM,SAAmB,CAAC;CAC1B,IAAI,OAAO,EAAE,WAAW,YAAY,EAAE,WAAW,IAAI,OAAO,KAAK,GAAG,KAAK,6BAA6B;CACtG,IAAI,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,KAAK,GAAG,KAAK,kCAAkC;MAC5E,IAAI,EAAE,SAAS,CAAC,OAAO,MAAM,EAAE,WAAW,GAAG,CAAC,GAAG,OAAO,KAAK,GAAG,KAAK,8BAA8B;CACxG,MAAM,OAAO,EAAE;CACf,IAAI,SAAS,KAAA,MAAc,OAAO,SAAS,YAAY,EAAE,QAAQ,KAAK,QAAQ,OAAO,OAAO,KAAK,GAAG,KAAK,wCAAwC;CACjJ,IAAI,EAAE,oBAAoB,KAAA,KAAa,OAAO,EAAE,oBAAoB,UAAU,OAAO,KAAK,GAAG,KAAK,oCAAoC;CACtI,KAAK,MAAM,SAAS,CAAC,aAAa,sBAAsB,GAAG;EACzD,MAAM,IAAI,EAAE;EACZ,IAAI,MAAM,KAAA,KAAa,EAAE,OAAO,MAAM,YAAY,OAAO,UAAU,CAAC,KAAK,IAAI,IAAI,OAAO,KAAK,GAAG,KAAK,KAAK,MAAM,4BAA4B;CAC9I;CACA,MAAM,UAAU,EAAE;CAClB,IAAI,YAAY,KAAA,GAAW;EACzB,IAAI,CAAC,SAAS,OAAO,GAAG,OAAO,KAAK,GAAG,KAAK,6BAA6B;OACpE;GACH,MAAM,QAAQ,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ,MAAM,cAAc,SAAS,CAAC,CAAC;GAC1E,IAAI,MAAM,SAAS,GAAG,OAAO,KAAK,GAAG,KAAK,kBAAkB,MAAM,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,+BAA+B;EACnI;CACF;CACA,IAAI,EAAE,eAAe,KAAA,KAAa,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,KAAK,GAAG,KAAK,0DAA0D;CAC1I,MAAM,QAAQ,EAAE;CAChB,IAAI,UAAU,KAAA,GAAW;EACvB,IAAI,CAAC,SAAS,KAAK,KAAK,OAAO,KAAK,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO,KAAK,GAAG,KAAK,sCAAsC;OAEjH,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,GAAG;GACjD,IAAI,CAAC,KAAK,KAAK,IAAI,GAAG,OAAO,KAAK,GAAG,KAAK,mBAAmB,KAAK,4DAA4D;GAC9H,IAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,MAAM,MAAM,EAAE,WAAW,GAAG,CAAC,GAAG,OAAO,KAAK,GAAG,KAAK,GAAG,KAAK,8CAA8C;EACzI;CAEJ;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,UAAU,MAAqB;CAC7C,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,WAAW,GAAG,MAAM,IAAI,MAAM,mCAAmC;CACvG,MAAM,SAAS,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,SAAS,CAAC,MAAM,OAAO,cAAc,MAAM,CAAC,CAAC;CAC7F,IAAI,OAAO,KAAK,KAAK,WAAW,CAAC,CAAC,WAAW,GAAG,OAAO,KAAK,0BAA0B;CACtF,IAAI,KAAK,gBAAgB,KAAA,KAAa,OAAO,KAAK,gBAAgB,UAAU,OAAO,KAAK,+BAA+B;CACvH,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,KAAA,MAAc,OAAO,SAAS,YAAY,EAAE,QAAQ,KAAK,QAAQ,OAAO,OAAO,KAAK,8CAA8C;CAC/I,MAAM,UAAU,KAAK;CACrB,IAAI,YAAY,KAAA,KAAa,CAAC,UAAU,OAAO,GAAG,OAAO,KAAK,mEAAmE;CACjI,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,MAAM,6BAA6B,OAAO,KAAK,MAAM,GAAG;CACzF,MAAM,OAAO;CACb,MAAM,QAAQ,IAAI,IAAI,eAAe,IAAI,CAAC;CAC1C,MAAM,UAAU,OAAO,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;CAChF,IAAI,QAAQ,SAAS,GAAG,MAAM,IAAI,MAAM,4EAA4E,QAAQ,KAAK,IAAI,GAAG;CACxI,OAAO;AACT;;AAGA,SAAgB,eAAe,MAAsB;CACnD,OAAO,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,SAAS,CAAC,MAAM,OAAO,CAAC,MAAM,GAAG,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC;AACpI;;AAGA,SAAgB,cAAc,MAAsB;CAClD,OAAO,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,SAAS,CAAC,MAAM,OAAQ,EAAE,UAAU,KAAA,IAAY,CAAC,IAAI,IAAI,OAAO,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,SAAS,GAAG,KAAK,GAAG,MAAM,CAAE;AACtJ;;;;;;AAOA,SAAgB,OAAO,MAAY,MAAyB;CAC1D,MAAM,CAAC,MAAM,IAAI,MAAM,GAAG,QAAQ,KAAK,MAAM,GAAG;CAChD,MAAM,IAAI,KAAK,SAAS;CACxB,MAAM,QAAQ,SAAS,KAAA,IAAY,KAAA,IAAY,GAAG,QAAQ;CAC1D,IAAI,MAAM,KAAA,KAAa,KAAK,SAAS,KAAM,SAAS,KAAA,KAAa,UAAU,KAAA,GACzE,MAAM,IAAI,MAAM,oCAAoC,KAAK,aAAa,eAAe,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG;CAGzG,MAAM,SAAS,UAAU,KAAA,IAAY,EAAE,SAAS,CAAC,GAAG,OAAO,GAAG,EAAE,OAAO,QAAQ,MAAM,EAAE,WAAW,GAAG,CAAC,CAAC;CACvG,OAAO;EAAE;EAAM;EAAK,KAAK,EAAE;EAAK;EAAQ,MAAM,EAAE;EAAM,cAAc,EAAE;EAAc,WAAW,EAAE;EAAW,sBAAsB,EAAE;EAAsB,SAAS,EAAE;CAAQ;AAC/K;;AAGA,MAAM,QAAQ;AAWd,SAAS,QAAQ,OAAsC;CACrD,MAAM,IAAI,MAAM,KAAK,KAAK;CAC1B,IAAI,IAAI,OAAO,KAAA,GAAW,OAAO,KAAA;CACjC,OAAO;EAAE;EAAO,MAAM,EAAE;EAAI,MAAM,OAAO,EAAE,EAAE;EAAG,IAAI,OAAO,EAAE,EAAE;EAAG,SAAS,EAAE,OAAO,KAAA,KAAa,EAAE,OAAO,KAAA;CAAU;AACtH;;AAGA,MAAM,UAAU,UAA0B,QAAQ,KAAK,CAAC,EAAE,QAAQ;;;;;AAMlE,SAAgB,YAAY,OAA0B,MAAuB;CAC3E,IAAI,WAAW;CACf,KAAK,MAAM,KAAK,OACd,IAAI,EAAE,WAAW,GAAG,GACd;MAAA,YAAY,YAAY,MAAM,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,WAAW;CAAA,OAC7D,IAAI,CAAC,YAAY,YAAY,MAAM,OAAO,CAAC,CAAC,GAAG,WAAW;CAEnE,OAAO;AACT;;;;;AAMA,SAAS,QAAQ,OAA0B,MAAmC;CAC5E,MAAM,OAAO,MAAM,QAAQ,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,YAAY,MAAM,OAAO,CAAC,CAAC,CAAC;CACnF,IAAI,KAAK,MAAM,MAAM,QAAQ,CAAC,MAAM,KAAA,CAAS,GAAG,OAAO;CACvD,OAAO,KAAK,SAAS,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7C;;;;;;;AAQA,SAAgB,aAAa,WAAsB,SAAsC;CACvF,MAAM,MAAM,MAAM,UAAU,UAAU,IAAI,WAAW,MAAM,GAAG,CAAC;CAC/D,OAAO,QACJ,KAAK,MAAM,MAAM,SAAS,KAAK,MAAM,UAAU,EAAE,WAAW,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACzE,QAAQ,MAAM,MAAM,MAAM,CAAC,EAAE,WAAW,KAAK,KAAK,CAAC,MAAM,WAAW,CAAC,KAAK,YAAY,UAAU,QAAQ,CAAC,CAAC,CAAC,CAC3G,SAAS,MAAM;EACd,MAAM,QAAQ,QAAQ,UAAU,QAAQ,CAAC;EACzC,OAAO,UAAU,QAAQ,CAAC,CAAC,IAAI,MAAM,KAAK,MAAM,GAAG,IAAI,EAAE,MAAM,MAAM,EAAE,KAAK,MAAM,GAAG;CACvF,CAAC;AACL;;AAGA,SAAS,YAAY,KAAa,MAAc,QAAuD,OAAqC;CAC1I,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,EAAE,MAAM,WAAW,QAC5B,IAAI,MAAM,SAAS,OAAO,KAAK,GAAG,IAAI,cAAc,MAAM,MAAM,eAAe,KAAK,kDAAkD;MACjI,IAAI,MAAM,OAAO,KAAK,MAAM,OAAO,MAAM,IAAI,OAAO,KAAK,GAAG,IAAI,cAAc,MAAM,MAAM,eAAe,KAAK,cAAc;CAEnI,IAAI,OAAO,SAAS,GAAG,OAAO;CAC9B,IAAI,OAAO;CACX,IAAI,OAAO;CACX,KAAK,MAAM,EAAE,MAAM,WAAW,OAAO,UAAU,GAAG,MAAM,EAAE,MAAM,OAAO,EAAE,MAAM,QAAQ,EAAE,MAAM,KAAK,EAAE,MAAM,EAAE,GAAG;EAC/G,IAAI,MAAM,OAAO,MAAM,OAAO,KAAK,GAAG,IAAI,cAAc,OAAO,IAAI,EAAE,GAAG,OAAO,MAAM,OAAO,CAAC,EAAE,MAAM,KAAK,gBAAgB;OACrH,IAAI,MAAM,OAAO,MAAM,OAAO,KAAK,GAAG,IAAI,cAAc,OAAO,MAAM,IAAI,EAAE,GAAG,OAAO,KAAK,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,KAAK,oBAAoB,KAAK,OAAO,MAAM;EACzK,IAAI,MAAM,MAAM,MAAM;GACpB,OAAO,MAAM,KAAK;GAClB,OAAO;EACT;CACF;CACA,IAAI,UAAU,KAAA,KAAa,QAAQ,OAAO,OAAO,KAAK,GAAG,IAAI,cAAc,OAAO,IAAI,EAAE,GAAG,OAAO,KAAK,EAAE,MAAM,KAAK,gBAAgB;CACpI,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,WAAW,MAAY,KAAa,OAA0B,OAA4C;CACxH,MAAM,IAAI,KAAK,SAAS;CACxB,IAAI,GAAG,UAAU,KAAA,GAAW,OAAO,CAAC;CACpC,MAAM,QAAQ,OAAO,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,UAAU;EAAE;EAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC;CAAO,EAAE;CAC1G,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,YAAY,EAAE,QAAQ,IAAI;EAC3C,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;EAClF,MAAM,SAAS,MAAM,QAAQ,MAAM,QAAQ,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO;GAAE,MAAM,EAAE;GAAM,OAAO,QAAQ,EAAE,QAAQ,IAAI;EAAE,EAAE;EAC1H,MAAM,SAAS,OAAO,OAAO,MAAM,EAAE,UAAU,KAAK;EACpD,IAAI,YAAY,QAAQ,WAAW,GAAG,OAAO,KAAK,GAAG,IAAI,aAAa,KAAK,iDAAiD;OACvH,IAAI,QAAQ,SAAS,KAAK,CAAC,QAAQ,OAAO,KAAK,GAAG,IAAI,aAAa,KAAK,6BAA6B,QAAQ,KAAK,IAAI,GAAG;OACzH,IAAI,CAAC,YAAY,QAAQ,SAAS,GAAG,OAAO,KAAK,GAAG,IAAI,aAAa,KAAK,kBAAkB,QAAQ,KAAK,IAAI,EAAE,sBAAsB;OACrI,IAAI,QAAQ,SAAS,KAAK,QAAQ;GACrC,MAAM,SAAS,OAAO,SAAS,MAAO,EAAE,UAAU,QAAQ,CAAC,IAAI,EAAE,MAAM,KAAK,WAAW;IAAE,MAAM,EAAE;IAAM;GAAM,EAAE,CAAE;GACjH,OAAO,KAAK,GAAG,YAAY,KAAK,MAAM,QAAQ,QAAQ,IAAI,CAAC,CAAC;EAC9D;CACF;CACA,OAAO;AACT;;;ACtPA,MAAa,aAAa;;;;;AAM1B,MAAa,aAAa;;;;;AAM1B,MAAa,cAAc;;;;;;AAO3B,SAAgB,iBAAiB,OAAoC;CACnE,OAAO,UAAU,KAAA,KAAa,QAAQ;AACxC;;AAGA,MAAa,0BAA0B;;;;;;AAOvC,SAAgB,cAAc,WAAsB,UAAyB,CAAC,GAAkB;CAC9F,MAAM,YAAY,QAAQ,aAAA;CAC1B,MAAM,MAAM,UAAU,QAAQ;CAC9B,OAAO;EACL,YAAY;EACZ,SAAS,CAAC,gCAAgC;EAC1C,GAAI,UAAU,iBAAiB,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,UAAU,aAAa,EAAE;EACjG,QAAQ,UAAU;EAClB,kBAAkB;EAClB,WAAW;GAAC;GAAc;GAAY;GAAQ;EAAM;EACpD,cAAc,EAAE,UAAU,GAAG,UAAU,aAAa;EACpD,cAAc,EAAE,UAAU,GAAG,UAAU,gBAAgB;EACvD,YAAY;GAAE,MAAM,KAAK,IAAI,KAAK,EAAE;GAAG;GAAK,OAAO;EAAK;EACxD,aAAa,QAAQ,eAAe;EACpC,WAAW,UAAU,aAAA;EACrB,sBAAsB,UAAU,wBAAA;EAChC,GAAI,QAAQ,oBAAoB,QAAQ,EAAE,cAAc,YAAY,IAAI,CAAC;EAEzE,GAAG,UAAU;EACb,GAAI,QAAQ,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;EAChF,GAAI,QAAQ,WAAW,OAAO;GAAE,YAAY;GAAM,aAAa;EAAK,IAAI,CAAC;CAC3E;AACF;;ACpCA,MAAM,6BAAa,IAAI,IAAI,CAAC,YAAY,YAAY,CAAC;;AAGrD,MAAa,cAAc,MAAuB,EAAE,WAAW,cAAc,EAAE,gBAAgB,GAAA,CAAI,WAAW,WAAW;;;;;;AAOzH,SAAgB,YAAY,MAA+B;CACzD,MAAM,QAAQ,OAAO,SAAS,YAAY,SAAS,OAAQ,KAA6B,QAAQ,KAAA;CAChG,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,MAAM,IAAI,MAAM,kCAAkC;CACnG,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,KAAK,GAC7C,IAAI,CAAC,MAAM,QAAS,MAAuC,OAAO,GAAG,MAAM,IAAI,MAAM,wCAAwC,MAAM;CAErI,MAAM,YAAa,KAAiC;CACpD,IAAI,cAAc,KAAA,GAAW;EAC3B,IAAI,OAAO,cAAc,YAAY,cAAc,MAAM,MAAM,IAAI,MAAM,sDAAsD;EAC/H,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,SAAS,GACjD,IAAI,CAAC,MAAM,QAAS,MAAqC,KAAK,GAAG,MAAM,IAAI,MAAM,oDAAoD,MAAM;CAE/I;CACA,OAAO;AACT;;AAGA,SAAgB,UAAU,QAA4C;CACpE,IAAI,OAAO,cAAc,KAAA,GAAW,OAAO,KAAA;CAC3C,OAAO,OAAO,OAAO,OAAO,SAAS,CAAC,CAAC,QAAQ,KAAK,MAAM,MAAM,EAAE,MAAM,QAAQ,CAAC;AACnF;;;;;;;AAQA,SAAgB,SAAS,OAAe,MAAc,SAAqC;CACzF,IAAI,QAAQ,KAAK,SAAS,MAAM,OAAO,KAAA;CACvC,MAAM,OAAQ,OAAO,OAAO,SAAU;CACtC,IAAI,QAAQ,SAAS,OAAO,KAAA;CAC5B,OAAO,gBAAgB,OAAO,KAAK,EAAE,UAAU,KAAK,QAAQ,CAAC,EAAE,oCAAoC,OAAO,IAAI,EAAE,iBAAiB,OAAO,OAAO,EAAE;AACnJ;;;;;;;;AASA,SAAgB,gBAAgB,QAAwB,QAA2B,UAA4C,CAAC,GAAG,MAAM,IAAc;CACrJ,MAAM,OAAO,IAAI,WAAW,MAAM,GAAG,CAAC,CAAC,QAAQ,QAAQ,GAAG;CAC1D,MAAM,OAAO,IAAI,IACf,OAAO,KAAK,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM;EAC7C,MAAM,OAAO,EAAE,WAAW,MAAM,GAAG;EACnC,OAAO,QAAQ,MAAM,KAAK,WAAW,IAAI,IAAI,KAAK,MAAM,KAAK,MAAM,IAAI,KAAK,QAAQ,SAAS,EAAE;CACjG,CAAC,CACH;CACA,OAAO,OAAO,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC,KAAK,QAAQ,OAAO,KAAA,CAAS;AACtE;;;;;AAMA,SAAgB,UAAU,OAAc,QAAuB;CAC7D,OAAO;EAAE,GAAG;EAAO,MAAM;EAAO,SAAS;EAAW,QAAQ,MAAM,WAAW,KAAA,IAAY,SAAS,GAAG,MAAM,OAAO,SAAS;CAAS;AACtI;;;;;;AAOA,SAAgB,YAAY,QAAwB,WAAgF;CAClI,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,WAAW;CACf,IAAI,gBAAgB;CACpB,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,OAAO,KAAK,GACpD,KAAK,MAAM,KAAK,KAAK,SAAS;EAC5B,MAAM,KAAK,GAAG,KAAK,GAAG,OAAO,EAAE,SAAS,MAAM,IAAI,EAAE,GAAG,EAAE;EACzD,IAAI,EAAE,WAAW,YAAY,WAAW,CAAC,GAAG;GAC1C;GACA;GACA,IAAI,EAAE,WAAW,WAAW;EAC9B,OAAO,IAAI,EAAE,WAAW,WAAW;GACjC;GACA;GACA,SAAS,KAAK,GAAG,GAAG,wBAAwB;EAC9C,OAAO,IAAI,WAAW,IAAI,EAAE,MAAM,GAAG;GACnC;GACA,SAAS,KAAK,EAAE;EAClB;CACF;CAEF,MAAM,UAAU,UAAU,IAAI,IAAK,MAAM,WAAY;CACrD,MAAM,mBAAmB,UAAU,IAAI,IAAK,OAAO,WAAW,iBAAkB;CAChF,MAAM,EAAE,MAAM,SAAS;CACvB,MAAM,CAAC,SAAS,UACd,UAAU,IACN,CAAC,WAAW,6FAA6F,IACzG,aAAa,IACX,CAAC,WAAW,kCAAkC,OAAO,KAAK,EAAE,yDAAyD,IACrH,SAAS,KAAA,KAAa,UAAU,OAC9B,CAAC,SAAS,aAAa,QAAQ,QAAQ,CAAC,EAAE,uBAAuB,OAAO,IAAI,EAAE,GAAG,IACjF,CAAC,QAAQ,KAAA,CAAS;CAC5B,OAAO;EAAE;EAAM;EAAM;EAAU;EAAU;EAAe;EAAO;EAAU;EAAS;EAAkB,OAAO,UAAU,MAAM;EAAG,MAAM,WAAW,KAAA;EAAW;EAAQ;CAAQ;AAC5K;;AAGA,MAAM,YAAY,MAChB,cAAc,OAAO,EAAE,QAAQ,EAAE,cAAc,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,iBAAiB,QAAQ,CAAC,EAAE;;AAGjH,SAAgB,YAAY,GAAkB;CAC5C,MAAM,OAAO,EAAE,SAAS,KAAA,IAAY,YAAY,QAAQ,OAAO,EAAE,IAAI,EAAE;CACvE,MAAM,SAAS,EAAE,OAAO,SAAS,SAAS,EAAE,UAAU;CACtD,MAAM,OAAO,EAAE,WAAW,EAAE,kBAAkB,IAAI,KAAK,KAAK,SAAS,CAAC;CACtE,MAAM,QAAQ,EAAE,UAAU,KAAA,IAAY,KAAK,KAAK,OAAO,EAAE,KAAK,EAAE;CAChE,OAAO,GAAG,EAAE,KAAK,IAAI,EAAE,QAAQ,QAAQ,CAAC,EAAE,MAAM,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,SAAS,MAAM,EAAE,WAAW,OAAO,MAAM,KAAK,KAAK,IAAI;AAC/J;;AAGA,SAAgB,gBAAgB,QAAkC;CAKhE,OAAO;EACL;EACA;EACA,GAPW,OAAO,KACjB,MACC,KAAK,EAAE,KAAK,KAAK,EAAE,QAAQ,QAAQ,CAAC,EAAE,OAAO,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,QAAQ,CAAC,EAAE,OAAO,EAAE,SAAS,KAAA,IAAY,SAAS,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,SAAS,SAAS,EAAE,UAAU,KAAK,KAAK,EAAE,UAAU,KAAA,IAAY,MAAM,OAAO,EAAE,KAAK,EAAE,GAKjV;EACN;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;AC5KA,SAAgB,aAAa,OAA+E;CAC1G,OAAO,MAAM,SAAS,EAAE,MAAM,WAC5B,KACG,MAAM,IAAI,CAAC,CACX,QAAQ,SAAS,KAAK,SAAS,iBAAiB,CAAC,CAAC,CAClD,KAAK,UAAU;EAAE;EAAM,SAAS,KAAK,KAAK;CAAE,EAAE,CACnD;AACF;AAEA,MAAM,UAAU,OAAgD;CAC9D,MAAM,oBAAI,IAAI,IAAoB;CAClC,KAAK,MAAM,KAAK,IAAI;EAClB,MAAM,IAAI,GAAG,EAAE,KAAK,IAAI,EAAE;EAC1B,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,KAAK,KAAK,CAAC;CAC9B;CACA,OAAO;AACT;;;;;AAMA,SAAS,UAAU,SAA0B;CAC3C,MAAM,QAAQ,QAAQ,QAAQ,kBAAkB;CAChD,IAAI,QAAQ,GAAG,OAAO;CACtB,MAAM,OAAO,QAAQ,MAAM,QAAQ,EAAyB;CAC5D,MAAM,QAAQ,KAAK,QAAQ,GAAG;CAC9B,OAAO,QAAQ,KAAK,KAAK,QAAQ,OAAO,OAAO,KAAK,KAAK,KAAK,QAAQ,MAAM,EAAE;AAChF;;AAGA,SAAgB,gBAAgB,OAA2B,QAA0C;CACnG,MAAM,WAAW,MAAM,QAAQ,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC;CAC1D,MAAM,IAAI,OAAO,KAAK;CACtB,MAAM,IAAI,OAAO,MAAM;CACvB,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;CAC3E,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;CAC7E,OAAO;EAAE;EAAO;EAAS;EAAU,IAAI,MAAM,WAAW,KAAK,QAAQ,WAAW,KAAK,SAAS,WAAW;CAAE;AAC7G;;;;;;;;AClCA,MAAM,SAAS;AAEf,MAAM,cAAc;AAEpB,MAAM,YAAY;AAClB,MAAM,UAAU;AAChB,MAAM,cAAc;;;;;;;AAQpB,SAAgB,aAAa,MAAc,cAAgC;CACzE,OAAO,YAAY,KAAK,IAAI,KAAM,iBAAiB,KAAA,KAAa,MAAM,UAAU,aAAa,WAAW,MAAM,GAAG,CAAC,MAAM;AAC1H;AAEA,SAAS,OAAO,MAAc,MAAuB;CACnD,IAAI,EAAE,SAAS,OAAO,SAAS,QAAQ,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK,MAAM,KAAK,SAAS,IAAI,GAAG,OAAO;CACvH,MAAM,SAAS,MAAM,UAAU,MAAM,KAAK,MAAM,QAAQ,IAAI,GAAG,IAAI,CAAC;CACpE,OAAO,WAAW,QAAQ,OAAO,WAAW,KAAK;AACnD;AAEA,MAAMA,SAAO;AACb,MAAM,aAAa;CAAC;CAAI;CAAO;CAAQ;CAAQ;CAAQ;CAAO;CAAQ;CAAQ;CAAa;AAAW;;AAGtG,SAAS,QAAQ,MAAc,MAAc,cAAoE;CAC/G,MAAM,UAAU,aAAa,MAAM,YAAY,IAAI,cAAc;CACjE,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,SAAS,UAAU,MAAM;EAC/C,IAAI,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,QAAQ,GAAG,OAAO,CAAC;EAChE,OAAO,CAAC,GAAG,SAAS,SAAS,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO;GAAE,MAAM,IAAI;GAAG,MAAM,EAAE,MAAM;EAAG,EAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,KAAK,WAAW,GAAG,CAAC;CAC7H,CAAC;AACH;;AAGA,SAAS,OAAO,MAAc,MAAc,OAAgD;CAC1F,MAAM,OAAO,MAAM,UAAU,MAAM,KAAK,MAAM,QAAQ,IAAI,GAAG,IAAI,CAAC;CAClE,MAAM,OAAO,KAAK,QAAQ,sBAAsB,EAAE;CAClD,OAAO,CAAC,GAAG,WAAW,KAAK,MAAM,OAAO,CAAC,GAAG,GAAG,WAAW,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,MAAM,IAAI,CAAC,CAAC;AACnH;;;;;;;;;;AAWA,SAAgB,aAAa,OAA+B,cAAsC;CAChG,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;CACxD,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,CAAC;CAClC,MAAM,QAAQ,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAMA,OAAK,KAAK,CAAC,KAAK,aAAa,GAAG,YAAY,CAAC;CAClG,MAAM,SAAS,IAAI,IAAI,KAAK;CAC5B,MAAM,QAAuB,CAAC;CAC9B,KAAK,IAAI,OAAO,MAAM,MAAM,GAAG,SAAS,KAAA,GAAW,OAAO,MAAM,MAAM,GACpE,KAAK,MAAM,EAAE,MAAM,UAAU,QAAQ,MAAM,MAAM,IAAI,IAAI,KAAK,IAAI,YAAY,GAC5E,IAAI,OAAO,MAAM,IAAI,GAAG,MAAM,KAAK;EAAE,MAAM;EAAM;EAAM;CAAK,CAAC;MACxD;EACH,MAAM,IAAI,OAAO,MAAM,MAAM,KAAK;EAClC,IAAI,MAAM,KAAA,KAAa,CAAC,OAAO,IAAI,CAAC,GAAG;GACrC,OAAO,IAAI,CAAC;GACZ,MAAM,KAAK,CAAC;EACd;CACF;CAGJ,OAAO,MAAM,UAAU,GAAG,MAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,CAAE;AAClG;AAGA,MAAM,iBAAiB;;AAGvB,SAAS,sBAAsB,MAAsB;CACnD,OAAO,KAAK,QAAQ,iBAAiB,cAAc,UAAU,QAAQ,UAAU,EAAE,CAAC;AACpF;;;;;;;;;AAUA,SAAgB,iBAAiB,OAA+B,UAA+C;CAC7G,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,sBAAsB,EAAE,IAAI,CAAC,CAAC,CAAC;CAC/E,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,CAAC;CAClC,MAAM,SAAS,SACb,QAAQ,MAAM,MAAM,IAAI,IAAI,KAAK,IAAI,KAAA,CAAS,CAAC,CAAC,SAAS,EAAE,WAAW;EACpE,MAAM,IAAI,OAAO,MAAM,MAAM,KAAK;EAClC,OAAO,MAAM,KAAA,IAAY,CAAC,IAAI,CAAC,CAAC;CAClC,CAAC;CACH,MAAM,WAAW,SAA0B;EACzC,MAAM,QAAQ,CAAC,IAAI;EACnB,MAAM,SAAS,IAAI,IAAI,KAAK;EAC5B,KAAK,IAAI,OAAO,MAAM,MAAM,GAAG,SAAS,KAAA,GAAW,OAAO,MAAM,MAAM,GACpE,KAAK,MAAM,KAAK,MAAM,IAAI,GAAG;GAC3B,IAAI,CAACA,OAAK,KAAK,CAAC,KAAK,SAAS,CAAC,GAAG,OAAO;GACzC,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG;IAClB,OAAO,IAAI,CAAC;IACZ,MAAM,KAAK,CAAC;GACd;EACF;EAEF,OAAO;CACT;CACA,OAAO,MAAM,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAMA,OAAK,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC;AAC1E;;;;;;ACrHA,MAAa,OAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCA+BW,WAAW;;AAGlD,MAAM,SAAS;AACf,MAAM,OAAO;AACb,MAAM,uBAAO,IAAI,IAAI;CAAC;CAAgB;CAAS;CAAQ;CAAW;AAAU,CAAC;;;;;AAM7E,SAAS,UAAU,MAAc,KAAa,QAAQ,OAAiB;CACrE,OAAO,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,CAAC,CAC7C,UAAU,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC,CAAC,CAChD,SAAS,MAAM;EACd,MAAM,OAAO,QAAQ,KAAK,EAAE,IAAI;EAChC,IAAI,EAAE,YAAY,GAAG,OAAO,EAAE,KAAK,WAAW,GAAG,KAAK,KAAK,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,UAAU,MAAM,MAAM,KAAK;EACzG,OAAO,EAAE,OAAO,KAAK,OAAO,KAAK,EAAE,IAAI,MAAM,SAAS,CAAC,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC,WAAW,MAAM,GAAG,CAAC,IAAI,CAAC;CAC9H,CAAC;AACL;;AAGA,SAAS,UAAU,MAAY,SAAiB,OAA0B,IAAmB;CAC3F,MAAM,OAAO,CAAC,GAAG,IAAI,IAAK,MAAM,WAAW,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,CAAE,CAAC;CACnH,IAAI,SAAS;CACb,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,IAAI,OAAO,MAAM,GAAG;EAC1B,MAAM,MAAM,QAAQ,SAAS,EAAE,GAAG;EAClC,IAAI,CAAC,WAAW,GAAG,GAAG,MAAM,IAAI,MAAM,GAAG,IAAI,eAAe,EAAE,IAAI,gBAAgB;EAClF,MAAM,QAAQ,UAAU,KAAK,KAAK,IAAI,CAAC,CACpC,QAAQ,MAAM,CAAC,EAAE,SAAS,OAAO,CAAC,CAAC,CACnC,KAAK,UAAU;GAAE;GAAM,MAAM,aAAa,QAAQ,KAAK,IAAI,GAAG,MAAM;EAAE,EAAE;EAC3E,MAAM,QAAQ,aAAa,OAAO,EAAE,YAAY;EAChD,KAAK,MAAM,KAAK,OACd,GAAG,OAAO,GAAG,EAAE,IAAI,GAAG,EAAE,KAAK,GAAG,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,sBAAsB,EAAE,IAAI;CAC5F;EAEG,IAAI,MAAM,WAAW,GAAG,GAAG,OAAO,cAAc,IAAI,IAAI,OAAO,MAAM,MAAM,EAAE,kCAAkC,EAAE,IAAI;CACxH;OACQ,UAAU;CACjB;CACA,IAAI,SAAS,GAAG,GAAG,OAAO,eAAe,OAAO,MAAM,EAAE;CACzD;CACC,OAAO,SAAS,IAAI,IAAI;AAC1B;AAEA,MAAM,YAAY,SAA0B,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;;;;;AAMjF,SAAS,gBAAgB,KAAiC;CACxD,IAAI;CACJ,IAAI;EACF,OAAO,cAAc,KAAK,KAAK,cAAc,CAAC,CAAC,CAAC,QAAQ,yBAAyB;CACnF,QAAQ;EACN;CACF;CACA,MAAM,UAAoB,SAAS,IAAI,CAAC,CAA2B;CACnE,MAAM,QAAQ,OAAO,YAAY,WAAW,OAAO,SAAS,SAAS,EAAE,IAAI;CAC3E,OAAO,OAAO,UAAU,KAAK,IAAI,QAAQ,KAAA;AAC3C;;;;;;;AAQA,MAAM,aAAa,SAA0B,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,IAAI,IAAI;AAEpH,SAAS,WAAW,MAAY,SAAiB,MAA+B;CAC9E,MAAM,SAAS,KAAK,SAAS,QAAQ;EACnC,MAAM,IAAI,KAAK,SAAS;EACxB,IAAI,GAAG,UAAU,KAAA,GAAW,OAAO,CAAC;EACpC,MAAM,MAAM,QAAQ,SAAS,EAAE,GAAG;EAClC,IAAI,CAAC,WAAW,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,eAAe,EAAE,IAAI,gBAAgB;EAC1E,OAAO,WAAW,MAAM,KAAK,UAAU,KAAK,GAAG,IAAI,SAAS,UAAU,aAAa,QAAQ,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC;CACjH,CAAC;CACD,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,MAAM,yDAAyD,OAAO,KAAK,MAAM,GAAG;AACvH;;AAGA,MAAM,gBAAgB,MAAY,SAAiB,UACjD,WAAW,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,MAAM,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAE7H,SAAS,SAAS,MAAY,SAAiB,OAAgB,IAAmB;CAChF,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,CAAC,MAAM,MAAM,OAAO,QAAQ,KAAK,QAAQ,GAAG;EACrD,MAAM,MAAM,QAAQ,SAAS,EAAE,GAAG;EAClC,IAAI,CAAC,WAAW,GAAG,GAAG,MAAM,IAAI,MAAM,GAAG,KAAK,eAAe,EAAE,IAAI,gBAAgB;EACnF,KAAK,MAAM,KAAK,UAAU,SAAS,GAAG,GAAG,MAAM,IAAI,CAAC;CACtD;CACA,MAAM,QAAQ,aAAa,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,UAAU;EAAE;EAAM,MAAM,aAAa,QAAQ,SAAS,IAAI,GAAG,MAAM;CAAE,EAAE,CAAC;CACnH,MAAM,WAAW,QAAQ,SAAS,KAAK,YAAY,wBAAwB;CAE3E,MAAM,QAAQ,gBAAgB,OADf,WAAW,QAAQ,IAAK,SAAS,QAAQ,IAAkB,CAAC,CAChC;CAC3C,KAAK,MAAM,KAAK,MAAM,UAAU,GAAG,OAAO,6CAA6C,EAAE,KAAK,IAAI,EAAE,QAAQ,GAAG;CAC/G,IAAI,OAAO;EACT,IAAI,MAAM,SAAS,SAAS,GAAG,OAAO;EACtC,cAAc,UAAU,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,GAAG;EAC7D,GAAG,OAAO,mBAAmB,OAAO,MAAM,MAAM,EAAE,eAAe,SAAS,GAAG,KAAK,QAAQ,CAAC,CAAC,WAAW,MAAM,GAAG,EAAE,GAAG;EACrH,OAAO;CACT;CACA,MAAM,0BAAU,IAAI,IAAoB;CACxC,KAAK,MAAM,KAAK,OAAO,QAAQ,IAAI,EAAE,OAAO,QAAQ,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC;CACzE,GAAG,OAAO,aAAa,OAAO,MAAM,MAAM,EAAE,MAAM,OAAO,QAAQ,IAAI,EAAE,SAAS;CAChF,KAAK,MAAM,CAAC,MAAM,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,IAAI,OAAO,CAAC,EAAE,GAAG;CACtE,KAAK,MAAM,KAAK,MAAM,OAAO,GAAG,OAAO,oBAAoB,EAAE,GAAG;CAChE,KAAK,MAAM,KAAK,MAAM,SAAS,GAAG,OAAO,oCAAoC,EAAE,GAAG;CAClF,IAAI,MAAM,MAAM,SAAS,KAAK,MAAM,QAAQ,SAAS,GACnD,GAAG,OAAO,0IAA0I;CAEtJ,OAAO,MAAM,KAAK,IAAI;AACxB;;;;;AAeA,SAAS,OAAO,MAAY,SAAiB,OAA0B,GAAkB,IAAmB;CAC1G,IAAI,MAAM,WAAW,GAAG,MAAM,IAAI,MAAM,uCAAuC;CAC/E,IAAI,EAAE,WAAW,KAAA,KAAa,MAAM,SAAS,GAAG,MAAM,IAAI,MAAM,8BAA8B;CAC9F,aAAa,MAAM,SAAS,KAAK;CACjC,MAAM,WAAW,EAAE,SAAS,KAAA,IAAY,KAAA,IAAY,QAAQ,GAAG,KAAK,EAAE,IAAI;CAC1E,MAAM,OAAO,aAAa,KAAA,KAAa,CAAC,WAAW,QAAQ,IAAI,CAAC,IAAI,WAAW,QAAQ;CACvF,IAAI,aAAa,KAAA,KAAa,CAAC,WAAW,QAAQ,GAAG,GAAG,OAAO,oBAAoB,EAAE,QAAQ,GAAG;CACjG;CACC,MAAM,QAAQ,IAAI,IAAsB,MAAM,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACjE,MAAM,QAAQ,MAAc,SAAuB,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI;CAClF,MAAM,QAAuB,CAAC;CAC9B,MAAM,UAAmB,MAAM,KAAK,SAAS;EAC3C,MAAM,IAAI,OAAO,MAAM,IAAI;EAC3B,MAAM,OAAO,EAAE,WAAW,KAAA,IAAY,QAAQ,SAAS,EAAE,KAAK,YAAY,eAAe,IAAI,QAAQ,GAAG,KAAK,EAAE,MAAM;EACrH,IAAI,CAAC,WAAW,IAAI,GAAG;GACrB,MAAM,SAAS,cAAc,SAAS,GAAG,KAAK,IAAI,EAAE;GACpD,OAAO;IAAE;IAAM,MAAM,EAAE;IAAM,UAAU;IAAG,UAAU;IAAG,eAAe;IAAG,OAAO;IAAG,UAAU,CAAC;IAAG,SAAS;IAAG,kBAAkB;IAAG,OAAO,KAAA;IAAW,MAAM;IAAO;IAAQ,SAAS;GAAU;EAC9L;EACA,MAAM,SAAS,YAAY,SAAS,IAAI,CAAC;EACzC,IAAI,QAAQ,YAAY,QAAQ,CAAC;EACjC,MAAM,SAAS,KAAK;EACpB,IAAI,aAAa,KAAA,KAAa,WAAW,KAAA,GAAW;GAClD,IAAI,MAAM,UAAU,KAAA,GAAW,QAAQ,UAAU,OAAO,uEAAuE;QAC1H;IACH,MAAM,OAAO,SAAS,MAAM,OAAO,QAAQ,KAAK,eAAA,EAA4B;IAC5E,MAAM,UAAU,KAAK,eAAe;IACpC,IAAI,SAAS,KAAA,KAAa,YAAY,KAAA,GAAW,QAAQ,UAAU,OAAO,IAAI;SACzE,IAAI,SAAS,KAAA,GAAW;KAC3B,MAAM,OAAO,GAAG,KAAK,QAAQ,8BAA8B,EAAE,EAAE,gBAAgB,WAAW;KAC1F,KAAK,MAAM,qBAAqB,MAAM;KACtC,MAAM,KAAK;MAAE;MAAM;KAAK,CAAC;IAC3B;GACF;EACF;EACA,IAAI,EAAE,WAAW,QAAQ,eAAe,MAAM,SAAS,GAAG,QAAQ,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;EACnG,OAAO;CACT,CAAC;CACD,KAAK,MAAM,KAAK,SAAS;EACvB,GAAG,OAAO,GAAG,YAAY,CAAC,EAAE;CAC/B;EACG,KAAK,MAAM,QAAQ,MAAM,IAAI,EAAE,IAAI,KAAK,CAAC,GAAG,GAAG,OAAO,GAAG,KAAK;CACjE;EACG,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,KAAK,EAAE,UAAU,GAAG,OAAO,eAAe,EAAE;CACvE;CACC;CACA,IAAI,EAAE,YAAY,KAAA,GAAW,eAAe,QAAQ,GAAG,KAAK,EAAE,OAAO,GAAG;;EAExE,gBAAgB,OAAO,EAAE;CAC1B;CACC,IAAI,EAAE,cAAc,KAAA,GAAW;EAC7B,MAAM,MAAM,QAAQ,GAAG,KAAK,EAAE,SAAS;EACvC,MAAM,SAAS,EAAE,GAAI,WAAW,GAAG,IAAI,WAAW,GAAG,IAAI,CAAC,EAAG;EAC7D,KAAK,MAAM,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,UAAU,KAAA,GAAW,OAAO,EAAE,QAAQ,EAAE;EACjF,UAAU,QAAQ,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;EAC3C,cAAc,KAAK,GAAG,KAAK,UAAU,OAAO,YAAY,OAAO,QAAQ,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAQ,IAAI,IAAI,KAAK,CAAE,CAAC,GAAG,MAAM,CAAC,EAAE;CACtI;CACC;CACA,IAAI,GAAG,MAAM,sBAAsB,QAAQ,KAAK,MAAM,QAAQ,YAAY,SAAS,KAAK,GAAG,GAAG,OAAO,GAAG,KAAK;CAC9G;CACC,MAAM,SAAS,QAAQ,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;CAC/D,IAAI,OAAO,SAAS,GAAG,GAAG,OAAO,uBAAuB,OAAO,KAAK,IAAI,EAAE;CAC3E;CACC,OAAO,OAAO,SAAS,IAAI,IAAI;AACjC;;AASA,MAAM,iBAAiB,MAAc,WAAW,UAAkB;CAChE,MAAM,OAAO,KAAK,WAAW,KAAK,KAAK,CAAC,CAAC,WAAW,MAAM,KAAK,CAAC,CAAC,WAAW,MAAM,KAAK;CACvF,OAAO,WAAW,KAAK,WAAW,KAAK,KAAK,CAAC,CAAC,WAAW,KAAK,KAAK,IAAI;AACzE;;;;;;AAOA,SAAS,YAAY,SAA2B,OAAyC;CACvF,MAAM,UAAU,QAAQ,QAAQ,MAAM,CAAC,EAAE,QAAQ,EAAE,YAAY,OAAO;CACtE,MAAM,QAAQ,OAAe,YAA4B,mBAAmB,cAAc,OAAO,IAAI,EAAE,IAAI,cAAc,OAAO;CAChI,OAAO;EACL,GAAG,QAAQ,KAAK,MAAM,KAAK,2BAA2B,OAAO,QAAQ,MAAM,EAAE,MAAM,OAAO,QAAQ,MAAM,EAAE,cAAc,GAAG,EAAE,KAAK,IAAI,EAAE,UAAU,IAAI,CAAC;EACvJ,GAAG,QAAQ,QAAQ,MAAM,CAAC,EAAE,QAAQ,EAAE,YAAY,OAAO,CAAC,CAAC,KAAK,MAAM,KAAK,iCAAiC,GAAG,EAAE,KAAK,IAAI,EAAE,UAAU,IAAI,CAAC;EAC3I,GAAG,MAAM,KAAK,MAAM,KAAK,8CAA8C,GAAG,EAAE,KAAK,IAAI,EAAE,MAAM,CAAC;CAChG;AACF;;AAGA,SAAS,WAAW,MAAsC;CACxD,MAAM,OAAO,SAAS,IAAI;CAE1B,IAAI,EADO,OAAO,SAAS,YAAY,SAAS,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAAK,OAAO,OAAO,IAAI,CAAC,CAAC,OAAO,MAAM,OAAO,UAAU,CAAC,KAAM,KAAgB,CAAC,IACjJ,MAAM,IAAI,MAAM,YAAY,KAAK,iCAAiC;CAC3E,OAAO;AACT;;AAGA,SAAS,aAAa,GAAuB;CAC3C,MAAM,SAAS,EAAE,UAAU;CAC3B,OAAO,OAAO,WAAW,YAAY,WAAW,QAAS,OAAmC,eAAe;AAC7G;;;;;;AAOA,SAAS,eAAe,MAAY,SAAiB,GAAc,QAAwB,OAAc,MAAqC;CAC5I,MAAM,IAAI,KAAK,SAAS,EAAE;CAC1B,IAAI,MAAM,KAAA,GAAW,OAAO;CAC5B,MAAM,MAAM,QAAQ,SAAS,EAAE,GAAG;CAClC,IAAI,OAAO,cAAc,KAAA,GAAW,OAAO,UAAU,OAAO,6EAA6E;CACzI,MAAM,QAAQ,UAAU,KAAK,KAAK,IAAI,CAAC,CAAC,QAAQ,MAAM,CAAC,EAAE,SAAS,OAAO,CAAC;CAC1E,MAAM,SAAS,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC,CAAC;CAO/C,MAAM,SAAS,gBAAgB,QANf,aAAa,CAAC,IAC1B,SACA,iBACE,MAAM,KAAK,UAAU;EAAE;EAAM,MAAM,aAAa,QAAQ,KAAK,IAAI,GAAG,MAAM;CAAE,EAAE,IAC7E,SAAS,YAAY,EAAE,QAAQ,IAAI,CACtC,GAC4C,EAAE,SAAS,GAAG;CAC9D,KAAK,MAAM,KAAK,QAAQ,KAAK,eAAe,EAAE,IAAI,GAAG,GAAG;CACxD,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,OAAO,UAAU,OAAO,4BAA4B,OAAO,OAAO,MAAM,EAAE,uGAAuG;AACnL;;AAGA,SAAgB,OAAO,MAAyB,IAAmB;CACjE,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACxC,MAAM,CAAC,GAAG,IAAI;EACd,kBAAkB;EAClB,SAAS;GACP,MAAM;IAAE,MAAM;IAAU,SAAS;GAAgB;GACjD,KAAK,EAAE,MAAM,SAAS;GACtB,aAAa,EAAE,MAAM,SAAS;GAC9B,QAAQ,EAAE,MAAM,SAAS;GACzB,SAAS,EAAE,MAAM,SAAS;GAC1B,OAAO;IAAE,MAAM;IAAW,SAAS;GAAM;GACzC,MAAM;IAAE,MAAM;IAAW,SAAS;GAAM;GACxC,WAAW;IAAE,MAAM;IAAW,SAAS;GAAM;GAC7C,SAAS,EAAE,MAAM,SAAS;GAC1B,MAAM,EAAE,MAAM,SAAS;GACvB,cAAc,EAAE,MAAM,SAAS;GAC/B,cAAc;IAAE,MAAM;IAAW,SAAS;GAAM;GAChD,MAAM;IAAE,MAAM;IAAW,SAAS;GAAM;EAC1C;CACF,CAAC;CACD,MAAM,CAAC,SAAS,GAAG,SAAS;CAC5B,IAAI,OAAO,QAAQ,YAAY,KAAA,GAAW;EACxC,GAAG,OAAO,IAAI;EACd,OAAO,YAAY,KAAA,KAAa,CAAC,OAAO,OAAO,IAAI;CACrD;CACA,MAAM,WAAW,QAAQ,GAAG,KAAK,OAAO,IAAI;CAC5C,MAAM,UAAU,QAAQ,QAAQ;CAChC,MAAM,OAAO,UAAU,SAAS,QAAQ,CAAC;CACzC,MAAM,UACJ,OAAO,YAAY,KAAA,IACf,KAAA,IACA,aAAa,QAAQ,GAAG,KAAK,OAAO,OAAO,GAAG,MAAM,CAAC,CAClD,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,QAAQ,SAAS,SAAS,EAAE;CACrC,MAAM,YAAoB;EACxB,IAAI,MAAM,WAAW,KAAK,MAAM,OAAO,KAAA,GAAW,MAAM,IAAI,MAAM,IAAI,QAAQ,sBAAsB;EACpG,OAAO,MAAM;CACf;CACA,QAAQ,SAAR;EACE,KAAK,QAAQ;GACX,IAAI,OAAO,MAAM,WAAW,MAAM,SAAS,OAAO,KAAK,KAAK,QAAQ,CAAC;GACrE,IAAI,YAAY,KAAA,KAAa,CAAC,OAAO,MAAM,MAAM,IAAI,MAAM,kCAAkC;GAC7F,MAAM,OAAO,OAAO,OAAO,cAAc,IAAI,IAAI,eAAe,IAAI;GACpE,MAAM,QAAQ,YAAY,KAAA,IAAY,OAAO,KAAK,QAAQ,MAAM,aAAa,OAAO,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,SAAS,CAAC;GACjH,GAAG,OAAO,MAAM,WAAW,IAAI,KAAK,GAAG,MAAM,KAAK,IAAI,EAAE,GAAG;GAC3D,OAAO;EACT;EACA,KAAK;GACH,GAAG,OAAO,GAAG,SAAS,GAAG,KAAK,QAAQ,SAAS,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,MAAM,GAAG,KAAK,IAAI,GAAG;GACzG,OAAO;EACT,KAAK,UAAU;GACb,MAAM,cAAc,OAAO,gBAAgB,KAAA,IAAY,KAAA,IAAY,OAAO,OAAO,WAAW;GAC5F,IAAI,gBAAgB,KAAA,KAAa,EAAE,OAAO,UAAU,WAAW,KAAK,cAAc,IAAI,MAAM,IAAI,MAAM,yCAAyC;GAC/I,aAAa,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;GACnC,MAAM,MAAM,OAAO,MAAM,IAAI,CAAC;GAC9B,MAAM,QAAQ,YAAY,KAAA,IAAY,KAAA,IAAY,aAAa,KAAK,OAAO;GAC3E,IAAI,OAAO,WAAW,GAAG,MAAM,IAAI,MAAM,iBAAiB,IAAI,KAAK,qBAAqB;GACxF,MAAM,YAAY,UAAU,KAAA,IAAY,MAAM;IAAE,GAAG;IAAK,QAAQ;GAAM;GACtE,MAAM,kBAAkB,iBAAiB,gBAAgB,QAAQ,SAAS,IAAI,GAAG,CAAC,CAAC;GACnF,MAAM,UAAU;IAAE,GAAI,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY;IAAI,QAAQ,OAAO;IAAY;GAAgB;GACpH,MAAM,OAAO,GAAG,KAAK,UAAU,cAAc,WAAW,OAAO,GAAG,MAAM,CAAC,EAAE;GAC3E,IAAI,OAAO,QAAQ,KAAA,GAAW,GAAG,OAAO,IAAI;QACvC;IACH,UAAU,QAAQ,QAAQ,GAAG,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;IACnE,cAAc,QAAQ,GAAG,KAAK,OAAO,GAAG,GAAG,IAAI;GACjD;GACA,OAAO;EACT;EACA,KAAK,UACH,OAAO,OAAO,MAAM,SAAS,OAAO;GAAE,QAAQ,OAAO;GAAQ,SAAS,OAAO;GAAS,MAAM,OAAO;GAAM,WAAW,OAAO;GAAe,WAAW,OAAO;EAAc,GAAG,EAAE;EACjL,KAAK,YACH,OAAO,SAAS,MAAM,SAAS,OAAO,OAAO,EAAE;EACjD,KAAK,cACH,OAAO,UAAU,MAAM,SAAS,OAAO,EAAE;EAC3C;GACE,GAAG,OAAO,oBAAoB,QAAQ,OAAO,MAAM;GACnD,OAAO;CACX;AACF"}