@williamthorsen/nmr 0.16.0 → 0.17.1

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 (41) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +41 -44
  3. package/dist/esm/cli-build.js +5 -5
  4. package/dist/esm/cli-ensure-prepublish-hooks.js +33 -34
  5. package/dist/esm/cli-report-overrides.js +7 -6
  6. package/dist/esm/cli-sync-agent-files.js +20 -22
  7. package/dist/esm/cli-sync-pnpm-version.js +7 -6
  8. package/dist/esm/cli.js +13 -13
  9. package/dist/esm/commands/build.d.ts +3 -9
  10. package/dist/esm/commands/build.js +288 -120
  11. package/dist/esm/commands/ensure-prepublish-hooks.js +66 -69
  12. package/dist/esm/commands/report-overrides.js +10 -13
  13. package/dist/esm/commands/sync-agent-files.js +46 -52
  14. package/dist/esm/commands/sync-pnpm-version.js +35 -42
  15. package/dist/esm/config.js +59 -57
  16. package/dist/esm/context.d.ts +1 -1
  17. package/dist/esm/context.js +70 -72
  18. package/dist/esm/default-scripts.js +63 -68
  19. package/dist/esm/help.d.ts +1 -1
  20. package/dist/esm/help.js +65 -67
  21. package/dist/esm/helpers/code-quality-pnpm-action.js +20 -24
  22. package/dist/esm/helpers/hook-name.js +2 -5
  23. package/dist/esm/helpers/package-json.js +46 -41
  24. package/dist/esm/helpers/type-guards.js +2 -5
  25. package/dist/esm/index.d.ts +3 -3
  26. package/dist/esm/index.js +1 -4
  27. package/dist/esm/resolve-scripts.d.ts +2 -2
  28. package/dist/esm/resolve-scripts.js +7 -11
  29. package/dist/esm/resolver.d.ts +2 -2
  30. package/dist/esm/resolver.js +84 -86
  31. package/dist/esm/runCli.js +136 -144
  32. package/dist/esm/runner.js +35 -34
  33. package/dist/esm/scripts.d.ts +2 -2
  34. package/dist/esm/scripts.js +1 -5
  35. package/dist/esm/tests/consistency.d.ts +1 -1
  36. package/dist/esm/tests/consistency.js +45 -54
  37. package/dist/esm/tests/helpers/get-runtime-version-from-asdf.js +11 -14
  38. package/dist/esm/tests/helpers/get-string-from-yaml-file.js +10 -13
  39. package/dist/esm/tests/helpers/get-value-at-path.js +30 -30
  40. package/package.json +5 -3
  41. package/dist/esm/.cache +0 -1
@@ -1,167 +1,159 @@
1
- import path from "node:path";
2
- import { readPackageVersion, reportError } from "@williamthorsen/nmr-core";
1
+ import path from 'node:path';
2
+ import { readPackageVersion, reportError } from '@williamthorsen/nmr-core';
3
3
  import { resolveContext } from "./context.js";
4
4
  import { generateHelp } from "./help.js";
5
5
  import { isHookName } from "./helpers/hook-name.js";
6
- import {
7
- applyDevBin,
8
- buildRootRegistry,
9
- buildWorkspaceRegistry,
10
- hasIntegrationTestConfig,
11
- resolveScript
12
- } from "./resolver.js";
6
+ import { applyDevBin, buildRootRegistry, buildWorkspaceRegistry, hasIntegrationTestConfig, resolveScript, } from "./resolver.js";
13
7
  import { runCommand } from "./runner.js";
14
8
  const VERSION = readPackageVersion(import.meta.url);
15
- async function runCli(options) {
16
- const { args, cwd, env, stdout, stderr } = options;
17
- const parseResult = parseArgs(args);
18
- if (!parseResult.ok) {
19
- reportError(parseResult.error, stderr);
20
- return { exitCode: 1 };
21
- }
22
- const { parsed } = parseResult;
23
- if (parsed.version) {
24
- stdout.write(`${VERSION}
25
- `);
26
- return { exitCode: 0 };
27
- }
28
- const context = await resolveContext(cwd);
29
- const useRoot = parsed.workspaceRoot || context.isRoot;
30
- const packageDir = useRoot ? context.monorepoRoot : context.packageDir ?? context.monorepoRoot;
31
- if (parsed.help || !parsed.command) {
32
- stdout.write(`${generateHelp(context.config, packageDir, useRoot)}
33
- `);
34
- return { exitCode: 0 };
35
- }
36
- const { command } = parsed;
37
- const passthrough = parsed.passthrough.length > 0 ? " " + parsed.passthrough.map(shellQuote).join(" ") : "";
38
- const runOptions = { quiet: parsed.quiet, stdout, stderr, env };
39
- if (parsed.filter) {
40
- const delegateCmd = `pnpm --filter ${shellQuote(parsed.filter)} exec nmr ${command}${passthrough}`;
41
- const exitCode2 = runCommand(delegateCmd, context.monorepoRoot, runOptions);
42
- return { exitCode: exitCode2 };
43
- }
44
- if (parsed.recursive) {
45
- const childEnv = { ...env, NMR_RUN_IF_PRESENT: "1" };
46
- const delegateCmd = `pnpm --recursive exec nmr ${command}${passthrough}`;
47
- const exitCode2 = runCommand(delegateCmd, context.monorepoRoot, { ...runOptions, env: childEnv });
48
- return { exitCode: exitCode2 };
49
- }
50
- const registry = useRoot ? buildRootRegistry(context.config) : buildWorkspaceRegistry(context.config, hasIntegrationTestConfig(packageDir));
51
- const resolved = resolveScript(command, registry, packageDir, parsed.workspaceRoot);
52
- if (!resolved) {
53
- if (env.NMR_RUN_IF_PRESENT === "1") {
54
- return { exitCode: 0 };
9
+ export async function runCli(options) {
10
+ const { args, cwd, env, stdout, stderr } = options;
11
+ const parseResult = parseArgs(args);
12
+ if (!parseResult.ok) {
13
+ reportError(parseResult.error, stderr);
14
+ return { exitCode: 1 };
55
15
  }
56
- reportError(`Unknown command: ${command}`, stderr);
57
- return { exitCode: 1 };
58
- }
59
- const skipExitCode = handleSkipMessage(resolved.command, packageDir, parsed.quiet, stdout);
60
- if (skipExitCode !== void 0) {
61
- return { exitCode: skipExitCode };
62
- }
63
- if (resolved.source === "package" && !parsed.quiet && registry[command] !== void 0) {
64
- stdout.write(`\u{1F4E6} ${path.basename(packageDir)}: Using override script: ${resolved.command}
65
- `);
66
- }
67
- const substitutedCommand = applyDevBin(resolved.command, context.config.devBin, context.monorepoRoot);
68
- const mainCommand = substitutedCommand + passthrough;
69
- const isHookInvocation = isHookName(command);
70
- const fullCommand = isHookInvocation ? mainCommand : wrapWithHooks(command, mainCommand, registry, packageDir, parsed.workspaceRoot);
71
- const exitCode = runCommand(fullCommand, cwd, runOptions);
72
- return { exitCode };
73
- }
74
- function parseArgs(args) {
75
- const parsed = {
76
- quiet: false,
77
- recursive: false,
78
- workspaceRoot: false,
79
- help: false,
80
- version: false,
81
- passthrough: []
82
- };
83
- let i = 0;
84
- while (i < args.length) {
85
- const arg = args[i];
86
- if (arg === void 0) break;
87
- if (arg === "-F" || arg === "--filter") {
88
- i++;
89
- const filterValue = args[i];
90
- if (filterValue === void 0) {
91
- return { ok: false, error: "-F/--filter requires a pattern argument" };
92
- }
93
- parsed.filter = filterValue;
94
- i++;
95
- continue;
16
+ const { parsed } = parseResult;
17
+ if (parsed.version) {
18
+ stdout.write(`${VERSION}\n`);
19
+ return { exitCode: 0 };
20
+ }
21
+ const context = await resolveContext(cwd);
22
+ const useRoot = parsed.workspaceRoot || context.isRoot;
23
+ const packageDir = useRoot ? context.monorepoRoot : (context.packageDir ?? context.monorepoRoot);
24
+ if (parsed.help || !parsed.command) {
25
+ stdout.write(`${generateHelp(context.config, packageDir, useRoot)}\n`);
26
+ return { exitCode: 0 };
27
+ }
28
+ const { command } = parsed;
29
+ const passthrough = parsed.passthrough.length > 0 ? ' ' + parsed.passthrough.map(shellQuote).join(' ') : '';
30
+ const runOptions = { quiet: parsed.quiet, stdout, stderr, env };
31
+ if (parsed.filter) {
32
+ const delegateCmd = `pnpm --filter ${shellQuote(parsed.filter)} exec nmr ${command}${passthrough}`;
33
+ const exitCode = runCommand(delegateCmd, context.monorepoRoot, runOptions);
34
+ return { exitCode };
96
35
  }
97
- if (arg === "-R" || arg === "--recursive") {
98
- parsed.recursive = true;
99
- i++;
100
- continue;
36
+ if (parsed.recursive) {
37
+ const childEnv = { ...env, NMR_RUN_IF_PRESENT: '1' };
38
+ const delegateCmd = `pnpm --recursive exec nmr ${command}${passthrough}`;
39
+ const exitCode = runCommand(delegateCmd, context.monorepoRoot, { ...runOptions, env: childEnv });
40
+ return { exitCode };
101
41
  }
102
- if (arg === "-w" || arg === "--workspace-root") {
103
- parsed.workspaceRoot = true;
104
- i++;
105
- continue;
42
+ const registry = useRoot
43
+ ? buildRootRegistry(context.config)
44
+ : buildWorkspaceRegistry(context.config, hasIntegrationTestConfig(packageDir));
45
+ const resolved = resolveScript(command, registry, packageDir, parsed.workspaceRoot);
46
+ if (!resolved) {
47
+ if (env.NMR_RUN_IF_PRESENT === '1') {
48
+ return { exitCode: 0 };
49
+ }
50
+ reportError(`Unknown command: ${command}`, stderr);
51
+ return { exitCode: 1 };
106
52
  }
107
- if (arg === "-?" || arg === "--help") {
108
- parsed.help = true;
109
- i++;
110
- continue;
53
+ const skipExitCode = handleSkipMessage(resolved.command, packageDir, parsed.quiet, stdout);
54
+ if (skipExitCode !== undefined) {
55
+ return { exitCode: skipExitCode };
111
56
  }
112
- if (arg === "-V" || arg === "--version") {
113
- parsed.version = true;
114
- i++;
115
- continue;
57
+ if (resolved.source === 'package' && !parsed.quiet && registry[command] !== undefined) {
58
+ stdout.write(`📦 ${path.basename(packageDir)}: Using override script: ${resolved.command}\n`);
116
59
  }
117
- if (arg === "-q" || arg === "--quiet") {
118
- parsed.quiet = true;
119
- i++;
120
- continue;
60
+ const substitutedCommand = applyDevBin(resolved.command, context.config.devBin, context.monorepoRoot);
61
+ const mainCommand = substitutedCommand + passthrough;
62
+ const isHookInvocation = isHookName(command);
63
+ const fullCommand = isHookInvocation
64
+ ? mainCommand
65
+ : wrapWithHooks(command, mainCommand, registry, packageDir, parsed.workspaceRoot);
66
+ const exitCode = runCommand(fullCommand, cwd, runOptions);
67
+ return { exitCode };
68
+ }
69
+ function parseArgs(args) {
70
+ const parsed = {
71
+ quiet: false,
72
+ recursive: false,
73
+ workspaceRoot: false,
74
+ help: false,
75
+ version: false,
76
+ passthrough: [],
77
+ };
78
+ let i = 0;
79
+ while (i < args.length) {
80
+ const arg = args[i];
81
+ if (arg === undefined)
82
+ break;
83
+ if (arg === '-F' || arg === '--filter') {
84
+ i++;
85
+ const filterValue = args[i];
86
+ if (filterValue === undefined) {
87
+ return { ok: false, error: '-F/--filter requires a pattern argument' };
88
+ }
89
+ parsed.filter = filterValue;
90
+ i++;
91
+ continue;
92
+ }
93
+ if (arg === '-R' || arg === '--recursive') {
94
+ parsed.recursive = true;
95
+ i++;
96
+ continue;
97
+ }
98
+ if (arg === '-w' || arg === '--workspace-root') {
99
+ parsed.workspaceRoot = true;
100
+ i++;
101
+ continue;
102
+ }
103
+ if (arg === '-?' || arg === '--help') {
104
+ parsed.help = true;
105
+ i++;
106
+ continue;
107
+ }
108
+ if (arg === '-V' || arg === '--version') {
109
+ parsed.version = true;
110
+ i++;
111
+ continue;
112
+ }
113
+ if (arg === '-q' || arg === '--quiet') {
114
+ parsed.quiet = true;
115
+ i++;
116
+ continue;
117
+ }
118
+ parsed.command = arg;
119
+ parsed.passthrough = args.slice(i + 1);
120
+ break;
121
121
  }
122
- parsed.command = arg;
123
- parsed.passthrough = args.slice(i + 1);
124
- break;
125
- }
126
- return { ok: true, parsed };
122
+ return { ok: true, parsed };
127
123
  }
128
124
  function handleSkipMessage(resolvedCommand, packageDir, quiet, stdout) {
129
- if (resolvedCommand === "") {
130
- if (!quiet) {
131
- stdout.write(`\u26D4 ${path.basename(packageDir)}: Override script is defined but empty. Skipping.
132
- `);
125
+ if (resolvedCommand === '') {
126
+ if (!quiet) {
127
+ stdout.write(`⛔ ${path.basename(packageDir)}: Override script is defined but empty. Skipping.\n`);
128
+ }
129
+ return 0;
133
130
  }
134
- return 0;
135
- }
136
- if (resolvedCommand === ":") {
137
- if (!quiet) {
138
- stdout.write(`\u26D4 ${path.basename(packageDir)}: Override script is a no-op. Skipping.
139
- `);
131
+ if (resolvedCommand === ':') {
132
+ if (!quiet) {
133
+ stdout.write(`⛔ ${path.basename(packageDir)}: Override script is a no-op. Skipping.\n`);
134
+ }
135
+ return 0;
140
136
  }
141
- return 0;
142
- }
143
- return void 0;
137
+ return undefined;
144
138
  }
145
139
  function wrapWithHooks(command, mainCommand, registry, packageDir, workspaceRoot) {
146
- const segments = [];
147
- const flag = workspaceRoot ? "-w " : "";
148
- if (hasRunnableHook(`${command}:pre`, registry, packageDir, workspaceRoot)) {
149
- segments.push(`nmr ${flag}${command}:pre`);
150
- }
151
- segments.push(mainCommand);
152
- if (hasRunnableHook(`${command}:post`, registry, packageDir, workspaceRoot)) {
153
- segments.push(`nmr ${flag}${command}:post`);
154
- }
155
- return segments.join(" && ");
140
+ const segments = [];
141
+ const flag = workspaceRoot ? '-w ' : '';
142
+ if (hasRunnableHook(`${command}:pre`, registry, packageDir, workspaceRoot)) {
143
+ segments.push(`nmr ${flag}${command}:pre`);
144
+ }
145
+ segments.push(mainCommand);
146
+ if (hasRunnableHook(`${command}:post`, registry, packageDir, workspaceRoot)) {
147
+ segments.push(`nmr ${flag}${command}:post`);
148
+ }
149
+ return segments.join(' && ');
156
150
  }
157
151
  function hasRunnableHook(hookName, registry, packageDir, workspaceRoot) {
158
- const resolved = resolveScript(hookName, registry, packageDir, workspaceRoot);
159
- if (!resolved) return false;
160
- return resolved.command !== "" && resolved.command !== ":";
152
+ const resolved = resolveScript(hookName, registry, packageDir, workspaceRoot);
153
+ if (!resolved)
154
+ return false;
155
+ return resolved.command !== '' && resolved.command !== ':';
161
156
  }
162
157
  function shellQuote(arg) {
163
- return "'" + arg.replace(/'/g, String.raw`'\''`) + "'";
158
+ return "'" + arg.replace(/'/g, String.raw `'\''`) + "'";
164
159
  }
165
- export {
166
- runCli
167
- };
@@ -1,40 +1,41 @@
1
- import { spawnSync } from "node:child_process";
2
- import process from "node:process";
3
- import { reportError } from "@williamthorsen/nmr-core";
4
- function runCommand(command, cwd, options) {
5
- const quiet = options?.quiet === true;
6
- const stdout = options?.stdout ?? process.stdout;
7
- const stderr = options?.stderr ?? process.stderr;
8
- const env = options?.env ?? process.env;
9
- const stdoutChannel = quiet ? "pipe" : streamFdOrPipe(stdout);
10
- const stderrChannel = quiet ? "pipe" : streamFdOrPipe(stderr);
11
- const result = spawnSync(command, [], {
12
- shell: true,
13
- stdio: ["inherit", stdoutChannel, stderrChannel],
14
- cwd,
15
- env
16
- });
17
- if (result.error) {
18
- reportError(result.error.message, stderr);
19
- return 1;
20
- }
21
- if (quiet) {
22
- if (result.status !== 0) {
23
- writeBuffer(result.stdout, stderr);
24
- writeBuffer(result.stderr, stderr);
1
+ import { spawnSync } from 'node:child_process';
2
+ import process from 'node:process';
3
+ import { reportError } from '@williamthorsen/nmr-core';
4
+ export function runCommand(command, cwd, options) {
5
+ const quiet = options?.quiet === true;
6
+ const stdout = options?.stdout ?? process.stdout;
7
+ const stderr = options?.stderr ?? process.stderr;
8
+ const env = options?.env ?? process.env;
9
+ const stdoutChannel = quiet ? 'pipe' : streamFdOrPipe(stdout);
10
+ const stderrChannel = quiet ? 'pipe' : streamFdOrPipe(stderr);
11
+ const result = spawnSync(command, [], {
12
+ shell: true,
13
+ stdio: ['inherit', stdoutChannel, stderrChannel],
14
+ cwd,
15
+ env,
16
+ });
17
+ if (result.error) {
18
+ reportError(result.error.message, stderr);
19
+ return 1;
25
20
  }
26
- } else {
27
- if (stdoutChannel === "pipe") writeBuffer(result.stdout, stdout);
28
- if (stderrChannel === "pipe") writeBuffer(result.stderr, stderr);
29
- }
30
- return result.status ?? 1;
21
+ if (quiet) {
22
+ if (result.status !== 0) {
23
+ writeBuffer(result.stdout, stderr);
24
+ writeBuffer(result.stderr, stderr);
25
+ }
26
+ }
27
+ else {
28
+ if (stdoutChannel === 'pipe')
29
+ writeBuffer(result.stdout, stdout);
30
+ if (stderrChannel === 'pipe')
31
+ writeBuffer(result.stderr, stderr);
32
+ }
33
+ return result.status ?? 1;
31
34
  }
32
35
  function streamFdOrPipe(stream) {
33
- return "fd" in stream && typeof stream.fd === "number" ? stream.fd : "pipe";
36
+ return 'fd' in stream && typeof stream.fd === 'number' ? stream.fd : 'pipe';
34
37
  }
35
38
  function writeBuffer(buffer, dest) {
36
- if (buffer.length > 0) dest.write(buffer);
39
+ if (buffer.length > 0)
40
+ dest.write(buffer);
37
41
  }
38
- export {
39
- runCommand
40
- };
@@ -1,2 +1,2 @@
1
- export type { ScriptRegistry, ScriptValue } from './default-scripts.ts';
2
- export { getDefaultRootScripts, getDefaultWorkspaceScripts } from './resolve-scripts.ts';
1
+ export type { ScriptRegistry, ScriptValue } from './default-scripts.js';
2
+ export { getDefaultRootScripts, getDefaultWorkspaceScripts } from './resolve-scripts.js';
@@ -1,5 +1 @@
1
- import { getDefaultRootScripts, getDefaultWorkspaceScripts } from "./resolve-scripts.js";
2
- export {
3
- getDefaultRootScripts,
4
- getDefaultWorkspaceScripts
5
- };
1
+ export { getDefaultRootScripts, getDefaultWorkspaceScripts } from "./resolve-scripts.js";
@@ -1,4 +1,4 @@
1
- export { findMonorepoRoot } from '../context.ts';
1
+ export { findMonorepoRoot } from '../context.js';
2
2
  export declare function checkPnpmVersionConsistency(monorepoRoot: string): void;
3
3
  export declare function checkNodeVersionConsistency(monorepoRoot: string): void;
4
4
  export declare function getPnpmVersionFromAction(monorepoRoot: string): Promise<string>;
@@ -1,66 +1,57 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import { describe, expect, it } from "vitest";
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { describe, expect, it } from 'vitest';
4
4
  import { findMonorepoRoot } from "../context.js";
5
- import { findMonorepoRoot as findMonorepoRoot2 } from "../context.js";
5
+ export { findMonorepoRoot } from "../context.js";
6
6
  import { getRuntimeVersionFromAsdf } from "./helpers/get-runtime-version-from-asdf.js";
7
7
  import { getStringFromYamlFile } from "./helpers/get-string-from-yaml-file.js";
8
8
  import { getValueAtPathOrThrow } from "./helpers/get-value-at-path.js";
9
- const GITHUB_ACTION_FILE_PATH = ".github/workflows/code-quality.yaml";
10
- function checkPnpmVersionConsistency(monorepoRoot) {
11
- describe("pnpm version consistency", () => {
12
- it("pnpm version is the same in GitHub action and package.json", async () => {
13
- const actionVersion = await getPnpmVersionFromAction(monorepoRoot);
14
- const packageJsonVersion = getPnpmVersionFromPackageJson(monorepoRoot);
15
- expect(actionVersion).toBe(packageJsonVersion);
9
+ const GITHUB_ACTION_FILE_PATH = '.github/workflows/code-quality.yaml';
10
+ export function checkPnpmVersionConsistency(monorepoRoot) {
11
+ describe('pnpm version consistency', () => {
12
+ it('pnpm version is the same in GitHub action and package.json', async () => {
13
+ const actionVersion = await getPnpmVersionFromAction(monorepoRoot);
14
+ const packageJsonVersion = getPnpmVersionFromPackageJson(monorepoRoot);
15
+ expect(actionVersion).toBe(packageJsonVersion);
16
+ });
16
17
  });
17
- });
18
18
  }
19
- function checkNodeVersionConsistency(monorepoRoot) {
20
- describe("Node.js version consistency", () => {
21
- it("version is the same in GitHub action and .tool-versions", async () => {
22
- const toolVersion = await getRuntimeVersionFromAsdf("nodejs", monorepoRoot);
23
- const actionVersion = await getNodeVersionFromAction(monorepoRoot);
24
- expect(toolVersion).toBe(actionVersion);
19
+ export function checkNodeVersionConsistency(monorepoRoot) {
20
+ describe('Node.js version consistency', () => {
21
+ it('version is the same in GitHub action and .tool-versions', async () => {
22
+ const toolVersion = await getRuntimeVersionFromAsdf('nodejs', monorepoRoot);
23
+ const actionVersion = await getNodeVersionFromAction(monorepoRoot);
24
+ expect(toolVersion).toBe(actionVersion);
25
+ });
25
26
  });
26
- });
27
27
  }
28
- async function getPnpmVersionFromAction(monorepoRoot) {
29
- const actionPath = path.join(monorepoRoot, GITHUB_ACTION_FILE_PATH);
30
- return getStringFromYamlFile(actionPath, "jobs.code-quality.with.pnpm-version", "pnpm version");
28
+ export async function getPnpmVersionFromAction(monorepoRoot) {
29
+ const actionPath = path.join(monorepoRoot, GITHUB_ACTION_FILE_PATH);
30
+ return getStringFromYamlFile(actionPath, 'jobs.code-quality.with.pnpm-version', 'pnpm version');
31
31
  }
32
- function getPnpmVersionFromPackageJson(monorepoRoot) {
33
- const pkgPath = path.join(monorepoRoot, "package.json");
34
- const raw = fs.readFileSync(pkgPath, "utf8");
35
- const pkg = JSON.parse(raw);
36
- const pm = getValueAtPathOrThrow(pkg, "packageManager");
37
- if (typeof pm !== "string") {
38
- throw new TypeError('"packageManager" field missing or not a string in package.json.');
39
- }
40
- const [name, version] = pm.split("@");
41
- if (name !== "pnpm") {
42
- throw new Error("packageManager is not pnpm.");
43
- }
44
- if (!version) {
45
- throw new Error("pnpm version missing in package.json.");
46
- }
47
- return version;
32
+ export function getPnpmVersionFromPackageJson(monorepoRoot) {
33
+ const pkgPath = path.join(monorepoRoot, 'package.json');
34
+ const raw = fs.readFileSync(pkgPath, 'utf8');
35
+ const pkg = JSON.parse(raw);
36
+ const pm = getValueAtPathOrThrow(pkg, 'packageManager');
37
+ if (typeof pm !== 'string') {
38
+ throw new TypeError('"packageManager" field missing or not a string in package.json.');
39
+ }
40
+ const [name, version] = pm.split('@');
41
+ if (name !== 'pnpm') {
42
+ throw new Error('packageManager is not pnpm.');
43
+ }
44
+ if (!version) {
45
+ throw new Error('pnpm version missing in package.json.');
46
+ }
47
+ return version;
48
48
  }
49
- async function getNodeVersionFromAction(monorepoRoot) {
50
- const actionPath = path.join(monorepoRoot, GITHUB_ACTION_FILE_PATH);
51
- return getStringFromYamlFile(actionPath, "jobs.code-quality.with.node-version", "Node.js version");
49
+ export async function getNodeVersionFromAction(monorepoRoot) {
50
+ const actionPath = path.join(monorepoRoot, GITHUB_ACTION_FILE_PATH);
51
+ return getStringFromYamlFile(actionPath, 'jobs.code-quality.with.node-version', 'Node.js version');
52
52
  }
53
- function runConsistencyChecks() {
54
- const monorepoRoot = findMonorepoRoot();
55
- checkPnpmVersionConsistency(monorepoRoot);
56
- checkNodeVersionConsistency(monorepoRoot);
53
+ export function runConsistencyChecks() {
54
+ const monorepoRoot = findMonorepoRoot();
55
+ checkPnpmVersionConsistency(monorepoRoot);
56
+ checkNodeVersionConsistency(monorepoRoot);
57
57
  }
58
- export {
59
- checkNodeVersionConsistency,
60
- checkPnpmVersionConsistency,
61
- findMonorepoRoot2 as findMonorepoRoot,
62
- getNodeVersionFromAction,
63
- getPnpmVersionFromAction,
64
- getPnpmVersionFromPackageJson,
65
- runConsistencyChecks
66
- };
@@ -1,15 +1,12 @@
1
- import assert from "node:assert";
2
- import fs from "node:fs";
3
- import path from "node:path";
4
- async function getRuntimeVersionFromAsdf(runtime, monorepoRoot) {
5
- const toolVersionsPath = path.join(monorepoRoot, ".tool-versions");
6
- const toolVersions = await fs.promises.readFile(toolVersionsPath, { encoding: "utf8" });
7
- const versionLine = toolVersions.split("\n").find((line) => line.trim().startsWith(runtime));
8
- assert.ok(versionLine, `${runtime} not found in .tool-versions`);
9
- const [, version] = versionLine.trim().split(/\s+/);
10
- assert.ok(version, `${runtime} version missing in .tool-versions`);
11
- return version;
1
+ import assert from 'node:assert';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ export async function getRuntimeVersionFromAsdf(runtime, monorepoRoot) {
5
+ const toolVersionsPath = path.join(monorepoRoot, '.tool-versions');
6
+ const toolVersions = await fs.promises.readFile(toolVersionsPath, { encoding: 'utf8' });
7
+ const versionLine = toolVersions.split('\n').find((line) => line.trim().startsWith(runtime));
8
+ assert.ok(versionLine, `${runtime} not found in .tool-versions`);
9
+ const [, version] = versionLine.trim().split(/\s+/);
10
+ assert.ok(version, `${runtime} version missing in .tool-versions`);
11
+ return version;
12
12
  }
13
- export {
14
- getRuntimeVersionFromAsdf
15
- };
@@ -1,15 +1,12 @@
1
- import assert from "node:assert";
2
- import fs from "node:fs";
3
- import { parse } from "yaml";
1
+ import assert from 'node:assert';
2
+ import fs from 'node:fs';
3
+ import { parse } from 'yaml';
4
4
  import { getValueAtPathOrThrow } from "./get-value-at-path.js";
5
- async function getStringFromYamlFile(filePath, keyPath, label) {
6
- const raw = await fs.promises.readFile(filePath, { encoding: "utf8" });
7
- const parsed = parse(raw);
8
- assert.ok(parsed, `YAML content not found in ${filePath}`);
9
- const value = getValueAtPathOrThrow(parsed, keyPath);
10
- assert.ok(typeof value === "string" && value.length > 0, `${label} not found at ${keyPath}`);
11
- return value;
5
+ export async function getStringFromYamlFile(filePath, keyPath, label) {
6
+ const raw = await fs.promises.readFile(filePath, { encoding: 'utf8' });
7
+ const parsed = parse(raw);
8
+ assert.ok(parsed, `YAML content not found in ${filePath}`);
9
+ const value = getValueAtPathOrThrow(parsed, keyPath);
10
+ assert.ok(typeof value === 'string' && value.length > 0, `${label} not found at ${keyPath}`);
11
+ return value;
12
12
  }
13
- export {
14
- getStringFromYamlFile
15
- };
@@ -1,34 +1,34 @@
1
1
  function isObject(value) {
2
- return typeof value === "object" && value !== null && !Array.isArray(value);
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3
3
  }
4
- function getValueAtPathOrThrow(obj, objPath) {
5
- if (!isObject(obj)) {
6
- throw new Error("Expected an object as root value.");
7
- }
8
- const keys = objPath.split(".");
9
- let current = obj;
10
- for (const key of keys) {
11
- if (Array.isArray(current)) {
12
- const index = Number(key);
13
- if (Number.isNaN(index)) {
14
- throw new TypeError(`Expected array index at segment "${key}" in path "${objPath}"`);
15
- }
16
- if (index >= 0 && index < current.length) {
17
- current = current[index];
18
- } else {
19
- throw new Error(`Array index out of bounds: "${key}" in path "${objPath}"`);
20
- }
21
- } else if (isObject(current)) {
22
- if (!(key in current)) {
23
- throw new Error(`Missing key "${key}" in path "${objPath}"`);
24
- }
25
- current = current[key];
26
- } else {
27
- throw new Error(`Unexpected non-object/non-array at segment "${key}" in path "${objPath}"`);
4
+ export function getValueAtPathOrThrow(obj, objPath) {
5
+ if (!isObject(obj)) {
6
+ throw new Error('Expected an object as root value.');
28
7
  }
29
- }
30
- return current;
8
+ const keys = objPath.split('.');
9
+ let current = obj;
10
+ for (const key of keys) {
11
+ if (Array.isArray(current)) {
12
+ const index = Number(key);
13
+ if (Number.isNaN(index)) {
14
+ throw new TypeError(`Expected array index at segment "${key}" in path "${objPath}"`);
15
+ }
16
+ if (index >= 0 && index < current.length) {
17
+ current = current[index];
18
+ }
19
+ else {
20
+ throw new Error(`Array index out of bounds: "${key}" in path "${objPath}"`);
21
+ }
22
+ }
23
+ else if (isObject(current)) {
24
+ if (!(key in current)) {
25
+ throw new Error(`Missing key "${key}" in path "${objPath}"`);
26
+ }
27
+ current = current[key];
28
+ }
29
+ else {
30
+ throw new Error(`Unexpected non-object/non-array at segment "${key}" in path "${objPath}"`);
31
+ }
32
+ }
33
+ return current;
31
34
  }
32
- export {
33
- getValueAtPathOrThrow
34
- };