@williamthorsen/nmr-core 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -9
- package/dist/esm/.cache +1 -1
- package/dist/esm/index.d.ts +7 -6
- package/dist/esm/index.js +2 -0
- package/dist/esm/readPackageVersion.d.ts +1 -0
- package/dist/esm/readPackageVersion.js +15 -0
- package/package.json +3 -3
- package/dist/esm/cli-report-overrides.d.ts +0 -1
- package/dist/esm/cli-report-overrides.js +0 -9
- package/dist/esm/cli-sync-pnpm-version.d.ts +0 -1
- package/dist/esm/cli-sync-pnpm-version.js +0 -9
- package/dist/esm/cli.d.ts +0 -1
- package/dist/esm/cli.js +0 -110
- package/dist/esm/commands/report-overrides.d.ts +0 -1
- package/dist/esm/commands/report-overrides.js +0 -15
- package/dist/esm/commands/sync-pnpm-version.d.ts +0 -3
- package/dist/esm/commands/sync-pnpm-version.js +0 -42
- package/dist/esm/config.d.ts +0 -6
- package/dist/esm/config.js +0 -21
- package/dist/esm/context.d.ts +0 -11
- package/dist/esm/context.js +0 -84
- package/dist/esm/help.d.ts +0 -2
- package/dist/esm/help.js +0 -31
- package/dist/esm/helpers/code-quality-pnpm-action.d.ts +0 -12
- package/dist/esm/helpers/code-quality-pnpm-action.js +0 -17
- package/dist/esm/helpers/package-json.d.ts +0 -11
- package/dist/esm/helpers/package-json.js +0 -45
- package/dist/esm/helpers/type-guards.d.ts +0 -1
- package/dist/esm/helpers/type-guards.js +0 -6
- package/dist/esm/helpers/yaml-utils.d.ts +0 -1
- package/dist/esm/helpers/yaml-utils.js +0 -14
- package/dist/esm/registries.d.ts +0 -5
- package/dist/esm/registries.js +0 -67
- package/dist/esm/resolver.d.ts +0 -11
- package/dist/esm/resolver.js +0 -64
- package/dist/esm/runner.d.ts +0 -4
- package/dist/esm/runner.js +0 -38
- package/dist/esm/tests/consistency.d.ts +0 -1
- package/dist/esm/tests/consistency.js +0 -70
- package/dist/esm/tests/helpers/get-runtime-version-from-asdf.d.ts +0 -1
- package/dist/esm/tests/helpers/get-runtime-version-from-asdf.js +0 -15
- package/dist/esm/tests/helpers/get-value-at-path.d.ts +0 -1
- package/dist/esm/tests/helpers/get-value-at-path.js +0 -34
package/README.md
CHANGED
|
@@ -4,15 +4,7 @@ Shared utilities for node-monorepo-tools packages.
|
|
|
4
4
|
|
|
5
5
|
This package serves as the shared library foundation for the monorepo. For the nmr CLI tool, see [`@williamthorsen/nmr`](../nmr).
|
|
6
6
|
|
|
7
|
-
<!-- section:release-notes -->
|
|
8
|
-
## Release notes — v0.3.0 (2026-04-23)
|
|
9
|
-
|
|
10
|
-
### Features
|
|
11
|
-
|
|
12
|
-
- Scaffold audit.yaml workflow from audit-deps init (#277)
|
|
13
|
-
|
|
14
|
-
Adds GitHub Actions workflow scaffolding to `audit-deps init`. Running the command now writes both `.config/audit-deps.config.json` and `.github/workflows/audit.yaml` in the target repo, so that consumers no longer have to copy the canonical caller workflow by hand from this repo. The workflow content is shipped as a bundled template that ships to npm, and the repo's own workflow is kept byte-identical to that template via a consistency test — the canonical workflow cannot silently drift from what is published.
|
|
15
|
-
<!-- /section:release-notes -->
|
|
7
|
+
<!-- section:release-notes --><!-- /section:release-notes -->
|
|
16
8
|
|
|
17
9
|
## Installation
|
|
18
10
|
|
package/dist/esm/.cache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1dc24071a091c2b879e7ff50fa75a058fc98715554757f75dc49184e781ea464
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export declare const PACKAGE_NAME = "@williamthorsen/nmr-core";
|
|
2
|
-
export { findPackageRoot } from './findPackageRoot.
|
|
3
|
-
export type { FlagDefinition, FlagSchema, ParsedArgs, ParsedFlags } from './parseArgs.
|
|
4
|
-
export { parseArgs, translateParseError } from './parseArgs.
|
|
5
|
-
export {
|
|
6
|
-
export
|
|
7
|
-
export {
|
|
2
|
+
export { findPackageRoot } from './findPackageRoot.ts';
|
|
3
|
+
export type { FlagDefinition, FlagSchema, ParsedArgs, ParsedFlags } from './parseArgs.ts';
|
|
4
|
+
export { parseArgs, translateParseError } from './parseArgs.ts';
|
|
5
|
+
export { readPackageVersion } from './readPackageVersion.ts';
|
|
6
|
+
export { printError, printSkip, printStep, printSuccess, reportWriteResult } from './terminal.ts';
|
|
7
|
+
export type { WriteOutcome, WriteResult } from './writeFileWithCheck.ts';
|
|
8
|
+
export { writeFileWithCheck } from './writeFileWithCheck.ts';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const PACKAGE_NAME = "@williamthorsen/nmr-core";
|
|
2
2
|
import { findPackageRoot } from "./findPackageRoot.js";
|
|
3
3
|
import { parseArgs, translateParseError } from "./parseArgs.js";
|
|
4
|
+
import { readPackageVersion } from "./readPackageVersion.js";
|
|
4
5
|
import { printError, printSkip, printStep, printSuccess, reportWriteResult } from "./terminal.js";
|
|
5
6
|
import { writeFileWithCheck } from "./writeFileWithCheck.js";
|
|
6
7
|
export {
|
|
@@ -11,6 +12,7 @@ export {
|
|
|
11
12
|
printSkip,
|
|
12
13
|
printStep,
|
|
13
14
|
printSuccess,
|
|
15
|
+
readPackageVersion,
|
|
14
16
|
reportWriteResult,
|
|
15
17
|
translateParseError,
|
|
16
18
|
writeFileWithCheck
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readPackageVersion(fromUrl: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { findPackageRoot } from "./findPackageRoot.js";
|
|
4
|
+
function readPackageVersion(fromUrl) {
|
|
5
|
+
const root = findPackageRoot(fromUrl);
|
|
6
|
+
const packageJsonPath = resolve(root, "package.json");
|
|
7
|
+
const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
8
|
+
if (typeof raw !== "object" || raw === null || !("version" in raw) || typeof raw.version !== "string") {
|
|
9
|
+
throw new Error(`No string "version" field in ${packageJsonPath}`);
|
|
10
|
+
}
|
|
11
|
+
return raw.version;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
readPackageVersion
|
|
15
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@williamthorsen/nmr-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared utilities for node-monorepo-tools packages",
|
|
6
6
|
"keywords": [
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
"pnpm",
|
|
9
9
|
"utilities"
|
|
10
10
|
],
|
|
11
|
-
"homepage": "https://github.com/williamthorsen/node-monorepo-tools/tree/main/packages/core#readme",
|
|
11
|
+
"homepage": "https://github.com/williamthorsen/node-monorepo-tools/tree/main/packages/nmr-core#readme",
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/williamthorsen/node-monorepo-tools/issues"
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
17
|
"url": "https://github.com/williamthorsen/node-monorepo-tools.git",
|
|
18
|
-
"directory": "packages/core"
|
|
18
|
+
"directory": "packages/nmr-core"
|
|
19
19
|
},
|
|
20
20
|
"license": "ISC",
|
|
21
21
|
"author": "William Thorsen <william@thorsen.dev> (https://github.com/williamthorsen)",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { reportOverrides } from "./commands/report-overrides.js";
|
|
2
|
-
import { findMonorepoRoot } from "./context.js";
|
|
3
|
-
try {
|
|
4
|
-
const monorepoRoot = findMonorepoRoot();
|
|
5
|
-
reportOverrides(monorepoRoot);
|
|
6
|
-
} catch (error) {
|
|
7
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { syncPnpmVersion } from "./commands/sync-pnpm-version.js";
|
|
2
|
-
import { findMonorepoRoot } from "./context.js";
|
|
3
|
-
try {
|
|
4
|
-
const monorepoRoot = findMonorepoRoot();
|
|
5
|
-
syncPnpmVersion(monorepoRoot);
|
|
6
|
-
} catch (error) {
|
|
7
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
package/dist/esm/cli.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/esm/cli.js
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import process from "node:process";
|
|
2
|
-
import { resolveContext } from "./context.js";
|
|
3
|
-
import { generateHelp } from "./help.js";
|
|
4
|
-
import { buildRootRegistry, buildWorkspaceRegistry, resolveScript } from "./resolver.js";
|
|
5
|
-
import { runCommand } from "./runner.js";
|
|
6
|
-
function shellQuote(arg) {
|
|
7
|
-
return "'" + arg.replace(/'/g, String.raw`'\''`) + "'";
|
|
8
|
-
}
|
|
9
|
-
function parseArgs(argv) {
|
|
10
|
-
const args = argv.slice(2);
|
|
11
|
-
const result = {
|
|
12
|
-
quiet: false,
|
|
13
|
-
recursive: false,
|
|
14
|
-
workspaceRoot: false,
|
|
15
|
-
help: false,
|
|
16
|
-
intTest: false,
|
|
17
|
-
passthrough: []
|
|
18
|
-
};
|
|
19
|
-
let i = 0;
|
|
20
|
-
while (i < args.length) {
|
|
21
|
-
const arg = args[i];
|
|
22
|
-
if (arg === void 0) break;
|
|
23
|
-
if (arg === "-F" || arg === "--filter") {
|
|
24
|
-
i++;
|
|
25
|
-
const filterValue = args[i];
|
|
26
|
-
if (filterValue === void 0) {
|
|
27
|
-
console.error("Error: -F/--filter requires a pattern argument");
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
result.filter = filterValue;
|
|
31
|
-
i++;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (arg === "-R" || arg === "--recursive") {
|
|
35
|
-
result.recursive = true;
|
|
36
|
-
i++;
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (arg === "-w" || arg === "--workspace-root") {
|
|
40
|
-
result.workspaceRoot = true;
|
|
41
|
-
i++;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (arg === "-?" || arg === "--help") {
|
|
45
|
-
result.help = true;
|
|
46
|
-
i++;
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
if (arg === "-q" || arg === "--quiet") {
|
|
50
|
-
result.quiet = true;
|
|
51
|
-
i++;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (arg === "--int-test") {
|
|
55
|
-
result.intTest = true;
|
|
56
|
-
i++;
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
result.command = arg;
|
|
60
|
-
result.passthrough = args.slice(i + 1);
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
65
|
-
async function main() {
|
|
66
|
-
const parsed = parseArgs(process.argv);
|
|
67
|
-
const context = await resolveContext();
|
|
68
|
-
if (parsed.help || !parsed.command) {
|
|
69
|
-
console.info(generateHelp(context.config));
|
|
70
|
-
process.exit(0);
|
|
71
|
-
}
|
|
72
|
-
const { command } = parsed;
|
|
73
|
-
const passthrough = parsed.passthrough.length > 0 ? " " + parsed.passthrough.map(shellQuote).join(" ") : "";
|
|
74
|
-
const runOptions = { quiet: parsed.quiet };
|
|
75
|
-
if (parsed.filter) {
|
|
76
|
-
const delegateCmd = `pnpm --filter ${shellQuote(parsed.filter)} exec nmr ${command}${passthrough}`;
|
|
77
|
-
const code2 = runCommand(delegateCmd, context.monorepoRoot, runOptions);
|
|
78
|
-
process.exit(code2);
|
|
79
|
-
}
|
|
80
|
-
if (parsed.recursive) {
|
|
81
|
-
const delegateCmd = `pnpm --recursive exec nmr ${command}${passthrough}`;
|
|
82
|
-
const code2 = runCommand(delegateCmd, context.monorepoRoot, runOptions);
|
|
83
|
-
process.exit(code2);
|
|
84
|
-
}
|
|
85
|
-
const useRoot = parsed.workspaceRoot || context.isRoot;
|
|
86
|
-
const registry = useRoot ? buildRootRegistry(context.config) : buildWorkspaceRegistry(context.config, parsed.intTest);
|
|
87
|
-
const resolved = resolveScript(command, registry, context.packageDir);
|
|
88
|
-
if (!resolved) {
|
|
89
|
-
console.error(`Unknown command: ${command}`);
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
if (resolved.command === "") {
|
|
93
|
-
if (!parsed.quiet) {
|
|
94
|
-
console.info("Override script is defined but empty. Skipping.");
|
|
95
|
-
}
|
|
96
|
-
process.exit(0);
|
|
97
|
-
}
|
|
98
|
-
if (resolved.source === "package" && !parsed.quiet) {
|
|
99
|
-
console.info(`Using override script: ${resolved.command}`);
|
|
100
|
-
}
|
|
101
|
-
const fullCommand = resolved.command + passthrough;
|
|
102
|
-
const code = runCommand(fullCommand, void 0, runOptions);
|
|
103
|
-
process.exit(code);
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
await main();
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error(error);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function reportOverrides(monorepoRoot: string): void;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { getPnpmOverrides, readPackageJson } from "../helpers/package-json.js";
|
|
2
|
-
function reportOverrides(monorepoRoot) {
|
|
3
|
-
const pkg = readPackageJson(monorepoRoot);
|
|
4
|
-
const overrides = getPnpmOverrides(pkg);
|
|
5
|
-
if (!overrides || Object.keys(overrides).length === 0) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
console.warn("\u{1F512} WARN: pnpm overrides are active! Check whether these are still needed:");
|
|
9
|
-
for (const [name, version] of Object.entries(overrides)) {
|
|
10
|
-
console.warn(`- ${name} \u2192 ${version}`);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export {
|
|
14
|
-
reportOverrides
|
|
15
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { CodeQualityPnpmWorkflowSchema, getPnpmVersion } from "../helpers/code-quality-pnpm-action.js";
|
|
4
|
-
import { readPackageJson } from "../helpers/package-json.js";
|
|
5
|
-
import { readYamlFile } from "../helpers/yaml-utils.js";
|
|
6
|
-
const WORKFLOW_RELATIVE_PATH = ".github/workflows/code-quality.yaml";
|
|
7
|
-
function extractPnpmVersion(packageManager) {
|
|
8
|
-
if (!packageManager) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
const match = /^pnpm@(.+)$/.exec(packageManager);
|
|
12
|
-
return match?.[1] ?? null;
|
|
13
|
-
}
|
|
14
|
-
function syncPnpmVersion(monorepoRoot) {
|
|
15
|
-
console.info("Synchronizing pnpm version in GitHub workflow...");
|
|
16
|
-
const pkg = readPackageJson(monorepoRoot);
|
|
17
|
-
const pnpmVersion = extractPnpmVersion(pkg.packageManager);
|
|
18
|
-
if (!pnpmVersion) {
|
|
19
|
-
throw new Error(
|
|
20
|
-
`Could not extract pnpm version from package.json packageManager field
|
|
21
|
-
packageManager field: ${pkg.packageManager ?? "(not set)"}`
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
console.info(`Package.json pnpm version: ${pnpmVersion}`);
|
|
25
|
-
const workflowPath = path.join(monorepoRoot, WORKFLOW_RELATIVE_PATH);
|
|
26
|
-
const workflowData = readYamlFile(workflowPath);
|
|
27
|
-
const workflow = CodeQualityPnpmWorkflowSchema.parse(workflowData);
|
|
28
|
-
const currentWorkflowVersion = getPnpmVersion(workflow);
|
|
29
|
-
console.info(`Current workflow pnpm version: ${currentWorkflowVersion}`);
|
|
30
|
-
if (currentWorkflowVersion === pnpmVersion) {
|
|
31
|
-
console.info("Workflow pnpm version is already up to date");
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const originalContent = readFileSync(workflowPath, "utf8");
|
|
35
|
-
const updatedContent = originalContent.replace(/(\s+pnpm-version:\s+)(['"]?)[\d.]+\2/, `$1$2${pnpmVersion}$2`);
|
|
36
|
-
writeFileSync(workflowPath, updatedContent, "utf8");
|
|
37
|
-
console.info(`\u2713 Updated workflow pnpm version: ${currentWorkflowVersion} \u2192 ${pnpmVersion}`);
|
|
38
|
-
}
|
|
39
|
-
export {
|
|
40
|
-
extractPnpmVersion,
|
|
41
|
-
syncPnpmVersion
|
|
42
|
-
};
|
package/dist/esm/config.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export interface NmrConfig {
|
|
2
|
-
workspaceScripts?: Record<string, string | string[]>;
|
|
3
|
-
rootScripts?: Record<string, string | string[]>;
|
|
4
|
-
}
|
|
5
|
-
export declare function defineConfig(config: NmrConfig): NmrConfig;
|
|
6
|
-
export declare function loadConfig(monorepoRoot: string): Promise<NmrConfig>;
|
package/dist/esm/config.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { createJiti } from "jiti";
|
|
4
|
-
const CONFIG_FILENAME = "nmr.config.ts";
|
|
5
|
-
const CONFIG_DIR = ".config";
|
|
6
|
-
function defineConfig(config) {
|
|
7
|
-
return config;
|
|
8
|
-
}
|
|
9
|
-
async function loadConfig(monorepoRoot) {
|
|
10
|
-
const configPath = path.join(monorepoRoot, CONFIG_DIR, CONFIG_FILENAME);
|
|
11
|
-
if (!existsSync(configPath)) {
|
|
12
|
-
return {};
|
|
13
|
-
}
|
|
14
|
-
const jiti = createJiti(path.join(monorepoRoot, "package.json"));
|
|
15
|
-
const loaded = await jiti.import(configPath, { default: true });
|
|
16
|
-
return loaded;
|
|
17
|
-
}
|
|
18
|
-
export {
|
|
19
|
-
defineConfig,
|
|
20
|
-
loadConfig
|
|
21
|
-
};
|
package/dist/esm/context.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { NmrConfig } from './config.js';
|
|
2
|
-
export interface ResolvedContext {
|
|
3
|
-
monorepoRoot: string;
|
|
4
|
-
isRoot: boolean;
|
|
5
|
-
packageDir?: string;
|
|
6
|
-
config: NmrConfig;
|
|
7
|
-
}
|
|
8
|
-
export declare function findMonorepoRoot(startDir?: string): string;
|
|
9
|
-
export declare function getWorkspacePackageDirs(monorepoRoot: string): string[];
|
|
10
|
-
export declare function findContainingPackageDir(dir: string, workspacePackageDirs: string[]): string | undefined;
|
|
11
|
-
export declare function resolveContext(cwd?: string): Promise<ResolvedContext>;
|
package/dist/esm/context.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import yaml from "js-yaml";
|
|
4
|
-
import { loadConfig } from "./config.js";
|
|
5
|
-
import { isObject } from "./helpers/type-guards.js";
|
|
6
|
-
function findMonorepoRoot(startDir) {
|
|
7
|
-
let dir = path.resolve(startDir ?? process.cwd());
|
|
8
|
-
for (; ; ) {
|
|
9
|
-
if (existsSync(path.join(dir, "pnpm-workspace.yaml"))) {
|
|
10
|
-
return dir;
|
|
11
|
-
}
|
|
12
|
-
const parent = path.dirname(dir);
|
|
13
|
-
if (parent === dir) {
|
|
14
|
-
throw new Error("Could not find monorepo root: no pnpm-workspace.yaml found in any parent directory");
|
|
15
|
-
}
|
|
16
|
-
dir = parent;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function getWorkspacePackageDirs(monorepoRoot) {
|
|
20
|
-
const workspaceFile = path.join(monorepoRoot, "pnpm-workspace.yaml");
|
|
21
|
-
const content = readFileSync(workspaceFile, "utf8");
|
|
22
|
-
const parsed = yaml.load(content);
|
|
23
|
-
const packages = getPackagesFromParsedYaml(parsed);
|
|
24
|
-
if (!packages) {
|
|
25
|
-
return [];
|
|
26
|
-
}
|
|
27
|
-
const dirs = [];
|
|
28
|
-
for (const pattern of packages) {
|
|
29
|
-
if (pattern.endsWith("/*")) {
|
|
30
|
-
const prefix = pattern.slice(0, -2);
|
|
31
|
-
const prefixDir = path.resolve(monorepoRoot, prefix);
|
|
32
|
-
if (existsSync(prefixDir)) {
|
|
33
|
-
for (const entry of readdirSync(prefixDir)) {
|
|
34
|
-
const fullPath = path.join(prefixDir, entry);
|
|
35
|
-
if (statSync(fullPath).isDirectory() && existsSync(path.join(fullPath, "package.json"))) {
|
|
36
|
-
dirs.push(fullPath);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else if (!pattern.includes("*")) {
|
|
41
|
-
const fullPath = path.resolve(monorepoRoot, pattern);
|
|
42
|
-
if (existsSync(fullPath) && existsSync(path.join(fullPath, "package.json"))) {
|
|
43
|
-
dirs.push(fullPath);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return dirs;
|
|
48
|
-
}
|
|
49
|
-
function findContainingPackageDir(dir, workspacePackageDirs) {
|
|
50
|
-
const resolved = path.resolve(dir);
|
|
51
|
-
for (const pkgDir of workspacePackageDirs) {
|
|
52
|
-
const resolvedPkgDir = path.resolve(pkgDir);
|
|
53
|
-
if (resolved === resolvedPkgDir || resolved.startsWith(resolvedPkgDir + path.sep)) {
|
|
54
|
-
return resolvedPkgDir;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return void 0;
|
|
58
|
-
}
|
|
59
|
-
function getPackagesFromParsedYaml(parsed) {
|
|
60
|
-
if (!isObject(parsed)) return void 0;
|
|
61
|
-
const packages = parsed.packages;
|
|
62
|
-
if (!Array.isArray(packages)) return void 0;
|
|
63
|
-
if (!packages.every((p) => typeof p === "string")) return void 0;
|
|
64
|
-
return packages;
|
|
65
|
-
}
|
|
66
|
-
async function resolveContext(cwd) {
|
|
67
|
-
const resolvedCwd = path.resolve(cwd ?? process.cwd());
|
|
68
|
-
const monorepoRoot = findMonorepoRoot(resolvedCwd);
|
|
69
|
-
const config = await loadConfig(monorepoRoot);
|
|
70
|
-
const workspaceDirs = getWorkspacePackageDirs(monorepoRoot);
|
|
71
|
-
const packageDir = findContainingPackageDir(resolvedCwd, workspaceDirs);
|
|
72
|
-
return {
|
|
73
|
-
monorepoRoot,
|
|
74
|
-
isRoot: packageDir === void 0,
|
|
75
|
-
...packageDir === void 0 ? {} : { packageDir },
|
|
76
|
-
config
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
export {
|
|
80
|
-
findContainingPackageDir,
|
|
81
|
-
findMonorepoRoot,
|
|
82
|
-
getWorkspacePackageDirs,
|
|
83
|
-
resolveContext
|
|
84
|
-
};
|
package/dist/esm/help.d.ts
DELETED
package/dist/esm/help.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { buildRootRegistry, buildWorkspaceRegistry } from "./resolver.js";
|
|
2
|
-
import { describeScript } from "./resolver.js";
|
|
3
|
-
function generateHelp(config) {
|
|
4
|
-
const lines = [
|
|
5
|
-
"Usage: nmr [flags] <command> [args...]",
|
|
6
|
-
"",
|
|
7
|
-
"Flags:",
|
|
8
|
-
" -F, --filter <pattern> Run command in matching packages",
|
|
9
|
-
" -R, --recursive Run command in all packages",
|
|
10
|
-
" -w, --workspace-root Run root command regardless of cwd",
|
|
11
|
-
" -q, --quiet Suppress output on success; show full output on failure",
|
|
12
|
-
" -?, --help Show this help",
|
|
13
|
-
" --int-test Use integration test scripts",
|
|
14
|
-
"",
|
|
15
|
-
"Workspace commands:"
|
|
16
|
-
];
|
|
17
|
-
formatRegistry(buildWorkspaceRegistry(config, false), lines);
|
|
18
|
-
lines.push("", "Root commands:");
|
|
19
|
-
formatRegistry(buildRootRegistry(config), lines);
|
|
20
|
-
return lines.join("\n");
|
|
21
|
-
}
|
|
22
|
-
function formatRegistry(registry, lines) {
|
|
23
|
-
const maxKeyLen = Math.max(...Object.keys(registry).map((k) => k.length));
|
|
24
|
-
const pad = Math.max(maxKeyLen + 2, 20);
|
|
25
|
-
for (const [key, value] of Object.entries(registry)) {
|
|
26
|
-
lines.push(` ${key.padEnd(pad)} ${describeScript(value)}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export {
|
|
30
|
-
generateHelp
|
|
31
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const CodeQualityPnpmWorkflowSchema: z.ZodObject<{
|
|
3
|
-
jobs: z.ZodObject<{
|
|
4
|
-
'code-quality': z.ZodObject<{
|
|
5
|
-
with: z.ZodObject<{
|
|
6
|
-
'pnpm-version': z.ZodString;
|
|
7
|
-
}, z.core.$loose>;
|
|
8
|
-
}, z.core.$loose>;
|
|
9
|
-
}, z.core.$loose>;
|
|
10
|
-
}, z.core.$loose>;
|
|
11
|
-
export type CodeQualityPnpmWorkflow = z.infer<typeof CodeQualityPnpmWorkflowSchema>;
|
|
12
|
-
export declare function getPnpmVersion(workflow: CodeQualityPnpmWorkflow): string;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
const CodeQualityPnpmWorkflowSchema = z.looseObject({
|
|
3
|
-
jobs: z.looseObject({
|
|
4
|
-
"code-quality": z.looseObject({
|
|
5
|
-
with: z.looseObject({
|
|
6
|
-
"pnpm-version": z.string()
|
|
7
|
-
})
|
|
8
|
-
})
|
|
9
|
-
})
|
|
10
|
-
});
|
|
11
|
-
function getPnpmVersion(workflow) {
|
|
12
|
-
return workflow.jobs["code-quality"].with["pnpm-version"];
|
|
13
|
-
}
|
|
14
|
-
export {
|
|
15
|
-
CodeQualityPnpmWorkflowSchema,
|
|
16
|
-
getPnpmVersion
|
|
17
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface PackageJson {
|
|
2
|
-
name?: string;
|
|
3
|
-
version?: string;
|
|
4
|
-
packageManager?: string;
|
|
5
|
-
scripts?: Record<string, string>;
|
|
6
|
-
pnpm?: {
|
|
7
|
-
overrides?: Record<string, string>;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
export declare function readPackageJson(dir: string): PackageJson;
|
|
11
|
-
export declare function getPnpmOverrides(pkg: PackageJson): Record<string, string> | undefined;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { isObject } from "./type-guards.js";
|
|
4
|
-
function readPackageJson(dir) {
|
|
5
|
-
const content = readFileSync(path.join(dir, "package.json"), "utf8");
|
|
6
|
-
const parsed = JSON.parse(content);
|
|
7
|
-
if (!isObject(parsed)) {
|
|
8
|
-
throw new TypeError(`Invalid package.json in ${dir}: expected an object`);
|
|
9
|
-
}
|
|
10
|
-
const pkg = {};
|
|
11
|
-
if (typeof parsed.name === "string") pkg.name = parsed.name;
|
|
12
|
-
if (typeof parsed.version === "string") pkg.version = parsed.version;
|
|
13
|
-
if (typeof parsed.packageManager === "string") pkg.packageManager = parsed.packageManager;
|
|
14
|
-
if (isObject(parsed.scripts)) {
|
|
15
|
-
const scripts = {};
|
|
16
|
-
for (const [key, val] of Object.entries(parsed.scripts)) {
|
|
17
|
-
if (typeof val === "string") scripts[key] = val;
|
|
18
|
-
}
|
|
19
|
-
pkg.scripts = scripts;
|
|
20
|
-
}
|
|
21
|
-
if (isObject(parsed.pnpm)) {
|
|
22
|
-
const pnpm = parsed.pnpm;
|
|
23
|
-
if (isObject(pnpm.overrides)) {
|
|
24
|
-
const overrides = {};
|
|
25
|
-
for (const [key, val] of Object.entries(pnpm.overrides)) {
|
|
26
|
-
if (typeof val === "string") overrides[key] = val;
|
|
27
|
-
}
|
|
28
|
-
pkg.pnpm = { overrides };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return pkg;
|
|
32
|
-
}
|
|
33
|
-
function getPnpmOverrides(pkg) {
|
|
34
|
-
if (!isObject(pkg.pnpm)) return void 0;
|
|
35
|
-
const overrides = pkg.pnpm.overrides;
|
|
36
|
-
if (!isObject(overrides)) return void 0;
|
|
37
|
-
for (const value of Object.values(overrides)) {
|
|
38
|
-
if (typeof value !== "string") return void 0;
|
|
39
|
-
}
|
|
40
|
-
return overrides;
|
|
41
|
-
}
|
|
42
|
-
export {
|
|
43
|
-
getPnpmOverrides,
|
|
44
|
-
readPackageJson
|
|
45
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function isObject(value: unknown): value is Record<string, unknown>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function readYamlFile(filepath: string): unknown;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import yaml from "js-yaml";
|
|
3
|
-
function readYamlFile(filepath) {
|
|
4
|
-
try {
|
|
5
|
-
const content = readFileSync(filepath, "utf8");
|
|
6
|
-
return yaml.load(content);
|
|
7
|
-
} catch (error) {
|
|
8
|
-
throw new Error(`Failed to read YAML file: ${filepath}
|
|
9
|
-
${error instanceof Error ? error.message : String(error)}`);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
export {
|
|
13
|
-
readYamlFile
|
|
14
|
-
};
|
package/dist/esm/registries.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export type ScriptValue = string | string[];
|
|
2
|
-
export type ScriptRegistry = Record<string, ScriptValue>;
|
|
3
|
-
declare function getDefaultWorkspaceScripts(useIntTests: boolean): ScriptRegistry;
|
|
4
|
-
declare function getDefaultRootScripts(): ScriptRegistry;
|
|
5
|
-
export { getDefaultRootScripts, getDefaultWorkspaceScripts };
|
package/dist/esm/registries.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
function getDefaultWorkspaceScripts(useIntTests) {
|
|
2
|
-
const commonScripts = {
|
|
3
|
-
build: ["compile", "generate-typings"],
|
|
4
|
-
check: ["typecheck", "fmt:check", "lint:check", "test"],
|
|
5
|
-
"check:strict": ["typecheck", "fmt:check", "lint:strict", "test:coverage"],
|
|
6
|
-
clean: "pnpm exec rimraf dist/*",
|
|
7
|
-
compile: "tsx ../../config/build.ts",
|
|
8
|
-
fmt: "prettier --list-different --write .",
|
|
9
|
-
"fmt:check": "prettier --check .",
|
|
10
|
-
"generate-typings": "tsc --project tsconfig.generate-typings.json",
|
|
11
|
-
lint: "eslint --fix .",
|
|
12
|
-
"lint:check": "eslint .",
|
|
13
|
-
"lint:strict": "strict-lint",
|
|
14
|
-
typecheck: "tsgo --noEmit",
|
|
15
|
-
"view-coverage": "open coverage/index.html"
|
|
16
|
-
};
|
|
17
|
-
const integrationTestOverrides = {
|
|
18
|
-
test: "pnpm exec vitest --config=vitest.standalone.config.ts",
|
|
19
|
-
"test:coverage": "pnpm exec vitest --config=vitest.standalone.config.ts --coverage",
|
|
20
|
-
"test:integration": "pnpm exec vitest --config=vitest.integration.config.ts",
|
|
21
|
-
"test:watch": "pnpm exec vitest --config=vitest.standalone.config.ts --watch"
|
|
22
|
-
};
|
|
23
|
-
const standardTestOverrides = {
|
|
24
|
-
test: "pnpm exec vitest",
|
|
25
|
-
"test:coverage": "pnpm exec vitest --coverage",
|
|
26
|
-
"test:watch": "pnpm exec vitest --watch"
|
|
27
|
-
};
|
|
28
|
-
return {
|
|
29
|
-
...commonScripts,
|
|
30
|
-
...useIntTests ? integrationTestOverrides : standardTestOverrides
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function getDefaultRootScripts() {
|
|
34
|
-
return {
|
|
35
|
-
audit: ["audit:prod", "audit:dev"],
|
|
36
|
-
"audit:dev": "pnpm dlx audit-ci@^6 --config .audit-ci/config.dev.json5",
|
|
37
|
-
"audit:prod": "pnpm dlx audit-ci@^6 --config .audit-ci/config.prod.json5",
|
|
38
|
-
build: "pnpm --recursive exec nmr build",
|
|
39
|
-
check: ["typecheck", "fmt:check", "lint:check", "test"],
|
|
40
|
-
"check:strict": ["typecheck", "fmt:check", "lint:strict", "test:coverage", "audit"],
|
|
41
|
-
ci: ["check:strict", "build"],
|
|
42
|
-
fmt: `sh -c 'prettier --list-different --write "\${@:-.}"' --`,
|
|
43
|
-
"fmt:check": `sh -c 'prettier --check "\${@:-.}"' --`,
|
|
44
|
-
lint: "nmr root:lint && pnpm --recursive exec nmr lint",
|
|
45
|
-
"lint:check": "nmr root:lint:check && pnpm --recursive exec nmr lint:check",
|
|
46
|
-
"lint:strict": "nmr root:lint:strict && pnpm --recursive exec nmr lint:strict",
|
|
47
|
-
outdated: "pnpm outdated --compatible --recursive",
|
|
48
|
-
"outdated:latest": "pnpm outdated --recursive",
|
|
49
|
-
"report-overrides": "nmr-report-overrides",
|
|
50
|
-
"root:lint": "eslint --fix --ignore-pattern 'packages/**' .",
|
|
51
|
-
"root:lint:check": "eslint --ignore-pattern 'packages/**' .",
|
|
52
|
-
"root:lint:strict": "strict-lint --ignore-pattern 'packages/**' .",
|
|
53
|
-
"root:test": "vitest --config ./vitest.root.config.ts",
|
|
54
|
-
"root:typecheck": "tsgo --noEmit",
|
|
55
|
-
"sync-pnpm-version": "nmr-sync-pnpm-version",
|
|
56
|
-
test: "nmr root:test && pnpm --recursive exec nmr test",
|
|
57
|
-
"test:coverage": "nmr root:test && pnpm --recursive exec nmr test:coverage",
|
|
58
|
-
"test:watch": "vitest --watch",
|
|
59
|
-
typecheck: "nmr root:typecheck && pnpm --recursive exec nmr typecheck",
|
|
60
|
-
update: "pnpm update --recursive",
|
|
61
|
-
"update:latest": "pnpm update --latest --recursive"
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
export {
|
|
65
|
-
getDefaultRootScripts,
|
|
66
|
-
getDefaultWorkspaceScripts
|
|
67
|
-
};
|
package/dist/esm/resolver.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { NmrConfig } from './config.js';
|
|
2
|
-
import type { ScriptRegistry, ScriptValue } from './registries.js';
|
|
3
|
-
export interface ResolvedScript {
|
|
4
|
-
command: string;
|
|
5
|
-
source: 'default' | 'package';
|
|
6
|
-
}
|
|
7
|
-
export declare function expandScript(script: ScriptValue): string;
|
|
8
|
-
export declare function describeScript(script: ScriptValue): string;
|
|
9
|
-
export declare function buildWorkspaceRegistry(config: NmrConfig, useIntTests: boolean): ScriptRegistry;
|
|
10
|
-
export declare function buildRootRegistry(config: NmrConfig): ScriptRegistry;
|
|
11
|
-
export declare function resolveScript(commandName: string, registry: ScriptRegistry, packageDir?: string): ResolvedScript | undefined;
|
package/dist/esm/resolver.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { isObject } from "./helpers/type-guards.js";
|
|
4
|
-
import { getDefaultRootScripts, getDefaultWorkspaceScripts } from "./registries.js";
|
|
5
|
-
function expandScript(script) {
|
|
6
|
-
if (typeof script === "string") {
|
|
7
|
-
return script;
|
|
8
|
-
}
|
|
9
|
-
return script.map((s) => `nmr ${s}`).join(" && ");
|
|
10
|
-
}
|
|
11
|
-
function describeScript(script) {
|
|
12
|
-
return typeof script === "string" ? script : `[${script.join(", ")}]`;
|
|
13
|
-
}
|
|
14
|
-
function readPackageJsonScripts(packageDir) {
|
|
15
|
-
try {
|
|
16
|
-
const raw = readFileSync(path.join(packageDir, "package.json"), "utf8");
|
|
17
|
-
const parsed = JSON.parse(raw);
|
|
18
|
-
if (!isObject(parsed)) return void 0;
|
|
19
|
-
const scripts = parsed.scripts;
|
|
20
|
-
if (!isObject(scripts)) return void 0;
|
|
21
|
-
const result = {};
|
|
22
|
-
for (const [key, val] of Object.entries(scripts)) {
|
|
23
|
-
if (typeof val === "string") result[key] = val;
|
|
24
|
-
}
|
|
25
|
-
return result;
|
|
26
|
-
} catch {
|
|
27
|
-
return void 0;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function buildWorkspaceRegistry(config, useIntTests) {
|
|
31
|
-
return {
|
|
32
|
-
...getDefaultWorkspaceScripts(useIntTests),
|
|
33
|
-
...config.workspaceScripts
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function buildRootRegistry(config) {
|
|
37
|
-
return {
|
|
38
|
-
...getDefaultRootScripts(),
|
|
39
|
-
...config.rootScripts
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function resolveScript(commandName, registry, packageDir) {
|
|
43
|
-
if (packageDir) {
|
|
44
|
-
const pkgScripts = readPackageJsonScripts(packageDir);
|
|
45
|
-
if (pkgScripts && commandName in pkgScripts) {
|
|
46
|
-
const override = pkgScripts[commandName];
|
|
47
|
-
if (override !== void 0) {
|
|
48
|
-
return { command: override, source: "package" };
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
const registryEntry = registry[commandName];
|
|
53
|
-
if (registryEntry === void 0) {
|
|
54
|
-
return void 0;
|
|
55
|
-
}
|
|
56
|
-
return { command: expandScript(registryEntry), source: "default" };
|
|
57
|
-
}
|
|
58
|
-
export {
|
|
59
|
-
buildRootRegistry,
|
|
60
|
-
buildWorkspaceRegistry,
|
|
61
|
-
describeScript,
|
|
62
|
-
expandScript,
|
|
63
|
-
resolveScript
|
|
64
|
-
};
|
package/dist/esm/runner.d.ts
DELETED
package/dist/esm/runner.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
|
-
import process from "node:process";
|
|
3
|
-
function runCommand(command, cwd, options) {
|
|
4
|
-
const quiet = options?.quiet === true;
|
|
5
|
-
const stdio = quiet ? "pipe" : "inherit";
|
|
6
|
-
try {
|
|
7
|
-
execSync(command, { stdio, cwd });
|
|
8
|
-
return 0;
|
|
9
|
-
} catch (error) {
|
|
10
|
-
if (error !== null && typeof error === "object") {
|
|
11
|
-
if (quiet) {
|
|
12
|
-
writeErrorOutput(error);
|
|
13
|
-
}
|
|
14
|
-
if ("status" in error) {
|
|
15
|
-
const { status } = error;
|
|
16
|
-
return typeof status === "number" ? status : 1;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return 1;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function writeErrorOutput(error) {
|
|
23
|
-
if ("stdout" in error) {
|
|
24
|
-
const { stdout } = error;
|
|
25
|
-
if (Buffer.isBuffer(stdout) && stdout.length > 0) {
|
|
26
|
-
process.stderr.write(stdout);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
if ("stderr" in error) {
|
|
30
|
-
const { stderr } = error;
|
|
31
|
-
if (Buffer.isBuffer(stderr) && stderr.length > 0) {
|
|
32
|
-
process.stderr.write(stderr);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export {
|
|
37
|
-
runCommand
|
|
38
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function runConsistencyChecks(): void;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import yaml from "js-yaml";
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import { findMonorepoRoot } from "../context.js";
|
|
7
|
-
import { getRuntimeVersionFromAsdf } from "./helpers/get-runtime-version-from-asdf.js";
|
|
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);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
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);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
async function getPnpmVersionFromAction(monorepoRoot) {
|
|
29
|
-
const actionPath = path.join(monorepoRoot, GITHUB_ACTION_FILE_PATH);
|
|
30
|
-
const actionYaml = await fs.promises.readFile(actionPath, { encoding: "utf8" });
|
|
31
|
-
const action = yaml.load(actionYaml);
|
|
32
|
-
assert.ok(action, "Action YAML not found");
|
|
33
|
-
const version = getValueAtPathOrThrow(action, "jobs.code-quality.with.pnpm-version");
|
|
34
|
-
assert.ok(typeof version === "string" && version.length > 0, "pnpm version not found in action");
|
|
35
|
-
return version;
|
|
36
|
-
}
|
|
37
|
-
function getPnpmVersionFromPackageJson(monorepoRoot) {
|
|
38
|
-
const pkgPath = path.join(monorepoRoot, "package.json");
|
|
39
|
-
const raw = fs.readFileSync(pkgPath, "utf8");
|
|
40
|
-
const pkg = JSON.parse(raw);
|
|
41
|
-
const pm = getValueAtPathOrThrow(pkg, "packageManager");
|
|
42
|
-
if (typeof pm !== "string") {
|
|
43
|
-
throw new TypeError('"packageManager" field missing or not a string in package.json.');
|
|
44
|
-
}
|
|
45
|
-
const [name, version] = pm.split("@");
|
|
46
|
-
if (name !== "pnpm") {
|
|
47
|
-
throw new Error("packageManager is not pnpm.");
|
|
48
|
-
}
|
|
49
|
-
if (!version) {
|
|
50
|
-
throw new Error("pnpm version missing in package.json.");
|
|
51
|
-
}
|
|
52
|
-
return version;
|
|
53
|
-
}
|
|
54
|
-
async function getNodeVersionFromAction(monorepoRoot) {
|
|
55
|
-
const actionPath = path.join(monorepoRoot, GITHUB_ACTION_FILE_PATH);
|
|
56
|
-
const actionYaml = await fs.promises.readFile(actionPath, { encoding: "utf8" });
|
|
57
|
-
const action = yaml.load(actionYaml);
|
|
58
|
-
assert.ok(action, "Action YAML not found");
|
|
59
|
-
const version = getValueAtPathOrThrow(action, "jobs.code-quality.with.node-version");
|
|
60
|
-
assert.ok(typeof version === "string" && version.length > 0, "Node.js version not found in action");
|
|
61
|
-
return version;
|
|
62
|
-
}
|
|
63
|
-
function runConsistencyChecks() {
|
|
64
|
-
const monorepoRoot = findMonorepoRoot();
|
|
65
|
-
checkPnpmVersionConsistency(monorepoRoot);
|
|
66
|
-
checkNodeVersionConsistency(monorepoRoot);
|
|
67
|
-
}
|
|
68
|
-
export {
|
|
69
|
-
runConsistencyChecks
|
|
70
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getRuntimeVersionFromAsdf(runtime: string, monorepoRoot: string): Promise<string>;
|
|
@@ -1,15 +0,0 @@
|
|
|
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;
|
|
12
|
-
}
|
|
13
|
-
export {
|
|
14
|
-
getRuntimeVersionFromAsdf
|
|
15
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getValueAtPathOrThrow(obj: unknown, objPath: string): unknown;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
function isObject(value) {
|
|
2
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
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}"`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return current;
|
|
31
|
-
}
|
|
32
|
-
export {
|
|
33
|
-
getValueAtPathOrThrow
|
|
34
|
-
};
|