@konvert7/klint 0.9.0 → 0.11.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/cli.ts +107 -0
- package/core/native-binary.ts +95 -0
- package/package.json +12 -1
- package/tools/prepare-native-release.ts +162 -0
- package/tools/semantic-release-root-npm.js +52 -0
package/cli.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
2
3
|
import {
|
|
3
4
|
cpSync,
|
|
4
5
|
existsSync,
|
|
@@ -11,6 +12,7 @@ import { dirname, join, relative, resolve } from "node:path";
|
|
|
11
12
|
import * as clack from "@clack/prompts";
|
|
12
13
|
import { parse as parseYaml } from "yaml";
|
|
13
14
|
import { applyFixes } from "./core/fixer";
|
|
15
|
+
import { resolveNativePackageBinary } from "./core/native-binary";
|
|
14
16
|
import { runKlint } from "./core/runner";
|
|
15
17
|
import type { ArchConfig, KlintConfig, KlintRule, RuleConfigValue } from "./core/types";
|
|
16
18
|
import { BUILT_IN_PLUGINS } from "./plugins/index";
|
|
@@ -80,6 +82,12 @@ export async function main(opts: CliOptions = {}): Promise<void> {
|
|
|
80
82
|
process.exit(1);
|
|
81
83
|
}
|
|
82
84
|
const root = resolve(configDir, raw.root ?? ".");
|
|
85
|
+
const engine = process.env.KLINT_ENGINE;
|
|
86
|
+
|
|
87
|
+
if (engine === "rust") {
|
|
88
|
+
runRustEngine({ configDir, fix, json, raw, rulesFile });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
83
91
|
|
|
84
92
|
let customRules: Record<string, KlintRule> = {};
|
|
85
93
|
const defaultRulesPath = resolve(configDir, "klint.rules.ts");
|
|
@@ -174,6 +182,105 @@ export async function main(opts: CliOptions = {}): Promise<void> {
|
|
|
174
182
|
process.exit(0);
|
|
175
183
|
}
|
|
176
184
|
|
|
185
|
+
function runRustEngine({
|
|
186
|
+
configDir,
|
|
187
|
+
fix,
|
|
188
|
+
json,
|
|
189
|
+
raw,
|
|
190
|
+
rulesFile,
|
|
191
|
+
}: {
|
|
192
|
+
configDir: string;
|
|
193
|
+
fix: boolean;
|
|
194
|
+
json: boolean;
|
|
195
|
+
raw: {
|
|
196
|
+
plugins?: string[];
|
|
197
|
+
rules?: Record<string, RuleConfigValue>;
|
|
198
|
+
arch?: unknown;
|
|
199
|
+
};
|
|
200
|
+
rulesFile?: string;
|
|
201
|
+
}): void {
|
|
202
|
+
const unsupportedReason = rustEngineUnsupportedReason({
|
|
203
|
+
fix,
|
|
204
|
+
json,
|
|
205
|
+
raw,
|
|
206
|
+
rulesFile,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
if (unsupportedReason) {
|
|
210
|
+
process.stderr.write(`klint: ${unsupportedReason}\n`);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const command = resolveRustEngineCommand(configDir);
|
|
215
|
+
const result = spawnSync(command.bin, command.args, {
|
|
216
|
+
cwd: import.meta.dir,
|
|
217
|
+
encoding: "utf-8",
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
221
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
222
|
+
process.exit(result.status ?? 1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface RustEngineCommand {
|
|
226
|
+
bin: string;
|
|
227
|
+
args: string[];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function resolveRustEngineCommand(configDir: string): RustEngineCommand {
|
|
231
|
+
const args = ["--config", configDir, "--json"];
|
|
232
|
+
const explicitBin = process.env.KLINT_RUST_BIN;
|
|
233
|
+
if (explicitBin) {
|
|
234
|
+
return { bin: explicitBin, args };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const nativePackageBin = resolveNativePackageBinary({ packageRoot: import.meta.dir });
|
|
238
|
+
if (nativePackageBin) {
|
|
239
|
+
return { bin: nativePackageBin, args };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const localBin = join(
|
|
243
|
+
import.meta.dir,
|
|
244
|
+
"target",
|
|
245
|
+
"debug",
|
|
246
|
+
process.platform === "win32" ? "klint-rs.exe" : "klint-rs"
|
|
247
|
+
);
|
|
248
|
+
if (existsSync(localBin)) {
|
|
249
|
+
return { bin: localBin, args };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
bin: "cargo",
|
|
254
|
+
args: ["run", "--quiet", "-p", "klint-rs", "--", ...args],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function rustEngineUnsupportedReason({
|
|
259
|
+
fix,
|
|
260
|
+
json,
|
|
261
|
+
raw,
|
|
262
|
+
rulesFile,
|
|
263
|
+
}: {
|
|
264
|
+
fix: boolean;
|
|
265
|
+
json: boolean;
|
|
266
|
+
raw: {
|
|
267
|
+
plugins?: string[];
|
|
268
|
+
rules?: Record<string, RuleConfigValue>;
|
|
269
|
+
arch?: unknown;
|
|
270
|
+
};
|
|
271
|
+
rulesFile?: string;
|
|
272
|
+
}): string | undefined {
|
|
273
|
+
if (!json) return "KLINT_ENGINE=rust currently requires --json";
|
|
274
|
+
if (fix) return "KLINT_ENGINE=rust does not support --fix";
|
|
275
|
+
if (rulesFile) return "KLINT_ENGINE=rust does not support --rules";
|
|
276
|
+
if (!raw.arch) return "KLINT_ENGINE=rust requires an arch config";
|
|
277
|
+
if ((raw.plugins?.length ?? 0) > 0) return "KLINT_ENGINE=rust does not support plugins";
|
|
278
|
+
if (Object.values(raw.rules ?? {}).some((value) => value !== "off")) {
|
|
279
|
+
return "KLINT_ENGINE=rust does not support TypeScript rules";
|
|
280
|
+
}
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
|
|
177
284
|
const AGENT_TARGETS = [
|
|
178
285
|
{ value: "claude", label: "Claude Code" },
|
|
179
286
|
{ value: "opencode", label: "opencode" },
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
type NativePlatform = "darwin" | "linux" | "win32";
|
|
6
|
+
type NativeArch = "arm64" | "x64";
|
|
7
|
+
|
|
8
|
+
export interface NativePackage {
|
|
9
|
+
platform: NativePlatform;
|
|
10
|
+
arch: NativeArch;
|
|
11
|
+
packageName: string;
|
|
12
|
+
binaryPath: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const NATIVE_PACKAGES: Record<string, NativePackage> = {
|
|
16
|
+
"darwin-arm64": {
|
|
17
|
+
platform: "darwin",
|
|
18
|
+
arch: "arm64",
|
|
19
|
+
packageName: "@konvert7/klint-darwin-arm64",
|
|
20
|
+
binaryPath: "bin/klint-rs",
|
|
21
|
+
},
|
|
22
|
+
"darwin-x64": {
|
|
23
|
+
platform: "darwin",
|
|
24
|
+
arch: "x64",
|
|
25
|
+
packageName: "@konvert7/klint-darwin-x64",
|
|
26
|
+
binaryPath: "bin/klint-rs",
|
|
27
|
+
},
|
|
28
|
+
"linux-x64": {
|
|
29
|
+
platform: "linux",
|
|
30
|
+
arch: "x64",
|
|
31
|
+
packageName: "@konvert7/klint-linux-x64",
|
|
32
|
+
binaryPath: "bin/klint-rs",
|
|
33
|
+
},
|
|
34
|
+
"win32-x64": {
|
|
35
|
+
platform: "win32",
|
|
36
|
+
arch: "x64",
|
|
37
|
+
packageName: "@konvert7/klint-win32-x64",
|
|
38
|
+
binaryPath: "bin/klint-rs.exe",
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
interface NativeBinaryOptions {
|
|
43
|
+
packageRoot: string;
|
|
44
|
+
platform?: string;
|
|
45
|
+
arch?: string;
|
|
46
|
+
exists?: (path: string) => boolean;
|
|
47
|
+
resolvePackageJson?: (packageName: string) => string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function nativePackageForPlatform(
|
|
51
|
+
platform: string = process.platform,
|
|
52
|
+
arch: string = process.arch
|
|
53
|
+
): NativePackage | undefined {
|
|
54
|
+
return NATIVE_PACKAGES[`${platform}-${arch}`];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function nativePackages(): NativePackage[] {
|
|
58
|
+
return Object.values(NATIVE_PACKAGES);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function resolveNativePackageBinary({
|
|
62
|
+
packageRoot,
|
|
63
|
+
platform = process.platform,
|
|
64
|
+
arch = process.arch,
|
|
65
|
+
exists = existsSync,
|
|
66
|
+
resolvePackageJson,
|
|
67
|
+
}: NativeBinaryOptions): string | undefined {
|
|
68
|
+
const nativePackage = nativePackageForPlatform(platform, arch);
|
|
69
|
+
if (!nativePackage) return undefined;
|
|
70
|
+
|
|
71
|
+
const packageJsonPath = resolveOptionalPackageJson(
|
|
72
|
+
packageRoot,
|
|
73
|
+
nativePackage.packageName,
|
|
74
|
+
resolvePackageJson
|
|
75
|
+
);
|
|
76
|
+
if (!packageJsonPath) return undefined;
|
|
77
|
+
|
|
78
|
+
const binaryPath = join(dirname(packageJsonPath), nativePackage.binaryPath);
|
|
79
|
+
return exists(binaryPath) ? binaryPath : undefined;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveOptionalPackageJson(
|
|
83
|
+
packageRoot: string,
|
|
84
|
+
packageName: string,
|
|
85
|
+
resolvePackageJson?: (packageName: string) => string
|
|
86
|
+
): string | undefined {
|
|
87
|
+
try {
|
|
88
|
+
if (resolvePackageJson) return resolvePackageJson(packageName);
|
|
89
|
+
return createRequire(join(packageRoot, "package.json")).resolve(
|
|
90
|
+
`${packageName}/package.json`
|
|
91
|
+
);
|
|
92
|
+
} catch {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konvert7/klint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Architecture-as-Code linter for TypeScript. Enforce layer boundaries, import rules, and singleton patterns in YAML.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"type-check": "tsc --noEmit",
|
|
37
37
|
"test": "bun test",
|
|
38
|
+
"test:rust-engine": "bun test tests/rust-engine-cli.test.ts",
|
|
39
|
+
"pack:check": "bun tests/pack-check.ts",
|
|
40
|
+
"native:stage": "bun tests/stage-native-binary.ts",
|
|
41
|
+
"native:smoke": "bun tests/smoke-native-binary.ts",
|
|
42
|
+
"native:release:dry-run": "bun tools/prepare-native-release.ts --version 0.0.0-dry-run",
|
|
38
43
|
"check": "biome check",
|
|
39
44
|
"check-write": "biome check --write",
|
|
40
45
|
"knip": "knip-bun",
|
|
@@ -55,6 +60,12 @@
|
|
|
55
60
|
"yaml": "^2.9.0",
|
|
56
61
|
"zod": "^4.4.3"
|
|
57
62
|
},
|
|
63
|
+
"optionalDependencies": {
|
|
64
|
+
"@konvert7/klint-darwin-arm64": "*",
|
|
65
|
+
"@konvert7/klint-darwin-x64": "*",
|
|
66
|
+
"@konvert7/klint-linux-x64": "*",
|
|
67
|
+
"@konvert7/klint-win32-x64": "*"
|
|
68
|
+
},
|
|
58
69
|
"devDependencies": {
|
|
59
70
|
"@biomejs/biome": "2.4.7",
|
|
60
71
|
"@commitlint/cli": "^20.5.3",
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
mkdtempSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { tmpdir } from "node:os";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { nativePackages } from "../core/native-binary";
|
|
14
|
+
|
|
15
|
+
interface PackageJson {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
private?: boolean;
|
|
19
|
+
optionalDependencies?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface Options {
|
|
23
|
+
version: string;
|
|
24
|
+
outDir: string;
|
|
25
|
+
requireBinaries: boolean;
|
|
26
|
+
keep: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const root = fileURLToPath(new URL("..", import.meta.url));
|
|
30
|
+
const options = parseArgs();
|
|
31
|
+
|
|
32
|
+
if (existsSync(options.outDir)) {
|
|
33
|
+
rmSync(options.outDir, { recursive: true, force: true });
|
|
34
|
+
}
|
|
35
|
+
mkdirSync(options.outDir, { recursive: true });
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const releaseRootPackageJson = prepareRootPackageJson();
|
|
39
|
+
const nativeResults = nativePackages().map(prepareNativePackage);
|
|
40
|
+
|
|
41
|
+
validateRootPackageJson(releaseRootPackageJson);
|
|
42
|
+
for (const result of nativeResults) validateNativePackage(result.packageJson);
|
|
43
|
+
|
|
44
|
+
const missing = nativeResults
|
|
45
|
+
.filter((result) => !result.binaryCopied)
|
|
46
|
+
.map((result) => result.packageJson.name);
|
|
47
|
+
|
|
48
|
+
if (options.requireBinaries && missing.length > 0) {
|
|
49
|
+
fail(`Missing native release binaries:\n${missing.join("\n")}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
process.stdout.write(
|
|
53
|
+
`${[
|
|
54
|
+
`native release dry-run ok (${options.version})`,
|
|
55
|
+
`output: ${options.outDir}`,
|
|
56
|
+
`native packages: ${nativeResults.length}`,
|
|
57
|
+
missing.length > 0
|
|
58
|
+
? `missing binaries: ${missing.join(", ")}`
|
|
59
|
+
: "missing binaries: none",
|
|
60
|
+
].join("\n")}\n`
|
|
61
|
+
);
|
|
62
|
+
} finally {
|
|
63
|
+
if (!options.keep) {
|
|
64
|
+
rmSync(options.outDir, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function prepareRootPackageJson(): PackageJson {
|
|
69
|
+
const packageJson = readPackageJson(join(root, "package.json"));
|
|
70
|
+
packageJson.version = options.version;
|
|
71
|
+
packageJson.optionalDependencies = Object.fromEntries(
|
|
72
|
+
nativePackages().map((nativePackage) => [nativePackage.packageName, options.version])
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const outPath = join(options.outDir, "package.json");
|
|
76
|
+
writeJson(outPath, packageJson);
|
|
77
|
+
return packageJson;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function prepareNativePackage(nativePackage: ReturnType<typeof nativePackages>[number]): {
|
|
81
|
+
binaryCopied: boolean;
|
|
82
|
+
packageJson: PackageJson;
|
|
83
|
+
} {
|
|
84
|
+
const packageDirName = `${nativePackage.platform}-${nativePackage.arch}`;
|
|
85
|
+
const sourceDir = join(root, "npm", "native", packageDirName);
|
|
86
|
+
const outDir = join(options.outDir, "npm", "native", packageDirName);
|
|
87
|
+
mkdirSync(outDir, { recursive: true });
|
|
88
|
+
|
|
89
|
+
const packageJson = readPackageJson(join(sourceDir, "package.json"));
|
|
90
|
+
packageJson.version = options.version;
|
|
91
|
+
packageJson.private = false;
|
|
92
|
+
writeJson(join(outDir, "package.json"), packageJson);
|
|
93
|
+
|
|
94
|
+
const sourceBinary = join(sourceDir, nativePackage.binaryPath);
|
|
95
|
+
const outBinary = join(outDir, nativePackage.binaryPath);
|
|
96
|
+
const binaryCopied = existsSync(sourceBinary);
|
|
97
|
+
if (binaryCopied) {
|
|
98
|
+
mkdirSync(dirname(outBinary), { recursive: true });
|
|
99
|
+
copyFileSync(sourceBinary, outBinary);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { binaryCopied, packageJson };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function validateRootPackageJson(packageJson: PackageJson): void {
|
|
106
|
+
const optionalDependencies = packageJson.optionalDependencies ?? {};
|
|
107
|
+
for (const nativePackage of nativePackages()) {
|
|
108
|
+
if (optionalDependencies[nativePackage.packageName] !== options.version) {
|
|
109
|
+
fail(
|
|
110
|
+
`Root optional dependency ${nativePackage.packageName} is not pinned to ${options.version}`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function validateNativePackage(packageJson: PackageJson): void {
|
|
117
|
+
if (packageJson.version !== options.version) {
|
|
118
|
+
fail(
|
|
119
|
+
`${packageJson.name} version is ${packageJson.version}, expected ${options.version}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
if (packageJson.private !== false) {
|
|
123
|
+
fail(`${packageJson.name} private must be false in release prep output`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function readPackageJson(path: string): PackageJson {
|
|
128
|
+
return JSON.parse(readFileSync(path, "utf-8")) as PackageJson;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function writeJson(path: string, value: unknown): void {
|
|
132
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function parseArgs(): Options {
|
|
136
|
+
const args = process.argv.slice(2);
|
|
137
|
+
const version = valueAfter(args, "--version");
|
|
138
|
+
if (!version) {
|
|
139
|
+
fail(
|
|
140
|
+
"Usage: bun tools/prepare-native-release.ts --version <version> [--out <dir>] [--require-binaries] [--keep]"
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
version,
|
|
146
|
+
outDir: resolve(
|
|
147
|
+
valueAfter(args, "--out") ?? mkdtempSync(join(tmpdir(), "klint-native-release-"))
|
|
148
|
+
),
|
|
149
|
+
requireBinaries: args.includes("--require-binaries"),
|
|
150
|
+
keep: args.includes("--keep"),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function valueAfter(args: string[], name: string): string | undefined {
|
|
155
|
+
const index = args.indexOf(name);
|
|
156
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function fail(message: string): never {
|
|
160
|
+
process.stderr.write(`${message}\n`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
export async function verifyConditions(_, context) {
|
|
6
|
+
const cwd = context.cwd ?? process.cwd();
|
|
7
|
+
const packageJson = readPackageJson(cwd);
|
|
8
|
+
|
|
9
|
+
if (!packageJson.name) {
|
|
10
|
+
throw new Error("Root package.json must have a name before npm publish");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function prepare(_, context) {
|
|
15
|
+
const cwd = context.cwd ?? process.cwd();
|
|
16
|
+
const version = context.nextRelease?.version;
|
|
17
|
+
|
|
18
|
+
if (!version) {
|
|
19
|
+
throw new Error("semantic-release did not provide nextRelease.version");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const packageJson = readPackageJson(cwd);
|
|
23
|
+
packageJson.version = version;
|
|
24
|
+
writePackageJson(cwd, packageJson);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function publish(_, context) {
|
|
28
|
+
const cwd = context.cwd ?? process.cwd();
|
|
29
|
+
|
|
30
|
+
if (context.options?.dryRun) {
|
|
31
|
+
context.logger?.log("Dry run: skipping npm publish");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const result = spawnSync("npm", ["publish", "--access", "public"], {
|
|
36
|
+
cwd,
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
stdio: "inherit",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if ((result.status ?? -1) !== 0) {
|
|
42
|
+
throw new Error(`npm publish failed with exit code ${result.status ?? -1}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readPackageJson(cwd) {
|
|
47
|
+
return JSON.parse(readFileSync(join(cwd, "package.json"), "utf-8"));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function writePackageJson(cwd, packageJson) {
|
|
51
|
+
writeFileSync(join(cwd, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
52
|
+
}
|