@venizia/dev-configs 0.4.7-3 → 0.4.7-5

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
@@ -105,10 +105,10 @@ Every IGNIS package and example does.
105
105
  | `@venizia/dev-configs` | Everything below, re-exported |
106
106
  | `@venizia/dev-configs/compilers` | `BunCompiler` |
107
107
  | `@venizia/dev-configs/testing` | `RejectionHelper` (`rejectionOf`, `expectRejection`), `SpawnHelper` (`spawnSyncBounded`), `RepoTmp` (`findRoot`, `apply`) - test helpers (imports `bun:test`; tests only) |
108
- | `@venizia/dev-configs/linters` | `oxlintConfigs`, `OxlintConfigs`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, `namingConventionConfigs`, `reactNamingConventionConfigs`, `houseConfigs`, `reactHouseConfigs`, `eslintConfigs`, `ReactEslintConfigs`, the rule classes and their types |
108
+ | `@venizia/dev-configs/linters` | `oxlintConfigs`, `OxlintConfigs`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, `namingConventionConfigs`, `reactNamingConventionConfigs`, `houseConfigs`, `reactHouseConfigs`, `eslintConfigs`, the rule classes and their types |
109
109
  | `@venizia/dev-configs/linters/oxlint` | `oxlintConfigs`, `OxlintConfigs`, `IOxlintPresetOptions`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, the rule classes and their types: everything an oxlint config needs, and nothing that loads ESLint. Loads in milliseconds: `/linters` also loads ESLint and its plugins, which an oxlint config never uses |
110
110
  | `@venizia/dev-configs/tsconfig.base.json` | Target and lib ES2025, `module` Node16, strict mode (`noImplicitAny` and `useUnknownInCatchVariables` on) with `strictPropertyInitialization` off (DI-injected properties have no initializer), `noEmitOnError`, tests excluded |
111
- | `@venizia/dev-configs/tsconfig.common.json` | Extends the base and switches `module` and `moduleResolution` to `nodenext` |
111
+ | `@venizia/dev-configs/tsconfig.common.json` | Extends the base and restates `module` as `esnext` and `moduleResolution` as `bundler` |
112
112
  | `@venizia/dev-configs/tsconfig.browser.json` | Extends the base for a browser library built with a bundler: `module` ESNext, `moduleResolution` bundler, lib ES2025 + `DOM` + `DOM.Iterable`, `types: []` so no Bun types reach `dist` |
113
113
  | `@venizia/dev-configs/tsconfig.react.json` | Extends `tsconfig.browser.json` and sets `jsx: react-jsx` |
114
114
 
@@ -250,44 +250,6 @@ conventions, `curly`, `eslint-plugin-n`, plus these IGNIS rules:
250
250
  | `@typescript-eslint/no-namespace` | `error` |
251
251
  | `unicorn/switch-case-braces` | `['error', 'always']` |
252
252
 
253
- ### ReactEslintConfigs
254
-
255
- `ReactEslintConfigs.create({ plugins })` is `eslintConfigs` plus what a React frontend needs. The
256
- plugins come in as options, so a backend installs none of them:
257
-
258
- ```js
259
- // eslint.config.mjs
260
- import { ReactEslintConfigs } from '@venizia/dev-configs';
261
- import react from 'eslint-plugin-react';
262
- import reactHooks from 'eslint-plugin-react-hooks';
263
- import jsxA11y from 'eslint-plugin-jsx-a11y';
264
-
265
- export default [
266
- { ignores: ['dist/'] },
267
- ...ReactEslintConfigs.create({ plugins: { react, reactHooks, jsxA11y } }),
268
- ];
269
- ```
270
-
271
- | Adds | Setting |
272
- | :--- | :--- |
273
- | React correctness (`jsx-key`, `no-children-prop`, `no-deprecated`, ... - 14 rules) | `error`, `.jsx`/`.tsx` |
274
- | `jsx-a11y` (`alt-text`, `aria-props`, `aria-role`, `click-events-have-key-events`, `label-has-associated-control`, ... - 15 rules) | `error`, `.jsx`/`.tsx` |
275
- | `react-hooks/rules-of-hooks` / `exhaustive-deps` | `error`, every source file |
276
- | `@typescript-eslint/consistent-type-imports` | `['error', { prefer: 'type-imports', fixStyle: 'inline-type-imports', disallowTypeAnnotations: false }]` |
277
- | `naming-convention` | the base rule, plus PascalCase functions (`function App()`), `.jsx`/`.tsx` |
278
- | `no-restricted-properties` | `NoRestrictedPropertiesRule.build()` - bans `crypto.randomUUID` |
279
-
280
- Nothing in the base is relaxed: frontend code meets the backend's standard, so a floating promise, a
281
- `void`, a use before declaration or a shadowed name fails the lint as it does in a service.
282
-
283
- Rules the automatic JSX runtime or `tsc` already enforce (`react-in-jsx-scope`, `prop-types`,
284
- `jsx-no-undef`, ...) are left out.
285
-
286
- - `reactVersion` defaults to `'detect'`. Under ESLint 10, eslint-plugin-react 7 cannot detect it and
287
- aborts - pass the version: `create({ plugins, reactVersion: '19.2' })`.
288
- - In an `eslint.config.ts`, `eslint-plugin-jsx-a11y` needs `@types/eslint-plugin-jsx-a11y`.
289
- - `consistent-type-imports` uses `fixStyle: inline-type-imports`, the same as the base preset.
290
-
291
253
  ### BrowserOxlintConfigs
292
254
 
293
255
  `BrowserOxlintConfigs.create()` is `oxlintConfigs` plus `NoRestrictedPropertiesRule.build()`. That
@@ -1 +1 @@
1
- {"version":3,"file":"test-mutate.d.ts","sourceRoot":"","sources":["../../src/checks/test-mutate.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,OAAO;IACtB,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC5B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iHAAiH;IACjH,eAAe,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,kGAAkG;IAClG,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiJD,qBAAa,eAAe;IAC1B,6GAA6G;IAC7G,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,EAAE;IAyD/F,6EAA6E;IAC7E,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,aAAa,EAAE,CAAA;KAAE,GAAG,MAAM,EAAE;CAazE"}
1
+ {"version":3,"file":"test-mutate.d.ts","sourceRoot":"","sources":["../../src/checks/test-mutate.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,OAAO;IACtB,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC5B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iHAAiH;IACjH,eAAe,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,kGAAkG;IAClG,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA6ID,qBAAa,eAAe;IAC1B,6GAA6G;IAC7G,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,EAAE;IAyD/F,6EAA6E;IAC7E,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,aAAa,EAAE,CAAA;KAAE,GAAG,MAAM,EAAE;CAazE"}
@@ -8,7 +8,6 @@ const TEST_TIMEOUT_MILLISECONDS = 300_000;
8
8
  /** The one place this tool builds an `Error`: `getError` would make dev-configs depend on inversion, which depends on dev-configs. */
9
9
  // eslint-disable-next-line venizia/no-new-error -- getError would be a dev-configs -> inversion cycle
10
10
  const replayError = (message) => new Error(message);
11
- const checksum = (bytes) => new Bun.CryptoHasher('sha256').update(bytes).digest('hex');
12
11
  /** The nearest folder at or above the test file that holds a `package.json`: where `bun test` runs. */
13
12
  const packageDirectoryOf = (opts) => {
14
13
  let current = (0, node_path_1.dirname)((0, node_path_1.join)(opts.root, opts.file));
@@ -48,7 +47,7 @@ const runIsRed = (opts) => {
48
47
  }
49
48
  return result.status !== 0 || failed > 0;
50
49
  };
51
- /** Applies `mutant`, runs `action`, and puts the file back byte for byte, verified by checksum. */
50
+ /** Applies `mutant`, runs `action`, and puts the file back byte for byte, verified byte for byte. */
52
51
  const withMutant = (opts) => {
53
52
  const path = (0, node_path_1.join)(opts.root, opts.mutant.file);
54
53
  const original = (0, node_fs_1.readFileSync)(path);
@@ -63,7 +62,6 @@ const withMutant = (opts) => {
63
62
  throw replayError(`[test-mutate][${opts.id}] a backup from an interrupted run exists: ${backup} | restore ${opts.mutant.file} from it, then delete it`);
64
63
  }
65
64
  (0, node_fs_1.writeFileSync)(backup, original);
66
- const expected = checksum(original);
67
65
  let outcome;
68
66
  try {
69
67
  (0, node_fs_1.writeFileSync)(path, text.replace(opts.mutant.find, () => opts.mutant.replace));
@@ -74,7 +72,7 @@ const withMutant = (opts) => {
74
72
  }
75
73
  // Restored whatever the action did, and checked, before its result or error is passed on.
76
74
  (0, node_fs_1.writeFileSync)(path, original);
77
- if (checksum((0, node_fs_1.readFileSync)(path)) !== expected) {
75
+ if (!(0, node_fs_1.readFileSync)(path).equals(original)) {
78
76
  throw replayError(`[test-mutate][${opts.id}] ${opts.mutant.file} was not restored | the backup is ${backup}`);
79
77
  }
80
78
  (0, node_fs_1.rmSync)(backup, { force: true });
@@ -83,7 +81,7 @@ const withMutant = (opts) => {
83
81
  }
84
82
  return outcome.value;
85
83
  };
86
- /** Applies every edit of `mutant`, runs `action`, and puts each file back byte for byte, verified by checksum. */
84
+ /** Applies every edit of `mutant`, runs `action`, and puts each file back byte for byte, verified byte for byte. */
87
85
  const withMutants = (opts) => {
88
86
  const edits = Array.isArray(opts.mutant) ? opts.mutant : [opts.mutant];
89
87
  const apply = (index) => index === edits.length
@@ -1 +1 @@
1
- {"version":3,"file":"test-mutate.js","sourceRoot":"","sources":["../../src/checks/test-mutate.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\n/**\n * Replays the mutation proof of the trim-tests method. A ledger line says: \"this test (the\n * candidate) is redundant because that test (the survivor) already catches the same break\". The\n * replay applies the break (the mutant) to a file, runs the survivor and the candidate, and puts the\n * file back. The survivor must go red. The candidate must go red too, unless the line says it is\n * vacuous and a second mutant leaves it green as well.\n *\n * The mutant edits the file the test really loads: the package's own `src` for a test that imports\n * through the `@/` alias, or the `dist` of the dependency for a test that reaches another package\n * through its `exports`. A rebuild is never needed.\n */\nexport interface IMutant {\n /** Repository-relative file to edit (a `src` file, or a `dist` file of a dependency). */\n file: string;\n /** Text that must occur exactly once in the file. */\n find: string;\n replace: string;\n}\n\nexport interface ILedgerLine {\n id: string;\n /** Repository-relative test file that is deleted. */\n candidate: string;\n /** Run only the cases whose name matches (`bun test -t`). Default: the whole file. */\n candidateName?: string;\n /** Repository-relative test file that stays. */\n survivor: string;\n survivorName?: string;\n /**\n * The break. An array applies every edit together: a survivor in the package that owns the code\n * loads its `src`, a candidate in another package loads that package's `dist`, so one break is two edits.\n */\n mutant: IMutant | IMutant[];\n /** The source line the mutant stands for, `path:line`; recorded, not used by the replay. */\n srcLine?: string;\n /** `red` (default): the candidate must fail. `vacuous`: it must stay green under `mutant` AND `secondMutant`. */\n expectCandidate?: 'red' | 'vacuous';\n secondMutant?: IMutant | IMutant[];\n}\n\nexport interface ILedger {\n mutants: ILedgerLine[];\n}\n\nexport interface ILedgerResult {\n id: string;\n survivorRed: boolean;\n candidateRed: boolean;\n /** Only for a `vacuous` line: whether the candidate also stayed green under the second mutant. */\n candidateGreenUnderSecond?: boolean;\n ok: boolean;\n problem?: string;\n}\n\nconst TEST_TIMEOUT_MILLISECONDS = 300_000;\n\n/** The one place this tool builds an `Error`: `getError` would make dev-configs depend on inversion, which depends on dev-configs. */\n// eslint-disable-next-line venizia/no-new-error -- getError would be a dev-configs -> inversion cycle\nconst replayError = (message: string): Error => new Error(message);\n\nconst checksum = (bytes: Buffer): string =>\n new Bun.CryptoHasher('sha256').update(bytes).digest('hex');\n\n/** The nearest folder at or above the test file that holds a `package.json`: where `bun test` runs. */\nconst packageDirectoryOf = (opts: { root: string; file: string }): string => {\n let current = dirname(join(opts.root, opts.file));\n\n for (;;) {\n if (existsSync(join(current, 'package.json'))) {\n return current;\n }\n\n const parent = dirname(current);\n if (parent === current || parent.length < opts.root.length) {\n return opts.root;\n }\n\n current = parent;\n }\n};\n\n/** Runs one test file (or the cases matching `name`) and reports whether it failed. */\nconst runIsRed = (opts: { root: string; file: string; name?: string }): boolean => {\n const directory = packageDirectoryOf({ root: opts.root, file: opts.file });\n const target = join(opts.root, opts.file).slice(directory.length + 1);\n const args = ['test', target, ...(opts.name ? ['-t', opts.name] : [])];\n const result = spawnSync('bun', args, {\n cwd: directory,\n encoding: 'utf8',\n timeout: TEST_TIMEOUT_MILLISECONDS,\n killSignal: 'SIGKILL',\n env: { ...process.env, NODE_ENV: 'test' },\n });\n\n if (result.error) {\n throw replayError(`[test-mutate] could not run bun test ${target}: ${result.error.message}`);\n }\n\n // A name filter that matches nothing runs no case and exits 0: that would read as \"green\" and could\n // hide a typo as a vacuous test, so a run that executed nothing is an unusable ledger line.\n const output = `${result.stdout ?? ''}${result.stderr ?? ''}`;\n const passed = Number(/^\\s*(\\d+) pass/m.exec(output)?.[1] ?? 0);\n const failed = Number(/^\\s*(\\d+) fail/m.exec(output)?.[1] ?? 0);\n\n if (passed + failed === 0) {\n throw replayError(\n `[test-mutate] bun test ${target}${opts.name ? ` -t ${opts.name}` : ''} ran no case | check the file and the name`,\n );\n }\n\n return result.status !== 0 || failed > 0;\n};\n\n/** Applies `mutant`, runs `action`, and puts the file back byte for byte, verified by checksum. */\nconst withMutant = <T>(opts: {\n root: string;\n mutant: IMutant;\n scratch: string;\n id: string;\n action: () => T;\n}): T => {\n const path = join(opts.root, opts.mutant.file);\n const original = readFileSync(path);\n const text = original.toString('utf8');\n const occurrences = text.split(opts.mutant.find).length - 1;\n\n if (occurrences !== 1) {\n throw replayError(\n `[test-mutate][${opts.id}] \\`find\\` occurs ${occurrences} times in ${opts.mutant.file}, it must occur exactly once`,\n );\n }\n\n mkdirSync(opts.scratch, { recursive: true });\n const backup = join(opts.scratch, `test-mutate-${opts.id.replace(/[^\\w.-]/g, '_')}.orig`);\n if (existsSync(backup)) {\n throw replayError(\n `[test-mutate][${opts.id}] a backup from an interrupted run exists: ${backup} | restore ${opts.mutant.file} from it, then delete it`,\n );\n }\n\n writeFileSync(backup, original);\n const expected = checksum(original);\n\n let outcome: { value: T } | { error: unknown };\n\n try {\n writeFileSync(\n path,\n text.replace(opts.mutant.find, () => opts.mutant.replace),\n );\n outcome = { value: opts.action() };\n } catch (error) {\n outcome = { error };\n }\n\n // Restored whatever the action did, and checked, before its result or error is passed on.\n writeFileSync(path, original);\n\n if (checksum(readFileSync(path)) !== expected) {\n throw replayError(\n `[test-mutate][${opts.id}] ${opts.mutant.file} was not restored | the backup is ${backup}`,\n );\n }\n\n rmSync(backup, { force: true });\n\n if ('error' in outcome) {\n throw outcome.error;\n }\n\n return outcome.value;\n};\n\n/** Applies every edit of `mutant`, runs `action`, and puts each file back byte for byte, verified by checksum. */\nconst withMutants = <T>(opts: {\n root: string;\n mutant: IMutant | IMutant[];\n scratch: string;\n id: string;\n action: () => T;\n}): T => {\n const edits = Array.isArray(opts.mutant) ? opts.mutant : [opts.mutant];\n\n const apply = (index: number): T =>\n index === edits.length\n ? opts.action()\n : withMutant({\n root: opts.root,\n mutant: edits[index],\n scratch: opts.scratch,\n id: `${opts.id}-${index}`,\n action: () => apply(index + 1),\n });\n\n return apply(0);\n};\n\nexport class TestMutateCheck {\n /** Replays every line; never throws for a green survivor (that is a result), only for an unusable ledger. */\n static replayLedger(opts: { root: string; ledger: ILedger; scratch?: string }): ILedgerResult[] {\n const root = resolve(opts.root);\n const scratch = opts.scratch ?? join(root, '.agents/local/tmp');\n const results: ILedgerResult[] = [];\n\n for (const line of opts.ledger.mutants) {\n const { survivorRed, candidateRed } = withMutants({\n root,\n mutant: line.mutant,\n scratch,\n id: line.id,\n action: () => ({\n survivorRed: runIsRed({ root, file: line.survivor, name: line.survivorName }),\n candidateRed: runIsRed({ root, file: line.candidate, name: line.candidateName }),\n }),\n });\n const result: ILedgerResult = { id: line.id, survivorRed, candidateRed, ok: true };\n const expectation = line.expectCandidate ?? 'red';\n\n if (!survivorRed) {\n result.ok = false;\n result.problem =\n 'the survivor stayed green under the mutant: it does not cover the behaviour';\n } else if (expectation === 'red' && !candidateRed) {\n result.ok = false;\n result.problem =\n 'the candidate stayed green under the mutant: record it as vacuous with a second mutant, or pick a mutant it checks';\n } else if (expectation === 'vacuous') {\n if (!line.secondMutant) {\n result.ok = false;\n result.problem = 'a vacuous line needs a secondMutant';\n } else if (candidateRed) {\n result.ok = false;\n result.problem = 'the candidate went red under the mutant: it is not vacuous';\n } else {\n const greenUnderSecond = !withMutants({\n root,\n mutant: line.secondMutant,\n scratch,\n id: `${line.id}-second`,\n action: () => runIsRed({ root, file: line.candidate, name: line.candidateName }),\n });\n result.candidateGreenUnderSecond = greenUnderSecond;\n\n if (!greenUnderSecond) {\n result.ok = false;\n result.problem = 'the candidate went red under the second mutant: it is not vacuous';\n }\n }\n }\n\n results.push(result);\n }\n\n return results;\n }\n\n /** The report lines of a replay, one per ledger line and a closing tally. */\n static formatLedgerResults(opts: { results: ILedgerResult[] }): string[] {\n const { results } = opts;\n const lines = results.map(\n (result) =>\n `${result.ok ? 'ok ' : 'FAIL'} ${result.id}: survivor ${result.survivorRed ? 'red' : 'GREEN'}, candidate ${result.candidateRed ? 'red' : 'green'}${result.problem ? ` | ${result.problem}` : ''}`,\n );\n const failed = results.filter((result) => !result.ok).length;\n lines.push(\n `\\n[test-mutate] ${results.length - failed}/${results.length} ledger lines hold${failed ? `, ${failed} do not` : ''}.`,\n );\n\n return lines;\n }\n}\n"]}
1
+ {"version":3,"file":"test-mutate.js","sourceRoot":"","sources":["../../src/checks/test-mutate.ts"],"names":[],"mappings":";;;AAAA,2DAA+C;AAC/C,qCAAqF;AACrF,yCAAmD;AAwDnD,MAAM,yBAAyB,GAAG,OAAO,CAAC;AAE1C,sIAAsI;AACtI,sGAAsG;AACtG,MAAM,WAAW,GAAG,CAAC,OAAe,EAAS,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;AAEnE,uGAAuG;AACvG,MAAM,kBAAkB,GAAG,CAAC,IAAoC,EAAU,EAAE;IAC1E,IAAI,OAAO,GAAG,IAAA,mBAAO,EAAC,IAAA,gBAAI,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAElD,SAAS,CAAC;QACR,IAAI,IAAA,oBAAU,EAAC,IAAA,gBAAI,EAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAC3D,OAAO,IAAI,CAAC,IAAI,CAAC;QACnB,CAAC;QAED,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF,uFAAuF;AACvF,MAAM,QAAQ,GAAG,CAAC,IAAmD,EAAW,EAAE;IAChF,MAAM,SAAS,GAAG,kBAAkB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,IAAA,gBAAI,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,IAAA,8BAAS,EAAC,KAAK,EAAE,IAAI,EAAE;QACpC,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,yBAAyB;QAClC,UAAU,EAAE,SAAS;QACrB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE;KAC1C,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,WAAW,CAAC,wCAAwC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,oGAAoG;IACpG,4FAA4F;IAC5F,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhE,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,WAAW,CACf,0BAA0B,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,4CAA4C,CACnH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,qGAAqG;AACrG,MAAM,UAAU,GAAG,CAAI,IAMtB,EAAK,EAAE;IACN,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAA,sBAAY,EAAC,IAAI,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAE5D,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,WAAW,CACf,iBAAiB,IAAI,CAAC,EAAE,qBAAqB,WAAW,aAAa,IAAI,CAAC,MAAM,CAAC,IAAI,8BAA8B,CACpH,CAAC;IACJ,CAAC;IAED,IAAA,mBAAS,EAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAA,gBAAI,EAAC,IAAI,CAAC,OAAO,EAAE,eAAe,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1F,IAAI,IAAA,oBAAU,EAAC,MAAM,CAAC,EAAE,CAAC;QACvB,MAAM,WAAW,CACf,iBAAiB,IAAI,CAAC,EAAE,8CAA8C,MAAM,cAAc,IAAI,CAAC,MAAM,CAAC,IAAI,0BAA0B,CACrI,CAAC;IACJ,CAAC;IAED,IAAA,uBAAa,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAEhC,IAAI,OAA0C,CAAC;IAE/C,IAAI,CAAC;QACH,IAAA,uBAAa,EACX,IAAI,EACJ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAC1D,CAAC;QACF,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,0FAA0F;IAC1F,IAAA,uBAAa,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE9B,IAAI,CAAC,IAAA,sBAAY,EAAC,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,MAAM,WAAW,CACf,iBAAiB,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,qCAAqC,MAAM,EAAE,CAC3F,CAAC;IACJ,CAAC;IAED,IAAA,gBAAM,EAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhC,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,OAAO,OAAO,CAAC,KAAK,CAAC;AACvB,CAAC,CAAC;AAEF,oHAAoH;AACpH,MAAM,WAAW,GAAG,CAAI,IAMvB,EAAK,EAAE;IACN,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEvE,MAAM,KAAK,GAAG,CAAC,KAAa,EAAK,EAAE,CACjC,KAAK,KAAK,KAAK,CAAC,MAAM;QACpB,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE;QACf,CAAC,CAAC,UAAU,CAAC;YACT,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC;YACpB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI,KAAK,EAAE;YACzB,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;SAC/B,CAAC,CAAC;IAET,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,MAAa,eAAe;IAC1B,6GAA6G;IAC7G,MAAM,CAAC,YAAY,CAAC,IAAyD;QAC3E,MAAM,IAAI,GAAG,IAAA,mBAAO,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAA,gBAAI,EAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAChE,MAAM,OAAO,GAAoB,EAAE,CAAC;QAEpC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,WAAW,CAAC;gBAChD,IAAI;gBACJ,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO;gBACP,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;oBACb,WAAW,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;oBAC7E,YAAY,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;iBACjF,CAAC;aACH,CAAC,CAAC;YACH,MAAM,MAAM,GAAkB,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YACnF,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC;YAElD,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC;gBAClB,MAAM,CAAC,OAAO;oBACZ,6EAA6E,CAAC;YAClF,CAAC;iBAAM,IAAI,WAAW,KAAK,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClD,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC;gBAClB,MAAM,CAAC,OAAO;oBACZ,oHAAoH,CAAC;YACzH,CAAC;iBAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBACrC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;oBACvB,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC;oBAClB,MAAM,CAAC,OAAO,GAAG,qCAAqC,CAAC;gBACzD,CAAC;qBAAM,IAAI,YAAY,EAAE,CAAC;oBACxB,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC;oBAClB,MAAM,CAAC,OAAO,GAAG,4DAA4D,CAAC;gBAChF,CAAC;qBAAM,CAAC;oBACN,MAAM,gBAAgB,GAAG,CAAC,WAAW,CAAC;wBACpC,IAAI;wBACJ,MAAM,EAAE,IAAI,CAAC,YAAY;wBACzB,OAAO;wBACP,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,SAAS;wBACvB,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;qBACjF,CAAC,CAAC;oBACH,MAAM,CAAC,yBAAyB,GAAG,gBAAgB,CAAC;oBAEpD,IAAI,CAAC,gBAAgB,EAAE,CAAC;wBACtB,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC;wBAClB,MAAM,CAAC,OAAO,GAAG,mEAAmE,CAAC;oBACvF,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,6EAA6E;IAC7E,MAAM,CAAC,mBAAmB,CAAC,IAAkC;QAC3D,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CACvB,CAAC,MAAM,EAAE,EAAE,CACT,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,cAAc,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,eAAe,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACrM,CAAC;QACF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;QAC7D,KAAK,CAAC,IAAI,CACR,mBAAmB,OAAO,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,MAAM,qBAAqB,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CACvH,CAAC;QAEF,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAzED,0CAyEC","sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\n/**\n * Replays the mutation proof of the trim-tests method. A ledger line says: \"this test (the\n * candidate) is redundant because that test (the survivor) already catches the same break\". The\n * replay applies the break (the mutant) to a file, runs the survivor and the candidate, and puts the\n * file back. The survivor must go red. The candidate must go red too, unless the line says it is\n * vacuous and a second mutant leaves it green as well.\n *\n * The mutant edits the file the test really loads: the package's own `src` for a test that imports\n * through the `@/` alias, or the `dist` of the dependency for a test that reaches another package\n * through its `exports`. A rebuild is never needed.\n */\nexport interface IMutant {\n /** Repository-relative file to edit (a `src` file, or a `dist` file of a dependency). */\n file: string;\n /** Text that must occur exactly once in the file. */\n find: string;\n replace: string;\n}\n\nexport interface ILedgerLine {\n id: string;\n /** Repository-relative test file that is deleted. */\n candidate: string;\n /** Run only the cases whose name matches (`bun test -t`). Default: the whole file. */\n candidateName?: string;\n /** Repository-relative test file that stays. */\n survivor: string;\n survivorName?: string;\n /**\n * The break. An array applies every edit together: a survivor in the package that owns the code\n * loads its `src`, a candidate in another package loads that package's `dist`, so one break is two edits.\n */\n mutant: IMutant | IMutant[];\n /** The source line the mutant stands for, `path:line`; recorded, not used by the replay. */\n srcLine?: string;\n /** `red` (default): the candidate must fail. `vacuous`: it must stay green under `mutant` AND `secondMutant`. */\n expectCandidate?: 'red' | 'vacuous';\n secondMutant?: IMutant | IMutant[];\n}\n\nexport interface ILedger {\n mutants: ILedgerLine[];\n}\n\nexport interface ILedgerResult {\n id: string;\n survivorRed: boolean;\n candidateRed: boolean;\n /** Only for a `vacuous` line: whether the candidate also stayed green under the second mutant. */\n candidateGreenUnderSecond?: boolean;\n ok: boolean;\n problem?: string;\n}\n\nconst TEST_TIMEOUT_MILLISECONDS = 300_000;\n\n/** The one place this tool builds an `Error`: `getError` would make dev-configs depend on inversion, which depends on dev-configs. */\n// eslint-disable-next-line venizia/no-new-error -- getError would be a dev-configs -> inversion cycle\nconst replayError = (message: string): Error => new Error(message);\n\n/** The nearest folder at or above the test file that holds a `package.json`: where `bun test` runs. */\nconst packageDirectoryOf = (opts: { root: string; file: string }): string => {\n let current = dirname(join(opts.root, opts.file));\n\n for (;;) {\n if (existsSync(join(current, 'package.json'))) {\n return current;\n }\n\n const parent = dirname(current);\n if (parent === current || parent.length < opts.root.length) {\n return opts.root;\n }\n\n current = parent;\n }\n};\n\n/** Runs one test file (or the cases matching `name`) and reports whether it failed. */\nconst runIsRed = (opts: { root: string; file: string; name?: string }): boolean => {\n const directory = packageDirectoryOf({ root: opts.root, file: opts.file });\n const target = join(opts.root, opts.file).slice(directory.length + 1);\n const args = ['test', target, ...(opts.name ? ['-t', opts.name] : [])];\n const result = spawnSync('bun', args, {\n cwd: directory,\n encoding: 'utf8',\n timeout: TEST_TIMEOUT_MILLISECONDS,\n killSignal: 'SIGKILL',\n env: { ...process.env, NODE_ENV: 'test' },\n });\n\n if (result.error) {\n throw replayError(`[test-mutate] could not run bun test ${target}: ${result.error.message}`);\n }\n\n // A name filter that matches nothing runs no case and exits 0: that would read as \"green\" and could\n // hide a typo as a vacuous test, so a run that executed nothing is an unusable ledger line.\n const output = `${result.stdout ?? ''}${result.stderr ?? ''}`;\n const passed = Number(/^\\s*(\\d+) pass/m.exec(output)?.[1] ?? 0);\n const failed = Number(/^\\s*(\\d+) fail/m.exec(output)?.[1] ?? 0);\n\n if (passed + failed === 0) {\n throw replayError(\n `[test-mutate] bun test ${target}${opts.name ? ` -t ${opts.name}` : ''} ran no case | check the file and the name`,\n );\n }\n\n return result.status !== 0 || failed > 0;\n};\n\n/** Applies `mutant`, runs `action`, and puts the file back byte for byte, verified byte for byte. */\nconst withMutant = <T>(opts: {\n root: string;\n mutant: IMutant;\n scratch: string;\n id: string;\n action: () => T;\n}): T => {\n const path = join(opts.root, opts.mutant.file);\n const original = readFileSync(path);\n const text = original.toString('utf8');\n const occurrences = text.split(opts.mutant.find).length - 1;\n\n if (occurrences !== 1) {\n throw replayError(\n `[test-mutate][${opts.id}] \\`find\\` occurs ${occurrences} times in ${opts.mutant.file}, it must occur exactly once`,\n );\n }\n\n mkdirSync(opts.scratch, { recursive: true });\n const backup = join(opts.scratch, `test-mutate-${opts.id.replace(/[^\\w.-]/g, '_')}.orig`);\n if (existsSync(backup)) {\n throw replayError(\n `[test-mutate][${opts.id}] a backup from an interrupted run exists: ${backup} | restore ${opts.mutant.file} from it, then delete it`,\n );\n }\n\n writeFileSync(backup, original);\n\n let outcome: { value: T } | { error: unknown };\n\n try {\n writeFileSync(\n path,\n text.replace(opts.mutant.find, () => opts.mutant.replace),\n );\n outcome = { value: opts.action() };\n } catch (error) {\n outcome = { error };\n }\n\n // Restored whatever the action did, and checked, before its result or error is passed on.\n writeFileSync(path, original);\n\n if (!readFileSync(path).equals(original)) {\n throw replayError(\n `[test-mutate][${opts.id}] ${opts.mutant.file} was not restored | the backup is ${backup}`,\n );\n }\n\n rmSync(backup, { force: true });\n\n if ('error' in outcome) {\n throw outcome.error;\n }\n\n return outcome.value;\n};\n\n/** Applies every edit of `mutant`, runs `action`, and puts each file back byte for byte, verified byte for byte. */\nconst withMutants = <T>(opts: {\n root: string;\n mutant: IMutant | IMutant[];\n scratch: string;\n id: string;\n action: () => T;\n}): T => {\n const edits = Array.isArray(opts.mutant) ? opts.mutant : [opts.mutant];\n\n const apply = (index: number): T =>\n index === edits.length\n ? opts.action()\n : withMutant({\n root: opts.root,\n mutant: edits[index],\n scratch: opts.scratch,\n id: `${opts.id}-${index}`,\n action: () => apply(index + 1),\n });\n\n return apply(0);\n};\n\nexport class TestMutateCheck {\n /** Replays every line; never throws for a green survivor (that is a result), only for an unusable ledger. */\n static replayLedger(opts: { root: string; ledger: ILedger; scratch?: string }): ILedgerResult[] {\n const root = resolve(opts.root);\n const scratch = opts.scratch ?? join(root, '.agents/local/tmp');\n const results: ILedgerResult[] = [];\n\n for (const line of opts.ledger.mutants) {\n const { survivorRed, candidateRed } = withMutants({\n root,\n mutant: line.mutant,\n scratch,\n id: line.id,\n action: () => ({\n survivorRed: runIsRed({ root, file: line.survivor, name: line.survivorName }),\n candidateRed: runIsRed({ root, file: line.candidate, name: line.candidateName }),\n }),\n });\n const result: ILedgerResult = { id: line.id, survivorRed, candidateRed, ok: true };\n const expectation = line.expectCandidate ?? 'red';\n\n if (!survivorRed) {\n result.ok = false;\n result.problem =\n 'the survivor stayed green under the mutant: it does not cover the behaviour';\n } else if (expectation === 'red' && !candidateRed) {\n result.ok = false;\n result.problem =\n 'the candidate stayed green under the mutant: record it as vacuous with a second mutant, or pick a mutant it checks';\n } else if (expectation === 'vacuous') {\n if (!line.secondMutant) {\n result.ok = false;\n result.problem = 'a vacuous line needs a secondMutant';\n } else if (candidateRed) {\n result.ok = false;\n result.problem = 'the candidate went red under the mutant: it is not vacuous';\n } else {\n const greenUnderSecond = !withMutants({\n root,\n mutant: line.secondMutant,\n scratch,\n id: `${line.id}-second`,\n action: () => runIsRed({ root, file: line.candidate, name: line.candidateName }),\n });\n result.candidateGreenUnderSecond = greenUnderSecond;\n\n if (!greenUnderSecond) {\n result.ok = false;\n result.problem = 'the candidate went red under the second mutant: it is not vacuous';\n }\n }\n }\n\n results.push(result);\n }\n\n return results;\n }\n\n /** The report lines of a replay, one per ledger line and a closing tally. */\n static formatLedgerResults(opts: { results: ILedgerResult[] }): string[] {\n const { results } = opts;\n const lines = results.map(\n (result) =>\n `${result.ok ? 'ok ' : 'FAIL'} ${result.id}: survivor ${result.survivorRed ? 'red' : 'GREEN'}, candidate ${result.candidateRed ? 'red' : 'green'}${result.problem ? ` | ${result.problem}` : ''}`,\n );\n const failed = results.filter((result) => !result.ok).length;\n lines.push(\n `\\n[test-mutate] ${results.length - failed}/${results.length} ledger lines hold${failed ? `, ${failed} do not` : ''}.`,\n );\n\n return lines;\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ /** The removed `@venizia/ignis/<sub-path>` specifiers and the `@venizia/ignis-connectors/<sub-path>` they became. */
2
+ export declare class ConnectorSpecifiers {
3
+ static readonly SUBPATHS: ReadonlyArray<string>;
4
+ static readonly MOVES: ReadonlyMap<string, string>;
5
+ }
6
+ export interface IConnectorImportsResult {
7
+ output: string;
8
+ changed: boolean;
9
+ /** How many specifiers were moved. */
10
+ rewritten: number;
11
+ }
12
+ /** Rewrites the module specifiers of the removed connector sub-paths. */
13
+ export declare class ConnectorImports {
14
+ static rewrite(opts: {
15
+ typescript: typeof import('typescript');
16
+ fileName: string;
17
+ source: string;
18
+ }): IConnectorImportsResult;
19
+ /**
20
+ * The `package.json` nearest to `file` (not above `root`), and whether it lists the connectors package; `undefined` when
21
+ * there is none to read.
22
+ */
23
+ static findManifest(opts: {
24
+ file: string;
25
+ root: string;
26
+ }): {
27
+ path: string;
28
+ hasConnectors: boolean;
29
+ } | undefined;
30
+ }
31
+ /**
32
+ * `devz codemod connector-imports [paths...] [--write | --check]`: moves the removed
33
+ * `@venizia/ignis/<connector sub-path>` specifiers to `@venizia/ignis-connectors`. It is a dry run unless `--write`
34
+ * is given. `--check` is the same dry run, and exits 1 while a file would change.
35
+ */
36
+ export declare class ConnectorImportsCommand {
37
+ static readonly USAGE = "Usage: devz codemod connector-imports [paths...] [--write | --check]\n\nMoves the connector sub-path imports of @venizia/ignis to @venizia/ignis-connectors. The sub-paths\n@venizia/ignis/postgres, /postgres/node-postgres, /postgres/postgres-js, /postgres/pglite,\n/postgres/supabase, /relational, /sqlite, /sqlite/libsql, /search, /search/controllers, /meilisearch,\n/typesense and /typesense/controllers are removed; each one is the same name under\n@venizia/ignis-connectors, so the rewrite changes only the specifier.\n\nIt reads TypeScript files (.ts, .tsx, .mts, .cts): import and export declarations, import(\"...\"),\nrequire(\"...\"), require.resolve(\"...\") and import.meta.resolve(\"...\"), import(\"...\") types, declare module\n\"...\" and the module name of mock.module(\"...\") style calls. A .js, .cjs or .mjs file is not read: edit it by hand. Other sub-paths of @venizia/ignis (mail, static-asset,\ntesting, websocket, ...) and the root are not touched. The app must list @venizia/ignis-connectors as a\ndirect dependency: it reports each package.json that does not.\n\n --write write the changed files (without it, nothing is written)\n --check dry run that exits 1 while a file would change (for CI)\n --help print this text and exit\n\nWith no flag it lists what would change and writes nothing. Inside a git repository it reads the\nfiles git knows (tracked, or untracked and not ignored), and --write refuses a file with local changes\n(changed, staged or untracked): commit or stash it first, so git can undo the codemod.";
38
+ static run(opts: {
39
+ root: string;
40
+ args: string[];
41
+ }): Promise<number>;
42
+ }
43
+ //# sourceMappingURL=connector-imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector-imports.d.ts","sourceRoot":"","sources":["../../../src/cli/codemod/connector-imports.ts"],"names":[],"mappings":"AA8DA,qHAAqH;AACrH,qBAAa,mBAAmB;IAC9B,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAc7C;IAEF,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAKhD;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,qBAAa,gBAAgB;IAC3B,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QACnB,UAAU,EAAE,cAAc,YAAY,CAAC,CAAC;QACxC,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,GAAG,uBAAuB;IAkF3B;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS;CAoCzD;AAED;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,MAAM,CAAC,QAAQ,CAAC,KAAK,4hDAAS;WAEjB,GAAG,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAwH1E"}
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectorImportsCommand = exports.ConnectorImports = exports.ConnectorSpecifiers = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const files_1 = require("./files");
7
+ const USAGE = `Usage: devz codemod connector-imports [paths...] [--write | --check]
8
+
9
+ Moves the connector sub-path imports of @venizia/ignis to @venizia/ignis-connectors. The sub-paths
10
+ @venizia/ignis/postgres, /postgres/node-postgres, /postgres/postgres-js, /postgres/pglite,
11
+ /postgres/supabase, /relational, /sqlite, /sqlite/libsql, /search, /search/controllers, /meilisearch,
12
+ /typesense and /typesense/controllers are removed; each one is the same name under
13
+ @venizia/ignis-connectors, so the rewrite changes only the specifier.
14
+
15
+ It reads TypeScript files (.ts, .tsx, .mts, .cts): import and export declarations, import("..."),
16
+ require("..."), require.resolve("...") and import.meta.resolve("..."), import("...") types, declare module
17
+ "..." and the module name of mock.module("...") style calls. A .js, .cjs or .mjs file is not read: edit it by hand. Other sub-paths of @venizia/ignis (mail, static-asset,
18
+ testing, websocket, ...) and the root are not touched. The app must list @venizia/ignis-connectors as a
19
+ direct dependency: it reports each package.json that does not.
20
+
21
+ --write write the changed files (without it, nothing is written)
22
+ --check dry run that exits 1 while a file would change (for CI)
23
+ --help print this text and exit
24
+
25
+ With no flag it lists what would change and writes nothing. Inside a git repository it reads the
26
+ files git knows (tracked, or untracked and not ignored), and --write refuses a file with local changes
27
+ (changed, staged or untracked): commit or stash it first, so git can undo the codemod.`;
28
+ /** A usage error: nothing was read or written. */
29
+ const USAGE_ERROR_CODE = 2;
30
+ const CONNECTORS_PACKAGE = '@venizia/ignis-connectors';
31
+ const OLD_PREFIX = '@venizia/ignis/';
32
+ /** The call names that take a module name as their first argument besides `require` and `import()`. */
33
+ const MODULE_NAME_CALLS = new Set([
34
+ 'module',
35
+ 'mock',
36
+ 'doMock',
37
+ 'unmock',
38
+ 'importActual',
39
+ 'requireActual',
40
+ 'importMock',
41
+ 'requireMock',
42
+ ]);
43
+ class ConnectorImportsFlags {
44
+ static { this.WRITE = '--write'; }
45
+ static { this.CHECK = '--check'; }
46
+ static { this.HELP = '--help'; }
47
+ static { this.HELP_SHORT = '-h'; }
48
+ static { this.SCHEME_SET = new Set([
49
+ this.WRITE,
50
+ this.CHECK,
51
+ this.HELP,
52
+ this.HELP_SHORT,
53
+ ]); }
54
+ static isValid(value) {
55
+ return this.SCHEME_SET.has(value);
56
+ }
57
+ }
58
+ /** The removed `@venizia/ignis/<sub-path>` specifiers and the `@venizia/ignis-connectors/<sub-path>` they became. */
59
+ class ConnectorSpecifiers {
60
+ static { this.SUBPATHS = [
61
+ 'postgres',
62
+ 'postgres/node-postgres',
63
+ 'postgres/postgres-js',
64
+ 'postgres/pglite',
65
+ 'postgres/supabase',
66
+ 'relational',
67
+ 'sqlite',
68
+ 'sqlite/libsql',
69
+ 'search',
70
+ 'search/controllers',
71
+ 'meilisearch',
72
+ 'typesense',
73
+ 'typesense/controllers',
74
+ ]; }
75
+ static { this.MOVES = new Map(ConnectorSpecifiers.SUBPATHS.map((subpath) => [
76
+ `${OLD_PREFIX}${subpath}`,
77
+ `${CONNECTORS_PACKAGE}/${subpath}`,
78
+ ])); }
79
+ }
80
+ exports.ConnectorSpecifiers = ConnectorSpecifiers;
81
+ /** Rewrites the module specifiers of the removed connector sub-paths. */
82
+ class ConnectorImports {
83
+ static rewrite(opts) {
84
+ const { typescript: ts, fileName, source } = opts;
85
+ const scriptKind = fileName.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
86
+ const file = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKind);
87
+ const edits = [];
88
+ const consider = (literal) => {
89
+ if (!literal || !ts.isStringLiteralLike(literal)) {
90
+ return;
91
+ }
92
+ const moved = ConnectorSpecifiers.MOVES.get(literal.text);
93
+ if (moved === undefined) {
94
+ return;
95
+ }
96
+ const start = literal.getStart(file);
97
+ const quote = source[start];
98
+ edits.push({ start, end: literal.getEnd(), text: `${quote}${moved}${quote}` });
99
+ };
100
+ const isModuleNameCall = (call) => {
101
+ const callee = call.expression;
102
+ if (callee.kind === ts.SyntaxKind.ImportKeyword) {
103
+ return true;
104
+ }
105
+ if (ts.isIdentifier(callee)) {
106
+ return callee.text === 'require';
107
+ }
108
+ if (!ts.isPropertyAccessExpression(callee)) {
109
+ return false;
110
+ }
111
+ if (callee.name.text === 'resolve') {
112
+ return ((ts.isIdentifier(callee.expression) && callee.expression.text === 'require') ||
113
+ ts.isMetaProperty(callee.expression));
114
+ }
115
+ return MODULE_NAME_CALLS.has(callee.name.text);
116
+ };
117
+ const visit = (node) => {
118
+ if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
119
+ consider(node.moduleSpecifier);
120
+ }
121
+ else if (ts.isImportEqualsDeclaration(node)) {
122
+ if (ts.isExternalModuleReference(node.moduleReference)) {
123
+ consider(node.moduleReference.expression);
124
+ }
125
+ }
126
+ else if (ts.isCallExpression(node)) {
127
+ if (isModuleNameCall(node)) {
128
+ consider(node.arguments[0]);
129
+ }
130
+ }
131
+ else if (ts.isModuleDeclaration(node)) {
132
+ consider(node.name);
133
+ }
134
+ else if (ts.isImportTypeNode(node)) {
135
+ if (ts.isLiteralTypeNode(node.argument)) {
136
+ consider(node.argument.literal);
137
+ }
138
+ }
139
+ ts.forEachChild(node, visit);
140
+ };
141
+ visit(file);
142
+ if (edits.length === 0) {
143
+ return { output: source, changed: false, rewritten: 0 };
144
+ }
145
+ let output = source;
146
+ for (const edit of edits.sort((a, b) => b.start - a.start)) {
147
+ output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
148
+ }
149
+ return { output, changed: true, rewritten: edits.length };
150
+ }
151
+ /**
152
+ * The `package.json` nearest to `file` (not above `root`), and whether it lists the connectors package; `undefined` when
153
+ * there is none to read.
154
+ */
155
+ static findManifest(opts) {
156
+ const { file, root } = opts;
157
+ let directory = (0, node_path_1.dirname)(file);
158
+ for (;;) {
159
+ const candidate = (0, node_path_1.join)(directory, 'package.json');
160
+ if ((0, node_fs_1.existsSync)(candidate)) {
161
+ let manifest;
162
+ try {
163
+ manifest = JSON.parse((0, node_fs_1.readFileSync)(candidate, 'utf8'));
164
+ }
165
+ catch (error) {
166
+ console.warn(`${candidate} is not valid JSON, so its dependencies were not checked | ${error instanceof Error ? error.message : String(error)}`);
167
+ return undefined;
168
+ }
169
+ const listed = typeof manifest === 'object' &&
170
+ manifest !== null &&
171
+ ['dependencies', 'devDependencies', 'peerDependencies'].some((field) => {
172
+ const group = Reflect.get(manifest, field);
173
+ return typeof group === 'object' && group !== null && CONNECTORS_PACKAGE in group;
174
+ });
175
+ return { path: candidate, hasConnectors: listed };
176
+ }
177
+ if (directory === root || (0, node_path_1.dirname)(directory) === directory) {
178
+ return undefined;
179
+ }
180
+ directory = (0, node_path_1.dirname)(directory);
181
+ }
182
+ }
183
+ }
184
+ exports.ConnectorImports = ConnectorImports;
185
+ /**
186
+ * `devz codemod connector-imports [paths...] [--write | --check]`: moves the removed
187
+ * `@venizia/ignis/<connector sub-path>` specifiers to `@venizia/ignis-connectors`. It is a dry run unless `--write`
188
+ * is given. `--check` is the same dry run, and exits 1 while a file would change.
189
+ */
190
+ class ConnectorImportsCommand {
191
+ static { this.USAGE = USAGE; }
192
+ static async run(opts) {
193
+ const { root, args } = opts;
194
+ if (args.includes(ConnectorImportsFlags.HELP) ||
195
+ args.includes(ConnectorImportsFlags.HELP_SHORT)) {
196
+ console.log(USAGE);
197
+ return 0;
198
+ }
199
+ const flags = args.filter((argument) => argument.startsWith('-'));
200
+ const paths = args.filter((argument) => !argument.startsWith('-'));
201
+ const unknown = flags.filter((flag) => !ConnectorImportsFlags.isValid(flag));
202
+ if (unknown.length > 0) {
203
+ console.error(`devz codemod: unknown option ${unknown.map((flag) => `"${flag}"`).join(', ')}\n${USAGE}`);
204
+ return USAGE_ERROR_CODE;
205
+ }
206
+ const isWrite = flags.includes(ConnectorImportsFlags.WRITE);
207
+ const isCheck = flags.includes(ConnectorImportsFlags.CHECK);
208
+ if (isWrite && isCheck) {
209
+ console.error(`devz codemod: ${ConnectorImportsFlags.WRITE} and ${ConnectorImportsFlags.CHECK} contradict each other\n${USAGE}`);
210
+ return USAGE_ERROR_CODE;
211
+ }
212
+ let typescript;
213
+ try {
214
+ const loaded = await import('typescript');
215
+ typescript = loaded.default;
216
+ }
217
+ catch {
218
+ console.error('devz codemod: the "typescript" package is required to read your sources');
219
+ return 1;
220
+ }
221
+ const targets = (paths.length > 0 ? paths : ['.']).map((path) => (0, node_path_1.resolve)(root, path));
222
+ const missing = new Set();
223
+ let changedCount = 0;
224
+ let specifierCount = 0;
225
+ let refusedCount = 0;
226
+ for (const target of targets) {
227
+ const files = files_1.CodemodFiles.collect({ target });
228
+ const dirty = isWrite ? files_1.CodemodFiles.dirty({ target }) : undefined;
229
+ if (files.length === 0 && paths.length > 0) {
230
+ console.warn(`devz codemod: no source files under "${(0, node_path_1.relative)(root, target) || target}" (git ignores the path, or it holds none): nothing was read`);
231
+ }
232
+ for (const file of files) {
233
+ const source = (0, node_fs_1.readFileSync)(file, 'utf8');
234
+ if (!source.includes(OLD_PREFIX)) {
235
+ continue;
236
+ }
237
+ const result = ConnectorImports.rewrite({ typescript, fileName: file, source });
238
+ if (!result.changed) {
239
+ continue;
240
+ }
241
+ const shown = (0, node_path_1.relative)(root, file).split('\\').join('/') || file;
242
+ if (dirty?.has(file)) {
243
+ refusedCount += 1;
244
+ console.warn(`refused ${shown} has local changes (commit or stash them, then run again)`);
245
+ continue;
246
+ }
247
+ changedCount += 1;
248
+ specifierCount += result.rewritten;
249
+ console.log(`${isWrite ? 'changed' : 'would change'} ${shown} (${result.rewritten} specifier(s))`);
250
+ const manifest = ConnectorImports.findManifest({ file, root });
251
+ if (manifest && !manifest.hasConnectors) {
252
+ missing.add((0, node_path_1.relative)(root, manifest.path).split('\\').join('/') || manifest.path);
253
+ }
254
+ if (isWrite) {
255
+ (0, node_fs_1.writeFileSync)(file, result.output);
256
+ }
257
+ }
258
+ }
259
+ console.log(`devz codemod connector-imports: ${changedCount} file(s) ${isWrite ? 'changed' : 'would change'}, ${specifierCount} specifier(s) ${isWrite ? 'moved' : 'would be moved'}` +
260
+ (refusedCount > 0 ? `, ${refusedCount} refused` : ''));
261
+ for (const manifestPath of [...missing].sort()) {
262
+ console.warn(`${manifestPath} does not list ${CONNECTORS_PACKAGE}: add it as a dependency, because the imports now come from it`);
263
+ }
264
+ if (!isWrite && changedCount > 0) {
265
+ console.log(`Nothing was written. Run again with ${ConnectorImportsFlags.WRITE} to apply, then add the dependency and run your typecheck.`);
266
+ }
267
+ if (isWrite && refusedCount > 0) {
268
+ return 1;
269
+ }
270
+ return isCheck && changedCount > 0 ? 1 : 0;
271
+ }
272
+ }
273
+ exports.ConnectorImportsCommand = ConnectorImportsCommand;
274
+ //# sourceMappingURL=connector-imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector-imports.js","sourceRoot":"","sources":["../../../src/cli/codemod/connector-imports.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { CodemodFiles } from './files';\n\nconst USAGE = `Usage: devz codemod connector-imports [paths...] [--write | --check]\n\nMoves the connector sub-path imports of @venizia/ignis to @venizia/ignis-connectors. The sub-paths\n@venizia/ignis/postgres, /postgres/node-postgres, /postgres/postgres-js, /postgres/pglite,\n/postgres/supabase, /relational, /sqlite, /sqlite/libsql, /search, /search/controllers, /meilisearch,\n/typesense and /typesense/controllers are removed; each one is the same name under\n@venizia/ignis-connectors, so the rewrite changes only the specifier.\n\nIt reads TypeScript files (.ts, .tsx, .mts, .cts): import and export declarations, import(\"...\"),\nrequire(\"...\"), require.resolve(\"...\") and import.meta.resolve(\"...\"), import(\"...\") types, declare module\n\"...\" and the module name of mock.module(\"...\") style calls. A .js, .cjs or .mjs file is not read: edit it by hand. Other sub-paths of @venizia/ignis (mail, static-asset,\ntesting, websocket, ...) and the root are not touched. The app must list @venizia/ignis-connectors as a\ndirect dependency: it reports each package.json that does not.\n\n --write write the changed files (without it, nothing is written)\n --check dry run that exits 1 while a file would change (for CI)\n --help print this text and exit\n\nWith no flag it lists what would change and writes nothing. Inside a git repository it reads the\nfiles git knows (tracked, or untracked and not ignored), and --write refuses a file with local changes\n(changed, staged or untracked): commit or stash it first, so git can undo the codemod.`;\n\n/** A usage error: nothing was read or written. */\nconst USAGE_ERROR_CODE = 2;\n\nconst CONNECTORS_PACKAGE = '@venizia/ignis-connectors';\nconst OLD_PREFIX = '@venizia/ignis/';\n\n/** The call names that take a module name as their first argument besides `require` and `import()`. */\nconst MODULE_NAME_CALLS = new Set([\n 'module',\n 'mock',\n 'doMock',\n 'unmock',\n 'importActual',\n 'requireActual',\n 'importMock',\n 'requireMock',\n]);\n\nclass ConnectorImportsFlags {\n static readonly WRITE = '--write';\n static readonly CHECK = '--check';\n static readonly HELP = '--help';\n static readonly HELP_SHORT = '-h';\n\n static readonly SCHEME_SET = new Set<string>([\n this.WRITE,\n this.CHECK,\n this.HELP,\n this.HELP_SHORT,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\n/** The removed `@venizia/ignis/<sub-path>` specifiers and the `@venizia/ignis-connectors/<sub-path>` they became. */\nexport class ConnectorSpecifiers {\n static readonly SUBPATHS: ReadonlyArray<string> = [\n 'postgres',\n 'postgres/node-postgres',\n 'postgres/postgres-js',\n 'postgres/pglite',\n 'postgres/supabase',\n 'relational',\n 'sqlite',\n 'sqlite/libsql',\n 'search',\n 'search/controllers',\n 'meilisearch',\n 'typesense',\n 'typesense/controllers',\n ];\n\n static readonly MOVES: ReadonlyMap<string, string> = new Map(\n ConnectorSpecifiers.SUBPATHS.map((subpath) => [\n `${OLD_PREFIX}${subpath}`,\n `${CONNECTORS_PACKAGE}/${subpath}`,\n ]),\n );\n}\n\nexport interface IConnectorImportsResult {\n output: string;\n changed: boolean;\n /** How many specifiers were moved. */\n rewritten: number;\n}\n\n/** Rewrites the module specifiers of the removed connector sub-paths. */\nexport class ConnectorImports {\n static rewrite(opts: {\n typescript: typeof import('typescript');\n fileName: string;\n source: string;\n }): IConnectorImportsResult {\n const { typescript: ts, fileName, source } = opts;\n const scriptKind = fileName.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS;\n const file = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKind);\n const edits: Array<{ start: number; end: number; text: string }> = [];\n\n const consider = (literal: import('typescript').Node | undefined) => {\n if (!literal || !ts.isStringLiteralLike(literal)) {\n return;\n }\n\n const moved = ConnectorSpecifiers.MOVES.get(literal.text);\n if (moved === undefined) {\n return;\n }\n\n const start = literal.getStart(file);\n const quote = source[start];\n edits.push({ start, end: literal.getEnd(), text: `${quote}${moved}${quote}` });\n };\n\n const isModuleNameCall = (call: import('typescript').CallExpression): boolean => {\n const callee = call.expression;\n\n if (callee.kind === ts.SyntaxKind.ImportKeyword) {\n return true;\n }\n\n if (ts.isIdentifier(callee)) {\n return callee.text === 'require';\n }\n\n if (!ts.isPropertyAccessExpression(callee)) {\n return false;\n }\n\n if (callee.name.text === 'resolve') {\n return (\n (ts.isIdentifier(callee.expression) && callee.expression.text === 'require') ||\n ts.isMetaProperty(callee.expression)\n );\n }\n\n return MODULE_NAME_CALLS.has(callee.name.text);\n };\n\n const visit = (node: import('typescript').Node): void => {\n if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {\n consider(node.moduleSpecifier);\n } else if (ts.isImportEqualsDeclaration(node)) {\n if (ts.isExternalModuleReference(node.moduleReference)) {\n consider(node.moduleReference.expression);\n }\n } else if (ts.isCallExpression(node)) {\n if (isModuleNameCall(node)) {\n consider(node.arguments[0]);\n }\n } else if (ts.isModuleDeclaration(node)) {\n consider(node.name);\n } else if (ts.isImportTypeNode(node)) {\n if (ts.isLiteralTypeNode(node.argument)) {\n consider(node.argument.literal);\n }\n }\n\n ts.forEachChild(node, visit);\n };\n\n visit(file);\n\n if (edits.length === 0) {\n return { output: source, changed: false, rewritten: 0 };\n }\n\n let output = source;\n for (const edit of edits.sort((a, b) => b.start - a.start)) {\n output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);\n }\n\n return { output, changed: true, rewritten: edits.length };\n }\n\n /**\n * The `package.json` nearest to `file` (not above `root`), and whether it lists the connectors package; `undefined` when\n * there is none to read.\n */\n static findManifest(opts: {\n file: string;\n root: string;\n }): { path: string; hasConnectors: boolean } | undefined {\n const { file, root } = opts;\n let directory = dirname(file);\n\n for (;;) {\n const candidate = join(directory, 'package.json');\n\n if (existsSync(candidate)) {\n let manifest: unknown;\n try {\n manifest = JSON.parse(readFileSync(candidate, 'utf8'));\n } catch (error) {\n console.warn(\n `${candidate} is not valid JSON, so its dependencies were not checked | ${error instanceof Error ? error.message : String(error)}`,\n );\n return undefined;\n }\n\n const listed =\n typeof manifest === 'object' &&\n manifest !== null &&\n ['dependencies', 'devDependencies', 'peerDependencies'].some((field) => {\n const group: unknown = Reflect.get(manifest, field);\n return typeof group === 'object' && group !== null && CONNECTORS_PACKAGE in group;\n });\n\n return { path: candidate, hasConnectors: listed };\n }\n\n if (directory === root || dirname(directory) === directory) {\n return undefined;\n }\n\n directory = dirname(directory);\n }\n }\n}\n\n/**\n * `devz codemod connector-imports [paths...] [--write | --check]`: moves the removed\n * `@venizia/ignis/<connector sub-path>` specifiers to `@venizia/ignis-connectors`. It is a dry run unless `--write`\n * is given. `--check` is the same dry run, and exits 1 while a file would change.\n */\nexport class ConnectorImportsCommand {\n static readonly USAGE = USAGE;\n\n static async run(opts: { root: string; args: string[] }): Promise<number> {\n const { root, args } = opts;\n\n if (\n args.includes(ConnectorImportsFlags.HELP) ||\n args.includes(ConnectorImportsFlags.HELP_SHORT)\n ) {\n console.log(USAGE);\n return 0;\n }\n\n const flags = args.filter((argument) => argument.startsWith('-'));\n const paths = args.filter((argument) => !argument.startsWith('-'));\n\n const unknown = flags.filter((flag) => !ConnectorImportsFlags.isValid(flag));\n if (unknown.length > 0) {\n console.error(\n `devz codemod: unknown option ${unknown.map((flag) => `\"${flag}\"`).join(', ')}\\n${USAGE}`,\n );\n return USAGE_ERROR_CODE;\n }\n\n const isWrite = flags.includes(ConnectorImportsFlags.WRITE);\n const isCheck = flags.includes(ConnectorImportsFlags.CHECK);\n\n if (isWrite && isCheck) {\n console.error(\n `devz codemod: ${ConnectorImportsFlags.WRITE} and ${ConnectorImportsFlags.CHECK} contradict each other\\n${USAGE}`,\n );\n return USAGE_ERROR_CODE;\n }\n\n let typescript: typeof import('typescript');\n try {\n const loaded = await import('typescript');\n typescript = loaded.default;\n } catch {\n console.error('devz codemod: the \"typescript\" package is required to read your sources');\n return 1;\n }\n\n const targets = (paths.length > 0 ? paths : ['.']).map((path) => resolve(root, path));\n const missing = new Set<string>();\n let changedCount = 0;\n let specifierCount = 0;\n let refusedCount = 0;\n\n for (const target of targets) {\n const files = CodemodFiles.collect({ target });\n const dirty = isWrite ? CodemodFiles.dirty({ target }) : undefined;\n\n if (files.length === 0 && paths.length > 0) {\n console.warn(\n `devz codemod: no source files under \"${relative(root, target) || target}\" (git ignores the path, or it holds none): nothing was read`,\n );\n }\n\n for (const file of files) {\n const source = readFileSync(file, 'utf8');\n\n if (!source.includes(OLD_PREFIX)) {\n continue;\n }\n\n const result = ConnectorImports.rewrite({ typescript, fileName: file, source });\n\n if (!result.changed) {\n continue;\n }\n\n const shown = relative(root, file).split('\\\\').join('/') || file;\n\n if (dirty?.has(file)) {\n refusedCount += 1;\n console.warn(\n `refused ${shown} has local changes (commit or stash them, then run again)`,\n );\n continue;\n }\n\n changedCount += 1;\n specifierCount += result.rewritten;\n console.log(\n `${isWrite ? 'changed' : 'would change'} ${shown} (${result.rewritten} specifier(s))`,\n );\n\n const manifest = ConnectorImports.findManifest({ file, root });\n if (manifest && !manifest.hasConnectors) {\n missing.add(relative(root, manifest.path).split('\\\\').join('/') || manifest.path);\n }\n\n if (isWrite) {\n writeFileSync(file, result.output);\n }\n }\n }\n\n console.log(\n `devz codemod connector-imports: ${changedCount} file(s) ${isWrite ? 'changed' : 'would change'}, ${specifierCount} specifier(s) ${isWrite ? 'moved' : 'would be moved'}` +\n (refusedCount > 0 ? `, ${refusedCount} refused` : ''),\n );\n\n for (const manifestPath of [...missing].sort()) {\n console.warn(\n `${manifestPath} does not list ${CONNECTORS_PACKAGE}: add it as a dependency, because the imports now come from it`,\n );\n }\n\n if (!isWrite && changedCount > 0) {\n console.log(\n `Nothing was written. Run again with ${ConnectorImportsFlags.WRITE} to apply, then add the dependency and run your typecheck.`,\n );\n }\n\n if (isWrite && refusedCount > 0) {\n return 1;\n }\n\n return isCheck && changedCount > 0 ? 1 : 0;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"const-classes.d.ts","sourceRoot":"","sources":["../../../src/cli/codemod/const-classes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAGjC,KAAK,WAAW,GAAG,OAAO,EAAE,CAAC;AAU7B,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oCAAoC;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC,qGAAqG;IACrG,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA4CD;;;;GAIG;AACH,qBAAa,YAAY;IACvB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QACnB,UAAU,EAAE,WAAW,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,4FAA4F;QAC5F,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,cAAc,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,iBAAiB;IA4KrB,OAAO,CAAC,MAAM,CAAC,WAAW;IA8C1B,yDAAyD;IACzD,OAAO,CAAC,MAAM,CAAC,aAAa;IAoD5B,OAAO,CAAC,MAAM,CAAC,UAAU;IAQzB,iIAAiI;IACjI,OAAO,CAAC,MAAM,CAAC,SAAS;IA+BxB,gFAAgF;IAChF,OAAO,CAAC,MAAM,CAAC,YAAY;IAuB3B,OAAO,CAAC,MAAM,CAAC,SAAS;IAqCxB,OAAO,CAAC,MAAM,CAAC,WAAW;IAuB1B,sHAAsH;IACtH,OAAO,CAAC,MAAM,CAAC,UAAU;IAkCzB,OAAO,CAAC,MAAM,CAAC,QAAQ;IA2BvB,wJAAwJ;IACxJ,OAAO,CAAC,MAAM,CAAC,UAAU;CAqD1B;AA4DD,mEAAmE;AACnE,qBAAa,mBAAmB;IAC9B,MAAM,CAAC,QAAQ,CAAC,KAAK,yxDAAS;WAEjB,GAAG,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAuL1E"}
1
+ {"version":3,"file":"const-classes.d.ts","sourceRoot":"","sources":["../../../src/cli/codemod/const-classes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAGjC,KAAK,WAAW,GAAG,OAAO,EAAE,CAAC;AAU7B,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IAClC,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oCAAoC;IACpC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC,qGAAqG;IACrG,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AA4CD;;;;GAIG;AACH,qBAAa,YAAY;IACvB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;QACnB,UAAU,EAAE,WAAW,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,4FAA4F;QAC5F,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,cAAc,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,iBAAiB;IA4KrB,OAAO,CAAC,MAAM,CAAC,WAAW;IA8C1B,yDAAyD;IACzD,OAAO,CAAC,MAAM,CAAC,aAAa;IAoD5B,OAAO,CAAC,MAAM,CAAC,UAAU;IAQzB,iIAAiI;IACjI,OAAO,CAAC,MAAM,CAAC,SAAS;IA+BxB,gFAAgF;IAChF,OAAO,CAAC,MAAM,CAAC,YAAY;IAuB3B,OAAO,CAAC,MAAM,CAAC,SAAS;IAqCxB,OAAO,CAAC,MAAM,CAAC,WAAW;IAsB1B,sHAAsH;IACtH,OAAO,CAAC,MAAM,CAAC,UAAU;IAkCzB,OAAO,CAAC,MAAM,CAAC,QAAQ;IA2BvB,wJAAwJ;IACxJ,OAAO,CAAC,MAAM,CAAC,UAAU;CAqD1B;AA4DD,mEAAmE;AACnE,qBAAa,mBAAmB;IAC9B,MAAM,CAAC,QAAQ,CAAC,KAAK,yxDAAS;WAEjB,GAAG,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAuL1E"}
@@ -323,7 +323,6 @@ class ConstClasses {
323
323
  const { className, typeName, members } = opts;
324
324
  const quote = (value) => `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
325
325
  const lines = [
326
- `/** The values of \`${typeName}\`. */`,
327
326
  `export class ${className} {`,
328
327
  ...members.map(({ value, key }) => ` static readonly ${key} = ${quote(value)};`),
329
328
  '',