@williamthorsen/nmr 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/.readyup/kits/default.js +56 -16
  2. package/.readyup/manifest.json +34 -3
  3. package/README.md +265 -64
  4. package/agents/guidance/rulebooks/nmr.md +5 -2
  5. package/bin/nmr-report-catalog.js +11 -0
  6. package/dist/esm/UserError.d.ts +3 -0
  7. package/dist/esm/UserError.js +6 -0
  8. package/dist/esm/check-cache.d.ts +36 -1
  9. package/dist/esm/check-cache.js +91 -23
  10. package/dist/esm/cli-build.js +2 -1
  11. package/dist/esm/cli-clean.js +2 -1
  12. package/dist/esm/cli-ensure-prepublish-hooks.js +4 -24
  13. package/dist/esm/cli-report-catalog.d.ts +1 -0
  14. package/dist/esm/cli-report-catalog.js +11 -0
  15. package/dist/esm/cli-report-overrides.js +2 -1
  16. package/dist/esm/cli-taze.js +2 -1
  17. package/dist/esm/cli.js +2 -1
  18. package/dist/esm/commands/build-output.d.ts +1 -0
  19. package/dist/esm/commands/build-output.js +25 -2
  20. package/dist/esm/commands/build.d.ts +5 -1
  21. package/dist/esm/commands/build.js +22 -8
  22. package/dist/esm/commands/clean.js +12 -0
  23. package/dist/esm/commands/ensure-prepublish-hooks.d.ts +1 -0
  24. package/dist/esm/commands/ensure-prepublish-hooks.js +43 -0
  25. package/dist/esm/commands/report-catalog.d.ts +1 -0
  26. package/dist/esm/commands/report-catalog.js +40 -0
  27. package/dist/esm/commands/report-overrides.js +30 -7
  28. package/dist/esm/commands/taze.js +2 -1
  29. package/dist/esm/config.d.ts +1 -0
  30. package/dist/esm/config.js +66 -18
  31. package/dist/esm/default-scripts.d.ts +5 -1
  32. package/dist/esm/default-scripts.js +13 -10
  33. package/dist/esm/defineConfig.d.ts +1 -1
  34. package/dist/esm/help.js +3 -1
  35. package/dist/esm/helpers/clampToBytes.d.ts +2 -0
  36. package/dist/esm/helpers/clampToBytes.js +20 -0
  37. package/dist/esm/helpers/createBoundedBuffer.js +1 -4
  38. package/dist/esm/helpers/deriveExcerpt.d.ts +1 -0
  39. package/dist/esm/helpers/deriveExcerpt.js +30 -0
  40. package/dist/esm/helpers/duration.js +16 -9
  41. package/dist/esm/helpers/package-json.d.ts +11 -4
  42. package/dist/esm/helpers/package-json.js +51 -22
  43. package/dist/esm/helpers/readStringValues.d.ts +1 -0
  44. package/dist/esm/helpers/readStringValues.js +8 -0
  45. package/dist/esm/helpers/reportClosing.d.ts +1 -0
  46. package/dist/esm/helpers/reportClosing.js +3 -0
  47. package/dist/esm/helpers/transcript.d.ts +5 -0
  48. package/dist/esm/helpers/transcript.js +59 -0
  49. package/dist/esm/recording.d.ts +65 -0
  50. package/dist/esm/recording.js +96 -0
  51. package/dist/esm/replay-assembly.d.ts +9 -0
  52. package/dist/esm/replay-assembly.js +26 -0
  53. package/dist/esm/report-format.d.ts +18 -0
  54. package/dist/esm/report-format.js +25 -0
  55. package/dist/esm/reportCliFailure.d.ts +2 -0
  56. package/dist/esm/reportCliFailure.js +11 -0
  57. package/dist/esm/resolve-scripts.d.ts +1 -1
  58. package/dist/esm/resolver.d.ts +9 -1
  59. package/dist/esm/resolver.js +28 -18
  60. package/dist/esm/runCli.js +339 -74
  61. package/dist/esm/runner.d.ts +9 -3
  62. package/dist/esm/runner.js +25 -4
  63. package/dist/esm/scripts.d.ts +1 -1
  64. package/dist/esm/steps.d.ts +9 -2
  65. package/dist/esm/steps.js +117 -4
  66. package/dist/esm/types.d.ts +11 -2
  67. package/dist/esm/verbosity.d.ts +15 -4
  68. package/dist/esm/verbosity.js +32 -12
  69. package/dist/esm/verdict.d.ts +29 -0
  70. package/dist/esm/verdict.js +150 -0
  71. package/dist/esm/workspace.d.ts +2 -0
  72. package/dist/esm/workspace.js +20 -3
  73. package/package.json +14 -5
@@ -1,6 +1,6 @@
1
1
  /** @noformat — @generated. Do not edit. Compiled by rdy. */
2
2
  /* eslint-disable */
3
- export const __readyupVersion = "0.26.0";
3
+ export const __readyupVersion = "0.28.0";
4
4
 
5
5
 
6
6
  // .readyup/kits/default.ts
@@ -20,10 +20,12 @@ import {
20
20
 
21
21
  // src/default-scripts.ts
22
22
  var GATE_PROJECTS = "--project unit --project tool";
23
+ var TYPECHECK_STEP = { run: "typecheck", declinesArgs: true };
24
+ var ROOT_TYPECHECK_STEP = { run: "root:typecheck", declinesArgs: true };
23
25
  var workspaceScripts = {
24
26
  build: ["compile"],
25
- check: ["typecheck", "fmt:check", "lint:check", "test"],
26
- "check:strict": ["typecheck", "fmt:check", "lint:strict", "test:coverage"],
27
+ check: [TYPECHECK_STEP, "fmt:check", "lint:check", "test"],
28
+ "check:strict": [TYPECHECK_STEP, "fmt:check", "lint:strict", "test:coverage"],
27
29
  clean: "nmr-clean",
28
30
  compile: "nmr-compile",
29
31
  fix: ["lint", "fmt"],
@@ -33,6 +35,7 @@ var workspaceScripts = {
33
35
  lint: "eslint --fix .",
34
36
  "lint:check": "eslint .",
35
37
  "lint:strict": "strict-lint",
38
+ "report-catalog": "nmr-report-catalog",
36
39
  test: `pnpm exec vitest ${GATE_PROJECTS}`,
37
40
  "test:all": "pnpm exec vitest",
38
41
  "test:coverage": `pnpm exec vitest ${GATE_PROJECTS} --coverage`,
@@ -40,8 +43,9 @@ var workspaceScripts = {
40
43
  "test:unit": "pnpm exec vitest --project unit",
41
44
  "test:watch": `pnpm exec vitest ${GATE_PROJECTS} --watch`,
42
45
  typecheck: "tsgo --noEmit",
43
- // Without `--include-locked`, nothing would be reported in a repo that pins exact version numbers.
44
- upgrade: "nmr-taze --include-locked",
46
+ // Without `--include-locked`, nothing would be reported in a repo that pins exact version numbers. The
47
+ // command is a string because neither half names an nmr command: both are binaries.
48
+ upgrade: "nmr-report-catalog && nmr-taze --include-locked",
45
49
  "view-coverage": "open coverage/index.html"
46
50
  };
47
51
  var rootScripts = {
@@ -49,10 +53,11 @@ var rootScripts = {
49
53
  "audit:dev": "pnpm exec v11y --dev",
50
54
  "audit:prod": "pnpm exec v11y --prod",
51
55
  build: ["-R build"],
52
- check: ["typecheck", "fmt:check", "lint:check", "test"],
53
- "check:strict": ["typecheck", "fmt:check", "lint:strict", "test:coverage"],
54
- // Excludes the audit, which in CI has a workflow of its own.
55
- ci: ["build", "check:strict"],
56
+ check: [TYPECHECK_STEP, "fmt:check", "lint:check", "test"],
57
+ "check:strict": [TYPECHECK_STEP, "fmt:check", "lint:strict", "test:coverage"],
58
+ // Excludes the audit, which in CI has a workflow of its own. The build is what the narrowed check runs
59
+ // against, so it declines the arguments rather than being narrowed by them.
60
+ ci: [{ run: "build", declinesArgs: true }, "check:strict"],
56
61
  clean: "nmr-clean",
57
62
  fix: ["lint", "fmt"],
58
63
  "fix:check": ["fmt:check", "lint:check"],
@@ -61,10 +66,11 @@ var rootScripts = {
61
66
  lint: "eslint --fix .",
62
67
  "lint:check": "eslint .",
63
68
  "lint:strict": "strict-lint",
64
- // The audit costs seconds and `ci` costs minutes, so the cheap gate fails first.
65
- prepush: ["audit", "ci"],
69
+ // The audit costs seconds and `ci` costs minutes, so the cheap gate fails first. The audit reads the
70
+ // dependency tree, which no argument narrowing the code under test says anything about.
71
+ prepush: [{ run: "audit", declinesArgs: true }, "ci"],
66
72
  "report-overrides": "nmr-report-overrides",
67
- "root:check": ["root:typecheck", "fmt:check", "root:lint:check", "root:test"],
73
+ "root:check": [ROOT_TYPECHECK_STEP, "fmt:check", "root:lint:check", "root:test"],
68
74
  "root:lint": "eslint --fix --ignore-pattern 'packages/**' .",
69
75
  "root:lint:check": "eslint --ignore-pattern 'packages/**' .",
70
76
  "root:lint:strict": "strict-lint --ignore-pattern 'packages/**' .",
@@ -73,15 +79,20 @@ var rootScripts = {
73
79
  "root:test:tool": "vitest --config ./vitest.root.config.ts --project tool",
74
80
  "root:test:unit": "vitest --config ./vitest.root.config.ts --project unit",
75
81
  "root:typecheck": "tsgo --noEmit",
76
- "root:upgrade": "nmr-taze --include-locked",
82
+ // Carries the override report for the same reason `upgrade` does: both end in the tool that rewrites a
83
+ // `pnpm.overrides` block, so both need the reporter's rejection ahead of them.
84
+ "root:upgrade": "nmr-report-overrides && nmr-taze --include-locked",
77
85
  test: ["root:test", "-R test"],
78
86
  "test:all": ["root:test:all", "-R test:all"],
79
87
  "test:coverage": ["root:test", "-R test:coverage"],
80
88
  "test:tool": ["root:test:tool", "-R test:tool"],
81
89
  "test:unit": ["root:test:unit", "-R test:unit"],
82
90
  "test:watch": `vitest ${GATE_PROJECTS} --watch`,
83
- typecheck: ["root:typecheck", "-R typecheck"],
84
- // The command must be a string rather than a composite: Passthrough args attach to the chain's last command.
91
+ // Neither step is narrowable, so `nmr typecheck <file>` is rejected rather than checking that file under
92
+ // default options at the root and hunting for it in every package.
93
+ typecheck: [ROOT_TYPECHECK_STEP, { run: "-R typecheck", declinesArgs: true }],
94
+ // The command is a string because neither half names an nmr command: both are binaries, and a composite
95
+ // element can name only a command.
85
96
  upgrade: "nmr-report-overrides && nmr-taze --include-locked --recursive"
86
97
  };
87
98
 
@@ -168,6 +179,13 @@ var default_default = defineRdyKit({
168
179
  check: toolVersionsHasNoPnpm,
169
180
  fix: "Remove pnpm from .tool-versions \u2014 manage via packageManager field and corepack"
170
181
  },
182
+ {
183
+ name: "no package.json declares a pnpm field",
184
+ severity: "error",
185
+ quiet: true,
186
+ check: () => noPnpmFieldInPackageJson(),
187
+ fix: "Move these settings into pnpm-workspace.yaml, quoting each version under `overrides`, or run `pnpx codemod run pnpm-v10-to-v11`. pnpm 11 reads no key from the `pnpm` field, so an override left there pins nothing while an upgrade run with `--write` goes on rewriting it"
188
+ },
171
189
  {
172
190
  name: ".config/nmr.config.ts uses defineConfig",
173
191
  severity: "recommend",
@@ -376,7 +394,7 @@ function formatPaths(paths) {
376
394
  ${paths.map((path2) => ` ${path2}`).join("\n")}`;
377
395
  }
378
396
  function getMinVersion() {
379
- const picked = { "version": "0.30.0" };
397
+ const picked = { "version": "0.32.0" };
380
398
  if (typeof picked["version"] !== "string") {
381
399
  throw new TypeError("nmr/package.json: 'version' must be a string");
382
400
  }
@@ -402,6 +420,15 @@ function isReExportOnly(content) {
402
420
  const statements = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "").split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
403
421
  return statements.length > 0 && statements.every((line) => RE_EXPORT_LINE_PATTERN.test(line));
404
422
  }
423
+ function noPnpmFieldInPackageJson(cwd = process.cwd()) {
424
+ const declaring = findFiles(["**/package.json"], cwd).flatMap((relativePath) => {
425
+ const keys = readPnpmFieldKeys(readFileIn(cwd, relativePath));
426
+ if (keys === void 0) return [];
427
+ return [keys.length > 0 ? `${relativePath} (${keys.join(", ")})` : relativePath];
428
+ });
429
+ if (declaring.length === 0) return true;
430
+ return { ok: false, detail: formatPaths(declaring) };
431
+ }
405
432
  function noReExportOnlyVitestConfigs(cwd = process.cwd()) {
406
433
  const nonRootConfigs = findFiles([`**/vitest.config.${CONFIG_EXTENSIONS}`], cwd).filter((path2) => path2.includes("/"));
407
434
  const reExports = nonRootConfigs.filter((path2) => isReExportOnly(readFileIn(cwd, path2)));
@@ -453,6 +480,18 @@ function readFileIn(cwd, relativePath) {
453
480
  return void 0;
454
481
  }
455
482
  }
483
+ function readPnpmFieldKeys(content) {
484
+ if (content === void 0) return void 0;
485
+ let parsed;
486
+ try {
487
+ parsed = JSON.parse(content);
488
+ } catch {
489
+ return void 0;
490
+ }
491
+ if (!isRecord(parsed)) return void 0;
492
+ const pnpm = parsed["pnpm"];
493
+ return isRecord(pnpm) ? Object.keys(pnpm).toSorted() : void 0;
494
+ }
456
495
  function resolvesVersionViaWorkspace(range) {
457
496
  return WORKSPACE_VERSION_MARKERS.some((marker) => range.startsWith(marker));
458
497
  }
@@ -472,6 +511,7 @@ export {
472
511
  everyTestFileNamesItsTier,
473
512
  hasSupportedEslintVersion,
474
513
  hasSupportedStrictLintVersion,
514
+ noPnpmFieldInPackageJson,
475
515
  noReExportOnlyVitestConfigs,
476
516
  noRetiredVitestConfigs,
477
517
  prettierConfigBuildsOnSharedConfig,
@@ -5,12 +5,43 @@
5
5
  "checklists": [
6
6
  "nmr"
7
7
  ],
8
+ "esbuildVersion": "0.28.1",
9
+ "inputs": [
10
+ {
11
+ "hash": "67afdcb4",
12
+ "kind": "module",
13
+ "path": "kits/default.ts"
14
+ },
15
+ {
16
+ "hash": "2bd89ec9",
17
+ "kind": "inline",
18
+ "path": "../package.json",
19
+ "paths": [
20
+ "version"
21
+ ]
22
+ },
23
+ {
24
+ "hash": "3dfc2ee7",
25
+ "kind": "module",
26
+ "path": "../src/default-scripts.ts"
27
+ },
28
+ {
29
+ "hash": "b42c7523",
30
+ "kind": "module",
31
+ "path": "../src/resolve-scripts.ts"
32
+ },
33
+ {
34
+ "hash": "c2d21075",
35
+ "kind": "module",
36
+ "path": "../src/tiers.ts"
37
+ }
38
+ ],
8
39
  "name": "default",
9
40
  "path": "kits/default.js",
10
- "readyupVersion": "0.26.0",
41
+ "readyupVersion": "0.28.0",
11
42
  "source": "kits/default.ts",
12
- "sourceHash": "7b2a223f",
13
- "targetHash": "bdca19db"
43
+ "sourceHash": "67afdcb4",
44
+ "targetHash": "b923a4b4"
14
45
  }
15
46
  ]
16
47
  }