@williamthorsen/nmr 0.32.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.readyup/kits/default.js +34 -9
- package/.readyup/manifest.json +6 -6
- package/README.md +30 -23
- package/dist/esm/default-scripts.js +5 -5
- package/dist/esm/steps.js +48 -1
- package/dist/esm/taze.js +2 -0
- package/package.json +4 -3
package/.readyup/kits/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @noformat — @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.30.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/default.ts
|
|
@@ -25,7 +25,7 @@ var ROOT_TYPECHECK_STEP = { run: "root:typecheck", declinesArgs: true };
|
|
|
25
25
|
var workspaceScripts = {
|
|
26
26
|
build: ["compile"],
|
|
27
27
|
check: [TYPECHECK_STEP, "fmt:check", "lint:check", "test"],
|
|
28
|
-
"check:strict": [TYPECHECK_STEP, "fmt:check", "lint:strict", "test
|
|
28
|
+
"check:strict": [TYPECHECK_STEP, "fmt:check", "lint:strict", "test"],
|
|
29
29
|
clean: "nmr-clean",
|
|
30
30
|
compile: "nmr-compile",
|
|
31
31
|
fix: ["lint", "fmt"],
|
|
@@ -43,9 +43,8 @@ var workspaceScripts = {
|
|
|
43
43
|
"test:unit": "pnpm exec vitest --project unit",
|
|
44
44
|
"test:watch": `pnpm exec vitest ${GATE_PROJECTS} --watch`,
|
|
45
45
|
typecheck: "tsgo --noEmit",
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
upgrade: "nmr-report-catalog && nmr-taze --include-locked",
|
|
46
|
+
// The command is a string because neither half names an nmr command: both are binaries.
|
|
47
|
+
upgrade: "nmr-report-catalog && nmr-taze",
|
|
49
48
|
"view-coverage": "open coverage/index.html"
|
|
50
49
|
};
|
|
51
50
|
var rootScripts = {
|
|
@@ -54,7 +53,7 @@ var rootScripts = {
|
|
|
54
53
|
"audit:prod": "pnpm exec v11y --prod",
|
|
55
54
|
build: ["-R build"],
|
|
56
55
|
check: [TYPECHECK_STEP, "fmt:check", "lint:check", "test"],
|
|
57
|
-
"check:strict": [TYPECHECK_STEP, "fmt:check", "lint:strict", "test
|
|
56
|
+
"check:strict": [TYPECHECK_STEP, "fmt:check", "lint:strict", "test"],
|
|
58
57
|
// Excludes the audit, which in CI has a workflow of its own. The build is what the narrowed check runs
|
|
59
58
|
// against, so it declines the arguments rather than being narrowed by them.
|
|
60
59
|
ci: [{ run: "build", declinesArgs: true }, "check:strict"],
|
|
@@ -81,7 +80,7 @@ var rootScripts = {
|
|
|
81
80
|
"root:typecheck": "tsgo --noEmit",
|
|
82
81
|
// Carries the override report for the same reason `upgrade` does: both end in the tool that rewrites a
|
|
83
82
|
// `pnpm.overrides` block, so both need the reporter's rejection ahead of them.
|
|
84
|
-
"root:upgrade": "nmr-report-overrides && nmr-taze
|
|
83
|
+
"root:upgrade": "nmr-report-overrides && nmr-taze",
|
|
85
84
|
test: ["root:test", "-R test"],
|
|
86
85
|
"test:all": ["root:test:all", "-R test:all"],
|
|
87
86
|
"test:coverage": ["root:test", "-R test:coverage"],
|
|
@@ -93,7 +92,7 @@ var rootScripts = {
|
|
|
93
92
|
typecheck: [ROOT_TYPECHECK_STEP, { run: "-R typecheck", declinesArgs: true }],
|
|
94
93
|
// The command is a string because neither half names an nmr command: both are binaries, and a composite
|
|
95
94
|
// element can name only a command.
|
|
96
|
-
upgrade: "nmr-report-overrides && nmr-taze --
|
|
95
|
+
upgrade: "nmr-report-overrides && nmr-taze --recursive"
|
|
97
96
|
};
|
|
98
97
|
|
|
99
98
|
// src/resolve-scripts.ts
|
|
@@ -272,6 +271,13 @@ var default_default = defineRdyKit({
|
|
|
272
271
|
check: () => prettierConfigBuildsOnSharedConfig(),
|
|
273
272
|
fix: "Replace the Prettier config with: import { definePrettierConfig } from '@williamthorsen/nmr/prettier'; export default definePrettierConfig();"
|
|
274
273
|
},
|
|
274
|
+
// -- Shared upgrade policy -----------------------------------------------
|
|
275
|
+
{
|
|
276
|
+
name: "taze.config.ts builds on @williamthorsen/nmr/taze",
|
|
277
|
+
severity: "warn",
|
|
278
|
+
check: () => tazeConfigBuildsOnSharedConfig(),
|
|
279
|
+
fix: "Replace the taze config with: import { defineConfig } from '@williamthorsen/nmr/taze'; export default defineConfig(); \u2014 nmr's upgrade policy reaches a repo only through this file, so without it `nmr upgrade` reports nothing where dependencies are pinned to exact versions"
|
|
280
|
+
},
|
|
275
281
|
// -- Audit dependency --------------------------------------------------------
|
|
276
282
|
{
|
|
277
283
|
name: "v11y-check in devDependencies",
|
|
@@ -303,6 +309,8 @@ var CONFIG_EXTENSIONS = "{ts,mts,cts,js,mjs,cjs}";
|
|
|
303
309
|
var SHARED_VITEST_MODULE = "@williamthorsen/nmr/vitest";
|
|
304
310
|
var SHARED_PRETTIER_MODULE = "@williamthorsen/nmr/prettier";
|
|
305
311
|
var INERT_PRETTIER_CONFIGS = [".prettierrc", ".prettierrc.{json,json5,yaml,yml,toml}"];
|
|
312
|
+
var SHARED_TAZE_MODULE = "@williamthorsen/nmr/taze";
|
|
313
|
+
var INERT_TAZE_CONFIGS = [".tazerc", ".tazerc.json", "taze.config.json"];
|
|
306
314
|
var RE_EXPORT_LINE_PATTERN = /^export\s*(?:\{\s*default\s*}|\*)\s*from\s*['"]\.\.\/[^'"]*['"];?$/;
|
|
307
315
|
var MIN_ESLINT_VERSION = "10.0.0";
|
|
308
316
|
var MIN_STRICT_LINT_VERSION = "9.3.0";
|
|
@@ -394,7 +402,7 @@ function formatPaths(paths) {
|
|
|
394
402
|
${paths.map((path2) => ` ${path2}`).join("\n")}`;
|
|
395
403
|
}
|
|
396
404
|
function getMinVersion() {
|
|
397
|
-
const picked = { "version": "0.
|
|
405
|
+
const picked = { "version": "0.33.0" };
|
|
398
406
|
if (typeof picked["version"] !== "string") {
|
|
399
407
|
throw new TypeError("nmr/package.json: 'version' must be a string");
|
|
400
408
|
}
|
|
@@ -495,6 +503,22 @@ function readPnpmFieldKeys(content) {
|
|
|
495
503
|
function resolvesVersionViaWorkspace(range) {
|
|
496
504
|
return WORKSPACE_VERSION_MARKERS.some((marker) => range.startsWith(marker));
|
|
497
505
|
}
|
|
506
|
+
function tazeConfigBuildsOnSharedConfig(cwd = process.cwd()) {
|
|
507
|
+
const configs = findFiles([`taze.config.${CONFIG_EXTENSIONS}`], cwd);
|
|
508
|
+
if (configs.length === 0) {
|
|
509
|
+
return { ok: false, detail: describeMissingTazeConfig(cwd) };
|
|
510
|
+
}
|
|
511
|
+
const stale = configs.filter(
|
|
512
|
+
(relativePath) => !importsSharedExport(readFileIn(cwd, relativePath), "defineConfig", SHARED_TAZE_MODULE)
|
|
513
|
+
);
|
|
514
|
+
if (stale.length === 0) return true;
|
|
515
|
+
return { ok: false, detail: `does not import defineConfig from ${SHARED_TAZE_MODULE}: ${stale.join(", ")}` };
|
|
516
|
+
}
|
|
517
|
+
function describeMissingTazeConfig(cwd) {
|
|
518
|
+
const inert = findFiles(INERT_TAZE_CONFIGS, cwd);
|
|
519
|
+
if (inert.length > 0) return `holds no code to call the factory: ${inert.join(", ")}`;
|
|
520
|
+
return "taze.config.ts is missing";
|
|
521
|
+
}
|
|
498
522
|
function toolVersionsHasNoPnpm() {
|
|
499
523
|
const content = readFile(".tool-versions");
|
|
500
524
|
if (content === void 0) return true;
|
|
@@ -515,6 +539,7 @@ export {
|
|
|
515
539
|
noReExportOnlyVitestConfigs,
|
|
516
540
|
noRetiredVitestConfigs,
|
|
517
541
|
prettierConfigBuildsOnSharedConfig,
|
|
542
|
+
tazeConfigBuildsOnSharedConfig,
|
|
518
543
|
vitestConfigBuildsOnSharedConfig,
|
|
519
544
|
vitestRootConfigBuildsOnSharedConfig
|
|
520
545
|
};
|
package/.readyup/manifest.json
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"esbuildVersion": "0.28.1",
|
|
9
9
|
"inputs": [
|
|
10
10
|
{
|
|
11
|
-
"hash": "
|
|
11
|
+
"hash": "904ac753",
|
|
12
12
|
"kind": "module",
|
|
13
13
|
"path": "kits/default.ts"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
"hash": "
|
|
16
|
+
"hash": "1cd4c58d",
|
|
17
17
|
"kind": "inline",
|
|
18
18
|
"path": "../package.json",
|
|
19
19
|
"paths": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
]
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
|
-
"hash": "
|
|
24
|
+
"hash": "74bd7994",
|
|
25
25
|
"kind": "module",
|
|
26
26
|
"path": "../src/default-scripts.ts"
|
|
27
27
|
},
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
],
|
|
39
39
|
"name": "default",
|
|
40
40
|
"path": "kits/default.js",
|
|
41
|
-
"readyupVersion": "0.
|
|
41
|
+
"readyupVersion": "0.30.0",
|
|
42
42
|
"source": "kits/default.ts",
|
|
43
|
-
"sourceHash": "
|
|
44
|
-
"targetHash": "
|
|
43
|
+
"sourceHash": "904ac753",
|
|
44
|
+
"targetHash": "2b35e5fd"
|
|
45
45
|
}
|
|
46
46
|
]
|
|
47
47
|
}
|
package/README.md
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
Context-aware script runner for pnpm monorepos. Ships an `nmr` (node-monorepo run) binary that provides centralized, consistent script execution across workspace packages and the monorepo root.
|
|
4
4
|
|
|
5
5
|
<!-- section:release-notes -->
|
|
6
|
-
## Release notes — v0.
|
|
6
|
+
## Release notes — v0.33.0 (2026-08-20)
|
|
7
7
|
|
|
8
|
-
###
|
|
8
|
+
### 🎉 Features
|
|
9
9
|
|
|
10
|
-
-
|
|
10
|
+
- Drop the coverage step from the `check:strict` gate (#727)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Drops the coverage step from `check:strict` in both the workspace and root registries: The gate now runs `test` rather than `test:coverage`.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Coverage is still available as `nmr test:coverage`, run as a separate step.
|
|
15
15
|
<!-- /section:release-notes -->
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
@@ -135,7 +135,7 @@ A string value is spawned through a shell as one command, so an `nmr` invocation
|
|
|
135
135
|
|
|
136
136
|
The line names the declaration it is an edit to — the file, the field, and the key — and its remedy follows from that site. A `.config/nmr.config.ts` entry keeps its nmr steps as a step list and moves anything else to a `<command>:pre` or `<command>:post` script: a step-list element is composed into `nmr <element>`, so it can name only an nmr command. A `package.json` entry has to go, since `package.json` holds no step list: delete it outright when it restates what nmr already runs for that command, and move the steps it adds to a `<command>:pre` or `<command>:post` script when they are the package's own. Where the registry defines no such command, both apply: name the command in `.config/nmr.config.ts`, and put the package-specific steps in a hook. The pair is named rather than `:post` alone because an entry's extra steps may run on either side of the chain: `rdy verify && nmr compile` puts them first. A hook is the exception at both tiers: nmr wraps a `:pre` or `:post` script in no hooks of its own, so a hook's other steps become a script of their own that the step list names.
|
|
137
137
|
|
|
138
|
-
nmr recognizes `nmr` in command position: at the start of a step, after an unquoted `&&`, `||`, `;`, `|`, or a newline, and behind `npx`, `bunx`, or an `exec`, `dlx`, or `x` subcommand of `npm`, `pnpm`, `yarn`, or `bun`. This line reports a boundary rather than enforcing a rule — it covers a step nmr runs as written, and only the reporting of the nested run is degraded — and it stays partial in stated ways: a value-taking flag standing immediately before the program name hides it (`npx -p foo nmr`), a launcher outside that set goes unreported, and a `devBin` substitution that introduces `nmr` itself is not reported, the line being an edit to a declaration rather than to a substitution.
|
|
138
|
+
nmr recognizes `nmr` in command position: at the start of a step, after an unquoted `&&`, `||`, `;`, `|`, or a newline, past any leading `NAME=value` assignments, and behind `npx`, `bunx`, or an `exec`, `dlx`, or `x` subcommand of `npm`, `pnpm`, `yarn`, or `bun`. This line reports a boundary rather than enforcing a rule — it covers a step nmr runs as written, and only the reporting of the nested run is degraded — and it stays partial in stated ways: a value-taking flag standing immediately before the program name hides it (`npx -p foo nmr`), a launcher outside that set goes unreported, and a `devBin` substitution that introduces `nmr` itself is not reported, the line being an edit to a declaration rather than to a substitution.
|
|
139
139
|
|
|
140
140
|
A [self-referential `package.json` entry](#three-tier-override-system) is the shape nmr cannot run as written, and it is rejected rather than reported. The same recognition finds it, so the same residuals apply — what goes unrecognized there re-enters nmr without bound, which hangs rather than passing quietly.
|
|
141
141
|
|
|
@@ -307,7 +307,7 @@ A check that passed on a working tree passes again on the same working tree. nmr
|
|
|
307
307
|
|
|
308
308
|
```console
|
|
309
309
|
$ nmr ci
|
|
310
|
-
# ... four minutes of build, typecheck, lint, and
|
|
310
|
+
# ... four minutes of build, typecheck, lint, and tests ...
|
|
311
311
|
|
|
312
312
|
$ nmr ci
|
|
313
313
|
⏭️ node-monorepo-tools: ci: passed 2m ago on this tree, saved ~4m
|
|
@@ -402,7 +402,7 @@ $ nmr check
|
|
|
402
402
|
⏭️ nmr-core: check: passed 3m ago on this tree, saved ~48s — replayed: nmr-core: fmt:check: All matched files use Prettier code style!; nmr-core: test: Test Files 6 passed (6) Tests 41 passed (41)
|
|
403
403
|
```
|
|
404
404
|
|
|
405
|
-
The assembly is flat: a constituent that is itself a composite contributes its own leaves' lines, so a skipped `ci` replays a package's `test
|
|
405
|
+
The assembly is flat: a constituent that is itself a composite contributes its own leaves' lines, so a skipped `ci` replays a package's `test` rather than one opaque `check:strict` line. A delegate expands into the scopes it fans out to, and a constituent that recorded no excerpt is absent rather than inferred: `typecheck` and `lint:check` print nothing on success and contribute nothing above, and a command outside the [cacheable set](#what-is-cached) records nothing at all, so `ci` replays what `check:strict` earned and nothing for `build`.
|
|
406
406
|
|
|
407
407
|
It is assembled when the composite records its pass rather than when it skips, so every excerpt in it was certified during that one run, on that one tree. `NMR_RUN_ID` is what makes that provable; see [reserved environment variables](#reserved-environment-variables).
|
|
408
408
|
|
|
@@ -534,8 +534,8 @@ A `pnpm.overrides` block left in the root `package.json` fails the command inste
|
|
|
534
534
|
The upgrade tool ([taze](https://github.com/antfu-collective/taze)) arrives with nmr, so your repo declares no dependency on it. Everything after the command name is passed through, including the range mode:
|
|
535
535
|
|
|
536
536
|
```bash
|
|
537
|
-
nmr upgrade # upgrades
|
|
538
|
-
nmr upgrade major # major upgrades,
|
|
537
|
+
nmr upgrade # minor and patch upgrades, regardless of the range each dependency declares
|
|
538
|
+
nmr upgrade major # major upgrades, for dependencies carrying no per-package ceiling
|
|
539
539
|
nmr upgrade --write # apply the proposals to package.json
|
|
540
540
|
```
|
|
541
541
|
|
|
@@ -554,11 +554,16 @@ export default defineConfig({
|
|
|
554
554
|
});
|
|
555
555
|
```
|
|
556
556
|
|
|
557
|
-
`defineConfig` supplies nmr's shared upgrade policy —
|
|
557
|
+
`defineConfig` supplies nmr's shared upgrade policy — a seven-day quarantine on brand-new releases, and the pair of settings that report a dependency pinned to an exact version: locked dependencies are included, and the range searched is `minor` — so your config carries only what is specific to your repo. Any setting you declare wins over nmr's default. Passing `undefined` clears a default rather than falling back to it, which is how you hand the quarantine policy back to `pnpm-workspace.yaml`'s `minimumReleaseAge`. `mode` is the exception: the upgrade tool carries a default of its own for it, and clearing nmr's leaves no valid range to search, so name a mode instead.
|
|
558
558
|
|
|
559
559
|
Everything the [taze configuration](https://github.com/antfu-collective/taze#config-file) accepts is accepted here.
|
|
560
560
|
|
|
561
|
-
> **Note:**
|
|
561
|
+
> **Note:** This file is what activates nmr's upgrade policy at all. A repo without one gets neither the release quarantine nor the settings that report a dependency pinned to an exact version, and `nmr upgrade` reports nothing in a repo using pnpm's `savePrefix: ''`. nmr's ReadyUp kit warns when the file is missing.
|
|
562
|
+
|
|
563
|
+
Two consequences of the `minor` range mode the policy declares:
|
|
564
|
+
|
|
565
|
+
- A `packageMode` entry is honored only by the pass whose mode matches it, or by a `default` pass; every other pass drops that dependency rather than narrowing it. Under the policy's `minor` mode, a `patch` ceiling hides its dependency until you run `nmr upgrade patch`, and a `minor` ceiling hides it from `nmr upgrade major`.
|
|
566
|
+
- A `~` range is searched as `^`, so minor upgrades are proposed for it and `--write` applies them under the original `~`. To hold one dependency to patches, give it a `packageMode` entry of `patch` and read it from `nmr upgrade patch`; to hold the whole repo there, declare `mode: 'patch'`.
|
|
562
567
|
|
|
563
568
|
## Default script registries
|
|
564
569
|
|
|
@@ -570,7 +575,7 @@ These scripts are available out of the box. Repo-wide config (tier 2) and per-pa
|
|
|
570
575
|
| ---------------- | ----------------------------------------------------------- |
|
|
571
576
|
| `build` | `compile` |
|
|
572
577
|
| `check` | `typecheck`, `fmt:check`, `lint:check`, `test` |
|
|
573
|
-
| `check:strict` | `typecheck`, `fmt:check`, `lint:strict`, `test
|
|
578
|
+
| `check:strict` | `typecheck`, `fmt:check`, `lint:strict`, `test` |
|
|
574
579
|
| `clean` | `nmr-clean` |
|
|
575
580
|
| `compile` | `nmr-compile` |
|
|
576
581
|
| `fix` | `lint`, `fmt` |
|
|
@@ -588,7 +593,7 @@ These scripts are available out of the box. Repo-wide config (tier 2) and per-pa
|
|
|
588
593
|
| `test:unit` | `pnpm exec vitest --project unit` |
|
|
589
594
|
| `test:watch` | `pnpm exec vitest --project unit --project tool --watch` |
|
|
590
595
|
| `typecheck` | `tsgo --noEmit` |
|
|
591
|
-
| `upgrade` | `nmr-report-catalog && nmr-taze
|
|
596
|
+
| `upgrade` | `nmr-report-catalog && nmr-taze` |
|
|
592
597
|
| `view-coverage` | `open coverage/index.html` |
|
|
593
598
|
|
|
594
599
|
`fmt` and `fmt:check` select their files through git rather than by walking the directory, which is what makes a package-level run and a root-level run apply the same ignore rules — see [file selection](#file-selection).
|
|
@@ -631,10 +636,12 @@ Neither is bound to a git hook. `prepush` is named for when you run it, not for
|
|
|
631
636
|
|
|
632
637
|
#### Check and quality
|
|
633
638
|
|
|
634
|
-
| Command | Runs
|
|
635
|
-
| -------------- |
|
|
636
|
-
| `check` | `typecheck`, `fmt:check`, `lint:check`, `test`
|
|
637
|
-
| `check:strict` | `typecheck`, `fmt:check`, `lint:strict`, `test
|
|
639
|
+
| Command | Runs |
|
|
640
|
+
| -------------- | ----------------------------------------------- |
|
|
641
|
+
| `check` | `typecheck`, `fmt:check`, `lint:check`, `test` |
|
|
642
|
+
| `check:strict` | `typecheck`, `fmt:check`, `lint:strict`, `test` |
|
|
643
|
+
|
|
644
|
+
Neither gate computes coverage: Instrumentation multiplies the wall time of the run they exist to keep short. Coverage is [`test:coverage`](#test-selections), run as a step of its own; a repo that wants it inside the gate [overrides](#configuration) `check:strict`.
|
|
638
645
|
|
|
639
646
|
#### Fix
|
|
640
647
|
|
|
@@ -702,9 +709,9 @@ A file git ignores is never formatted, even when named directly. Trailing argume
|
|
|
702
709
|
|
|
703
710
|
#### Dependencies
|
|
704
711
|
|
|
705
|
-
| Command | Runs
|
|
706
|
-
| --------- |
|
|
707
|
-
| `upgrade` | `nmr-report-overrides && nmr-taze --
|
|
712
|
+
| Command | Runs |
|
|
713
|
+
| --------- | ---------------------------------------------- |
|
|
714
|
+
| `upgrade` | `nmr-report-overrides && nmr-taze --recursive` |
|
|
708
715
|
|
|
709
716
|
See [dependency upgrades](#dependency-upgrades) for the workflow and its configuration.
|
|
710
717
|
|
|
@@ -723,7 +730,7 @@ These scripts operate on root-level code only (not workspace packages):
|
|
|
723
730
|
| `root:test:tool` | `vitest --config ./vitest.root.config.ts --project tool` |
|
|
724
731
|
| `root:test:unit` | `vitest --config ./vitest.root.config.ts --project unit` |
|
|
725
732
|
| `root:typecheck` | `tsgo --noEmit` |
|
|
726
|
-
| `root:upgrade` | `nmr-report-overrides && nmr-taze
|
|
733
|
+
| `root:upgrade` | `nmr-report-overrides && nmr-taze` |
|
|
727
734
|
|
|
728
735
|
#### Utilities
|
|
729
736
|
|
|
@@ -875,7 +882,7 @@ Run the [taze](https://github.com/antfu-collective/taze) dependency-upgrade tool
|
|
|
875
882
|
Under pnpm's isolated `node_modules`, a transitive package's binary is absent from the consuming repo's `node_modules/.bin`, so a repo that depends on nmr cannot run `taze` directly. `nmr-taze` can, because nmr is a direct dependency, and it resolves the tool from the tree nmr controls.
|
|
876
883
|
|
|
877
884
|
```bash
|
|
878
|
-
nmr-taze --
|
|
885
|
+
nmr-taze --recursive
|
|
879
886
|
```
|
|
880
887
|
|
|
881
888
|
### `ensure-prepublish-hooks`
|
|
@@ -4,7 +4,7 @@ const ROOT_TYPECHECK_STEP = { run: 'root:typecheck', declinesArgs: true };
|
|
|
4
4
|
export const workspaceScripts = {
|
|
5
5
|
build: ['compile'],
|
|
6
6
|
check: [TYPECHECK_STEP, 'fmt:check', 'lint:check', 'test'],
|
|
7
|
-
'check:strict': [TYPECHECK_STEP, 'fmt:check', 'lint:strict', 'test
|
|
7
|
+
'check:strict': [TYPECHECK_STEP, 'fmt:check', 'lint:strict', 'test'],
|
|
8
8
|
clean: 'nmr-clean',
|
|
9
9
|
compile: 'nmr-compile',
|
|
10
10
|
fix: ['lint', 'fmt'],
|
|
@@ -22,7 +22,7 @@ export const workspaceScripts = {
|
|
|
22
22
|
'test:unit': 'pnpm exec vitest --project unit',
|
|
23
23
|
'test:watch': `pnpm exec vitest ${GATE_PROJECTS} --watch`,
|
|
24
24
|
typecheck: 'tsgo --noEmit',
|
|
25
|
-
upgrade: 'nmr-report-catalog && nmr-taze
|
|
25
|
+
upgrade: 'nmr-report-catalog && nmr-taze',
|
|
26
26
|
'view-coverage': 'open coverage/index.html',
|
|
27
27
|
};
|
|
28
28
|
export const rootScripts = {
|
|
@@ -31,7 +31,7 @@ export const rootScripts = {
|
|
|
31
31
|
'audit:prod': 'pnpm exec v11y --prod',
|
|
32
32
|
build: ['-R build'],
|
|
33
33
|
check: [TYPECHECK_STEP, 'fmt:check', 'lint:check', 'test'],
|
|
34
|
-
'check:strict': [TYPECHECK_STEP, 'fmt:check', 'lint:strict', 'test
|
|
34
|
+
'check:strict': [TYPECHECK_STEP, 'fmt:check', 'lint:strict', 'test'],
|
|
35
35
|
ci: [{ run: 'build', declinesArgs: true }, 'check:strict'],
|
|
36
36
|
clean: 'nmr-clean',
|
|
37
37
|
fix: ['lint', 'fmt'],
|
|
@@ -52,7 +52,7 @@ export const rootScripts = {
|
|
|
52
52
|
'root:test:tool': 'vitest --config ./vitest.root.config.ts --project tool',
|
|
53
53
|
'root:test:unit': 'vitest --config ./vitest.root.config.ts --project unit',
|
|
54
54
|
'root:typecheck': 'tsgo --noEmit',
|
|
55
|
-
'root:upgrade': 'nmr-report-overrides && nmr-taze
|
|
55
|
+
'root:upgrade': 'nmr-report-overrides && nmr-taze',
|
|
56
56
|
test: ['root:test', '-R test'],
|
|
57
57
|
'test:all': ['root:test:all', '-R test:all'],
|
|
58
58
|
'test:coverage': ['root:test', '-R test:coverage'],
|
|
@@ -60,5 +60,5 @@ export const rootScripts = {
|
|
|
60
60
|
'test:unit': ['root:test:unit', '-R test:unit'],
|
|
61
61
|
'test:watch': `vitest ${GATE_PROJECTS} --watch`,
|
|
62
62
|
typecheck: [ROOT_TYPECHECK_STEP, { run: '-R typecheck', declinesArgs: true }],
|
|
63
|
-
upgrade: 'nmr-report-overrides && nmr-taze --
|
|
63
|
+
upgrade: 'nmr-report-overrides && nmr-taze --recursive',
|
|
64
64
|
};
|
package/dist/esm/steps.js
CHANGED
|
@@ -10,6 +10,7 @@ const LAUNCHERS = new Map([
|
|
|
10
10
|
const QUOTES = new Set(['"', "'"]);
|
|
11
11
|
const SEGMENT_SEPARATORS = new Set([';', '|', '&', '\n', '\r']);
|
|
12
12
|
const SHELL_SAFE_TOKEN = /^[\w@%+=:,./-]+$/;
|
|
13
|
+
const TOKEN_SEPARATORS = new Set([' ', '\t', '\n', '\r']);
|
|
13
14
|
export function composeNmrStep(element, workspaceRoot, declinesArgs = false) {
|
|
14
15
|
const flags = workspaceRoot ? ['-w'] : [];
|
|
15
16
|
return { kind: 'structural', argv: ['nmr', ...flags, ...tokenize(element)], ...(declinesArgs && { declinesArgs }) };
|
|
@@ -65,7 +66,7 @@ function quoteToken(token) {
|
|
|
65
66
|
return "'" + token.replaceAll("'", String.raw `'\''`) + "'";
|
|
66
67
|
}
|
|
67
68
|
function readNmrTail(segment) {
|
|
68
|
-
const [head, ...rest] = dropLeadingAssignments(
|
|
69
|
+
const [head, ...rest] = dropLeadingAssignments(tokenizeSegment(segment));
|
|
69
70
|
if (head === undefined) {
|
|
70
71
|
return undefined;
|
|
71
72
|
}
|
|
@@ -167,3 +168,49 @@ function splitSegments(command) {
|
|
|
167
168
|
function tokenize(element) {
|
|
168
169
|
return element.split(/\s+/).filter((token) => token.length > 0);
|
|
169
170
|
}
|
|
171
|
+
function tokenizeSegment(segment) {
|
|
172
|
+
const tokens = [];
|
|
173
|
+
let current = '';
|
|
174
|
+
let quote;
|
|
175
|
+
let index = 0;
|
|
176
|
+
while (index < segment.length) {
|
|
177
|
+
const char = segment[index] ?? '';
|
|
178
|
+
if (quote !== undefined) {
|
|
179
|
+
if (char === '\\' && quote === '"') {
|
|
180
|
+
current += char + (segment[index + 1] ?? '');
|
|
181
|
+
index += 2;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
current += char;
|
|
185
|
+
if (char === quote)
|
|
186
|
+
quote = undefined;
|
|
187
|
+
index += 1;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (char === '\\') {
|
|
191
|
+
current += char + (segment[index + 1] ?? '');
|
|
192
|
+
index += 2;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (QUOTES.has(char)) {
|
|
196
|
+
quote = char;
|
|
197
|
+
current += char;
|
|
198
|
+
index += 1;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (TOKEN_SEPARATORS.has(char)) {
|
|
202
|
+
if (current !== '') {
|
|
203
|
+
tokens.push(current);
|
|
204
|
+
}
|
|
205
|
+
current = '';
|
|
206
|
+
index += 1;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
current += char;
|
|
210
|
+
index += 1;
|
|
211
|
+
}
|
|
212
|
+
if (current !== '') {
|
|
213
|
+
tokens.push(current);
|
|
214
|
+
}
|
|
215
|
+
return tokens;
|
|
216
|
+
}
|
package/dist/esm/taze.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@williamthorsen/nmr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Context-aware script runner for pnpm monorepos",
|
|
6
6
|
"keywords": [
|
|
@@ -73,13 +73,14 @@
|
|
|
73
73
|
"prettier-plugin-sh": "0.19.0",
|
|
74
74
|
"taze": "20.0.1",
|
|
75
75
|
"yaml": "2.9.0",
|
|
76
|
-
"@williamthorsen/nmr-core": "0.10.
|
|
76
|
+
"@williamthorsen/nmr-core": "0.10.2"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
+
"@williamthorsen/toolbelt.filesystem": "0.6.0",
|
|
79
80
|
"@williamthorsen/toolbelt.testing": "0.3.0",
|
|
80
81
|
"@williamthorsen/toolbelt.vitest": "0.4.0",
|
|
81
82
|
"prettier": "3.9.6",
|
|
82
|
-
"readyup": "0.
|
|
83
|
+
"readyup": "0.30.0",
|
|
83
84
|
"tinyglobby": "0.2.17",
|
|
84
85
|
"typescript": "6.0.3",
|
|
85
86
|
"vitest": "4.1.10"
|