@systemfsoftware/stryker-js-cli 4.0.0 → 4.0.2

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/main.mjs +43 -20
  3. package/package.json +16 -15
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @systemfsoftware/stryker-js-cli
2
2
 
3
+ ## 4.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Re-published against the oxc-based instrumenter: workspace dependency ranges move to the new instrumenter major; no package's own behavior changes in this release.
8
+
9
+ ## 4.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - A mutation run that is killed mid-way keeps every completed mutant: the JSONL progress stream is flushed after each result, and incremental mode writes remembered verdicts as they finish so the next run continues instead of starting over.
14
+
15
+ Remembered killed mutants still name the tests that killed them, so a resumed run's report matches a complete run.
16
+
17
+ The progress stream path is progressStreamFile (default reports/mutation-stream.jsonl) and can be set in config or with --progressStreamFile.
18
+
19
+ - Peer Effect requirement advances to 4.0.0-rc.112. No API changes.
20
+
3
21
  ## 4.0.0
4
22
 
5
23
  ### Major Changes
package/dist/main.mjs CHANGED
@@ -1053,6 +1053,35 @@ function emitMachineModeOutput(stream, mode, outcome, basePath, pathService) {
1053
1053
  });
1054
1054
  }
1055
1055
  //#endregion
1056
+ //#region src/StreamFile.ts
1057
+ const DEFAULT_PROGRESS_STREAM_FILE = "reports/mutation-stream.jsonl";
1058
+ const encodeUtf8 = (line) => new TextEncoder().encode(line);
1059
+ const drainStreamFile = (fileName, framed) => Effect.gen(function* () {
1060
+ const fs = yield* FileSystem.FileSystem;
1061
+ const path = yield* Path.Path;
1062
+ yield* fs.makeDirectory(path.dirname(fileName), { recursive: true }).pipe(Effect.orDie);
1063
+ yield* Effect.scoped(Effect.gen(function* () {
1064
+ const handle = yield* fs.open(fileName, { flag: "w" });
1065
+ yield* Stream.runForEach(framed, (line) => handle.writeAll(encodeUtf8(line)).pipe(Effect.flatMap(() => handle.sync)));
1066
+ })).pipe(Effect.orDie);
1067
+ });
1068
+ const RunEventStreamFileLive = Layer.effect(RunEventStreamPort, Effect.gen(function* () {
1069
+ const stdio = yield* Stdio.Stdio;
1070
+ const fs = yield* FileSystem.FileSystem;
1071
+ const path = yield* Path.Path;
1072
+ const fileNameRef = yield* Ref.make(DEFAULT_PROGRESS_STREAM_FILE);
1073
+ const drainFramed = (framed) => Effect.gen(function* () {
1074
+ const fileName = yield* Ref.get(fileNameRef);
1075
+ yield* drainStreamFile(fileName, framed).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
1076
+ });
1077
+ return RunEventStreamPort.of({ createRunEventStream: (resolved) => Effect.gen(function* () {
1078
+ return {
1079
+ ...yield* makeRunEventStream(stdio, resolved, drainFramed),
1080
+ setProgressStreamFile: (fileName) => Ref.set(fileNameRef, fileName)
1081
+ };
1082
+ }) });
1083
+ }));
1084
+ //#endregion
1056
1085
  //#region src/Survivors.ts
1057
1086
  /**
1058
1087
  * Survivors — the survivors-admission capability.
@@ -1562,6 +1591,7 @@ const runOptions = {
1562
1591
  incremental: Flag.map(optional(Flag.boolean("incremental")), absentWhenFalse).pipe(Flag.withDescription("Enable 'incremental mode'. Stryker will store results in a file and use that file to speed up the next --incremental run")),
1563
1592
  allowEmpty: Flag.map(optional(Flag.boolean("allowEmpty")), absentWhenFalse).pipe(Flag.withDescription("Allows stryker to exit without any errors in cases where no tests are found")),
1564
1593
  incrementalFile: Flag.string("incrementalFile").pipe(Flag.withDescription("Specify the file to use for incremental mode."), optional),
1594
+ progressStreamFile: Flag.string("progressStreamFile").pipe(Flag.withDescription("Specify the file for the machine-mode progress stream."), optional),
1565
1595
  force: Flag.map(optional(Flag.boolean("force")), absentWhenFalse).pipe(Flag.withDescription("Run all mutants, even if --incremental is provided and an incremental file exists. Can be used to force a rebuild of the incremental file.")),
1566
1596
  mutate: Flag.string("mutate").pipe(Flag.withAlias("m"), Flag.withDescription("With `mutate` you configure the subset of files or just one specific file to be mutated. These should be your _production code files_, and definitely not your test files. (Whereas with `ignorePatterns` you prevent non-relevant files from being copied to the sandbox directory in the first place)\nThe default will try to guess your production code files based on sane defaults. It reads like this:\n- Include all js-like files inside the `src` or `lib` dir\n- Except files inside `__tests__` directories and file names ending with `test` or `spec`.\nIf the defaults are not sufficient for you, for example in a angular project you might want to **exclude** not only the `*.spec.ts` files but other files too, just like the default already does.\nIt is possible to override the defaults by: - supplying one or more [glob patterns](https://github.com/isaacs/minimatch) to include (e.g. `src/**/*.js`) - or one or more comma separated glob patterns preceded with `!` to exclude (e.g. `!src/**/*.spec.js`) - or both (e.g. `src/**/*.js,!src/**/*.spec.js`).\nNote: Stryker will use [minimatch](https://github.com/isaacs/minimatch) for parsing these patterns, see minimatch for the exact syntax."), Flag.map(splitOnComma), optional),
1567
1597
  testFiles: Flag.string("testFiles").pipe(Flag.withAlias("t"), Flag.withDescription("With `testFiles` you can limit which test files are executed during mutation testing. When specified, only tests from these files will be run. This allows you to verify that a module's dedicated unit tests can kill all its mutants independently."), Flag.map(splitOnComma), optional),
@@ -1657,6 +1687,7 @@ function makeStrykerCommand(requestRef) {
1657
1687
  setIfPresent(options, "incremental", config.incremental);
1658
1688
  setIfPresent(options, "allowEmpty", config.allowEmpty);
1659
1689
  setIfPresent(options, "incrementalFile", config.incrementalFile);
1690
+ setIfPresent(options, "progressStreamFile", config.progressStreamFile);
1660
1691
  setIfPresent(options, "force", config.force);
1661
1692
  setIfPresent(options, "mutate", config.mutate);
1662
1693
  setIfPresent(options, "testFiles", config.testFiles);
@@ -1802,9 +1833,19 @@ const runStrykerCli = (input, createRunEventStream) => Effect.gen(function* () {
1802
1833
  process.on("SIGINT", onSignal);
1803
1834
  process.on("SIGTERM", onSignal);
1804
1835
  }), () => Effect.gen(function* () {
1805
- yield* stream.open;
1806
- yield* input.program;
1836
+ const parsed = yield* Effect.result(input.program);
1807
1837
  const request = yield* Ref.get(input.requestRef);
1838
+ const fileName = Option.match(request, {
1839
+ onNone: () => DEFAULT_PROGRESS_STREAM_FILE,
1840
+ onSome: (cliRequest) => Match.value(cliRequest).pipe(Match.tag("run", (runRequest) => {
1841
+ const fromCli = runRequest.options["progressStreamFile"];
1842
+ if (typeof fromCli === "string" && fromCli.length > 0) return fromCli;
1843
+ return DEFAULT_PROGRESS_STREAM_FILE;
1844
+ }), Match.orElse(() => DEFAULT_PROGRESS_STREAM_FILE))
1845
+ });
1846
+ if (stream.setProgressStreamFile !== void 0) yield* stream.setProgressStreamFile(fileName);
1847
+ yield* stream.open;
1848
+ if (Result.isFailure(parsed)) return yield* Effect.fail(parsed.failure);
1808
1849
  return yield* Option.match(request, {
1809
1850
  onNone: () => Effect.void,
1810
1851
  onSome: (cliRequest) => dispatch(cliRequest)
@@ -1822,24 +1863,6 @@ const runStrykerCli = (input, createRunEventStream) => Effect.gen(function* () {
1822
1863
  }));
1823
1864
  });
1824
1865
  //#endregion
1825
- //#region src/StreamFile.ts
1826
- const STREAM_FILE_DIR = "reports";
1827
- const STREAM_FILE_NAME = "mutation-stream.jsonl";
1828
- const encodeUtf8 = (line) => new TextEncoder().encode(line);
1829
- const drainStreamFile = (framed) => Effect.gen(function* () {
1830
- const fs = yield* FileSystem.FileSystem;
1831
- const file = (yield* Path.Path).join(STREAM_FILE_DIR, STREAM_FILE_NAME);
1832
- yield* fs.makeDirectory(STREAM_FILE_DIR, { recursive: true }).pipe(Effect.orDie);
1833
- yield* Stream.run(framed.pipe(Stream.map(encodeUtf8)), fs.sink(file, { flag: "w" })).pipe(Effect.orDie);
1834
- });
1835
- const RunEventStreamFileLive = Layer.effect(RunEventStreamPort, Effect.gen(function* () {
1836
- const stdio = yield* Stdio.Stdio;
1837
- const fs = yield* FileSystem.FileSystem;
1838
- const path = yield* Path.Path;
1839
- const drainFramed = (framed) => drainStreamFile(framed).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
1840
- return RunEventStreamPort.of({ createRunEventStream: (resolved) => makeRunEventStream(stdio, resolved, drainFramed) });
1841
- }));
1842
- //#endregion
1843
1866
  //#region src/main.ts
1844
1867
  const EXIT_CODE_RUN_NEVER_REACHED_ITS_FINALIZER = 1;
1845
1868
  process.title = "stryker";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@systemfsoftware/stryker-js-cli",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/systemfsoftware/systemfsoftware.git",
@@ -18,10 +18,10 @@
18
18
  "@effect/platform-node-shared": "^4.0.0-rc.112",
19
19
  "@noble/hashes": "1.8.0",
20
20
  "effect": "^4.0.0-rc.112",
21
- "@systemfsoftware/effect-cell-types": "^5.0.0",
22
- "@systemfsoftware/stryker-js-html-reporter": "^0.1.0",
23
- "@systemfsoftware/stryker-js": "^0.1.0",
24
- "@systemfsoftware/stryker-js-platform-node": "^0.1.0"
21
+ "@systemfsoftware/effect-cell-types": "^5.0.2",
22
+ "@systemfsoftware/stryker-js-html-reporter": "^0.1.1",
23
+ "@systemfsoftware/stryker-js": "^0.1.1",
24
+ "@systemfsoftware/stryker-js-platform-node": "^0.1.2"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@systemfsoftware/arethetypeswrong-cli": "^1.1.1",
@@ -32,15 +32,16 @@
32
32
  "testcontainers": "^12.1.0",
33
33
  "tsdown": "^0.22.14",
34
34
  "vite-tsconfig-paths": "^6.1.1",
35
- "vitest": "^4.1.10",
36
- "@systemfsoftware/all": "^1.0.0",
37
- "@systemfsoftware/effect-gherkin-spec": "^2.0.1",
38
- "@systemfsoftware/effect-schema-law": "^1.0.0",
39
- "@systemfsoftware/effect-schema-vite": "^2.0.0",
35
+ "vitest": "^4",
36
+ "@systemfsoftware/all": "^1.0.2",
37
+ "@systemfsoftware/effect-gherkin-spec": "^4.0.0",
38
+ "@systemfsoftware/effect-schema-law": "^2.0.1",
39
+ "@systemfsoftware/effect-schema-vite": "^2.0.2",
40
+ "@systemfsoftware/stryker-js-typescript-checker": "^3.0.2",
41
+ "@systemfsoftware/stryker-js-vitest-runner": "^2.0.2",
42
+ "@systemfsoftware/stryker-test-contribution": "^1.1.1",
43
+ "@systemfsoftware/stryker-plugins": "^2.0.0",
40
44
  "@systemfsoftware/oxlint-config": "^0.1.0",
41
- "@systemfsoftware/oxlint-plugin-effect-entrypoint": "^1.0.5",
42
- "@systemfsoftware/oxlint-plugin-test-placement": "^3.2.0",
43
- "@systemfsoftware/oxlint-plugin-cell-vocabulary": "^1.2.2",
44
45
  "@systemfsoftware/tsconfig": "^1.3.3",
45
46
  "@systemfsoftware/vitest-config": "^0.1.0"
46
47
  },
@@ -65,8 +66,8 @@
65
66
  "test": "vitest run",
66
67
  "test:contract": "vitest run --config vitest.contract.config.ts",
67
68
  "lint": "f=${OXLINT_FORMAT:-${AGENT:+agent}}; oxlint . --format=${f:-default}",
68
- "mutation": "stryker run",
69
- "mutation:full": "stryker run --force",
69
+ "mutation": "node ./dist/main.mjs run",
70
+ "mutation:full": "node ./dist/main.mjs run --force",
70
71
  "api:check": "echo 'no API report for CLI (dts: false)' && exit 0",
71
72
  "api:update": "echo 'no API report for CLI (dts: false)' && exit 0"
72
73
  }