@williamthorsen/nmr 2.0.0 → 2.0.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/.meta/changelog.json +164 -0
- package/.readyup/kits/default.js +51 -15
- package/.readyup/manifest.json +26 -21
- package/CHANGELOG.md +45 -0
- package/README.md +10 -4
- package/dist/esm/{check-cache-build-output.d.ts → check-cache/check-cache-build-output.d.ts} +1 -1
- package/dist/esm/{check-cache-build-output.js → check-cache/check-cache-build-output.js} +6 -6
- package/dist/esm/{check-cache-delegation.d.ts → check-cache/check-cache-delegation.d.ts} +3 -3
- package/dist/esm/{check-cache-delegation.js → check-cache/check-cache-delegation.js} +2 -2
- package/dist/esm/{check-cache-entries.js → check-cache/check-cache-entries.js} +1 -1
- package/dist/esm/{check-cache-gate.d.ts → check-cache/check-cache-gate.d.ts} +5 -4
- package/dist/esm/{check-cache-gate.js → check-cache/check-cache-gate.js} +10 -10
- package/dist/esm/{check-cache-key.d.ts → check-cache/check-cache-key.d.ts} +1 -1
- package/dist/esm/{check-cache-record.d.ts → check-cache/check-cache-record.d.ts} +6 -5
- package/dist/esm/{check-cache-record.js → check-cache/check-cache-record.js} +7 -6
- package/dist/esm/{check-cache.d.ts → check-cache/check-cache.d.ts} +10 -2
- package/dist/esm/{check-cache.js → check-cache/check-cache.js} +7 -4
- package/dist/esm/{config-check-cache.d.ts → check-cache/config-check-cache.d.ts} +1 -1
- package/dist/esm/{config-check-cache.js → check-cache/config-check-cache.js} +4 -4
- package/dist/esm/{pass-manifest.d.ts → check-cache/pass-manifest.d.ts} +1 -1
- package/dist/esm/{pass-manifest.js → check-cache/pass-manifest.js} +1 -1
- package/dist/esm/{recording.js → check-cache/recording.js} +2 -2
- package/dist/esm/{replay-assembly.d.ts → check-cache/replay-assembly.d.ts} +1 -1
- package/dist/esm/{replay-assembly.js → check-cache/replay-assembly.js} +2 -2
- package/dist/esm/child-env.d.ts +1 -1
- package/dist/esm/child-env.js +2 -2
- package/dist/esm/cli-build.js +3 -10
- package/dist/esm/cli-clean.js +1 -2
- package/dist/esm/cli-report-catalog.js +2 -3
- package/dist/esm/cli-report-overrides.js +3 -5
- package/dist/esm/commands/actionlint.d.ts +2 -7
- package/dist/esm/commands/actionlint.js +5 -11
- package/dist/esm/commands/build-output.d.ts +7 -32
- package/dist/esm/commands/build-output.js +8 -13
- package/dist/esm/commands/build-report.d.ts +6 -0
- package/dist/esm/commands/build-report.js +21 -0
- package/dist/esm/commands/build.d.ts +27 -4
- package/dist/esm/commands/build.js +24 -86
- package/dist/esm/commands/clean-report.d.ts +6 -0
- package/dist/esm/commands/clean-report.js +20 -0
- package/dist/esm/commands/clean.d.ts +39 -7
- package/dist/esm/commands/clean.js +55 -31
- package/dist/esm/commands/compile.d.ts +5 -0
- package/dist/esm/commands/compile.js +32 -0
- package/dist/esm/commands/fmt-cache.js +3 -2
- package/dist/esm/commands/fmt.d.ts +6 -2
- package/dist/esm/commands/fmt.js +48 -27
- package/dist/esm/commands/node-pin.d.ts +15 -5
- package/dist/esm/commands/node-pin.js +43 -10
- package/dist/esm/commands/package-manifest.d.ts +28 -0
- package/dist/esm/commands/package-manifest.js +32 -0
- package/dist/esm/commands/publish-output.d.ts +40 -0
- package/dist/esm/commands/publish-output.js +66 -0
- package/dist/esm/commands/report-catalog.d.ts +5 -0
- package/dist/esm/commands/report-catalog.js +19 -0
- package/dist/esm/commands/report-overrides.d.ts +5 -0
- package/dist/esm/commands/report-overrides.js +20 -1
- package/dist/esm/commands/run-vitest.js +21 -20
- package/dist/esm/commands/shellcheck.d.ts +2 -7
- package/dist/esm/commands/shellcheck.js +3 -11
- package/dist/esm/commands/spawn-inherited.d.ts +21 -0
- package/dist/esm/commands/spawn-inherited.js +11 -0
- package/dist/esm/commands/taze.d.ts +6 -6
- package/dist/esm/commands/taze.js +3 -7
- package/dist/esm/config-validation.js +1 -1
- package/dist/esm/config.js +3 -12
- package/dist/esm/{delegate-host.d.ts → delegation/delegate-host.d.ts} +3 -3
- package/dist/esm/{delegate-host.js → delegation/delegate-host.js} +9 -8
- package/dist/esm/{delegation-target.js → delegation/delegation-target.js} +1 -1
- package/dist/esm/{remote-probe.js → delegation/remote-probe.js} +2 -2
- package/dist/esm/{remote-run.js → delegation/remote-run.js} +5 -5
- package/dist/esm/{remote-session.js → delegation/remote-session.js} +1 -1
- package/dist/esm/{user-config.js → delegation/user-config.js} +4 -13
- package/dist/esm/env-switch.d.ts +25 -0
- package/dist/esm/env-switch.js +26 -0
- package/dist/esm/fan-out.d.ts +4 -1
- package/dist/esm/fan-out.js +1 -3
- package/dist/esm/help.js +1 -1
- package/dist/esm/helpers/filter-selection.d.ts +2 -0
- package/dist/esm/helpers/importConfigDefault.d.ts +7 -0
- package/dist/esm/helpers/importConfigDefault.js +45 -0
- package/dist/esm/invocation.d.ts +7 -3
- package/dist/esm/machine-lock.js +2 -1
- package/dist/esm/route.d.ts +6 -0
- package/dist/esm/route.js +15 -2
- package/dist/esm/run-chain.d.ts +1 -1
- package/dist/esm/run-chain.js +1 -1
- package/dist/esm/runCli.d.ts +9 -0
- package/dist/esm/runCli.js +24 -9
- package/dist/esm/runner.d.ts +2 -0
- package/dist/esm/runner.js +1 -1
- package/dist/esm/verdict.d.ts +1 -1
- package/docs/check-cache.md +7 -7
- package/docs/delegate.md +2 -2
- package/docs/machine-lock.md +4 -4
- package/docs/scripts.md +4 -0
- package/docs/upgrades.md +10 -2
- package/docs/utilities.md +6 -4
- package/package.json +7 -7
- /package/dist/esm/{check-cache-entries.d.ts → check-cache/check-cache-entries.d.ts} +0 -0
- /package/dist/esm/{check-cache-key.js → check-cache/check-cache-key.js} +0 -0
- /package/dist/esm/{recording.d.ts → check-cache/recording.d.ts} +0 -0
- /package/dist/esm/{delegation-target.d.ts → delegation/delegation-target.d.ts} +0 -0
- /package/dist/esm/{remote-host-session.d.ts → delegation/remote-host-session.d.ts} +0 -0
- /package/dist/esm/{remote-host-session.js → delegation/remote-host-session.js} +0 -0
- /package/dist/esm/{remote-probe-host.d.ts → delegation/remote-probe-host.d.ts} +0 -0
- /package/dist/esm/{remote-probe-host.js → delegation/remote-probe-host.js} +0 -0
- /package/dist/esm/{remote-probe.d.ts → delegation/remote-probe.d.ts} +0 -0
- /package/dist/esm/{remote-run.d.ts → delegation/remote-run.d.ts} +0 -0
- /package/dist/esm/{remote-session.d.ts → delegation/remote-session.d.ts} +0 -0
- /package/dist/esm/{remote-snapshot.d.ts → delegation/remote-snapshot.d.ts} +0 -0
- /package/dist/esm/{remote-snapshot.js → delegation/remote-snapshot.js} +0 -0
- /package/dist/esm/{user-config.d.ts → delegation/user-config.d.ts} +0 -0
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
|
-
import { readFile
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
7
|
-
import { glob } from 'glob';
|
|
8
|
-
import { NMR_GLYPHS } from "../glyphs.js";
|
|
5
|
+
import { readCacheEntry, startTimer, UserError, writeCacheEntry } from '@williamthorsen/nmr-core';
|
|
9
6
|
import { resolveConfigPath } from "../helpers/config-path.js";
|
|
10
|
-
import { formatSaving } from "../helpers/duration.js";
|
|
11
7
|
import { writeStatedOutcome } from "../stated-outcome.js";
|
|
12
|
-
import {
|
|
8
|
+
import { DEFAULT_OUTDIR, hasExpectedBuildOutput, readEmitDuration, resolveBuildCachePath, resolveEntryPoints, resolveToolchainFingerprint, writeEmitDuration, } from "./build-output.js";
|
|
13
9
|
import { assertSupportedTypeScript, formatDiagnostics, getCompiler, loadCompiler } from "./compiler.js";
|
|
14
|
-
import {
|
|
10
|
+
import { discardScratchDirs, publishOutput, removeScratchDirs } from "./publish-output.js";
|
|
11
|
+
import { rewriteSpecifiers } from "./rewrite-specifiers.js";
|
|
15
12
|
import { resolveTsconfigChain } from "./tsconfig-chain.js";
|
|
16
13
|
const SOURCE_ROOT = 'src';
|
|
17
|
-
export async function buildPackage(packageDir, options) {
|
|
14
|
+
export async function buildPackage(packageDir, options = {}) {
|
|
18
15
|
await loadCompiler(options.loadTypeScript);
|
|
19
16
|
assertSupportedTypeScript();
|
|
20
17
|
const cachePath = resolveBuildCachePath(packageDir);
|
|
21
18
|
const outdir = options.outdir ?? DEFAULT_OUTDIR;
|
|
22
19
|
const emitDir = resolveEmitDir(packageDir, outdir);
|
|
23
20
|
const emitConfig = { outdir, declaration: true, rewriteRelativeImportExtensions: true };
|
|
24
|
-
const entryPoints = await
|
|
25
|
-
cwd: packageDir,
|
|
26
|
-
ignore: [...(options.ignorePatterns ?? DEFAULT_IGNORE_PATTERNS), ...(options.extraIgnorePatterns ?? [])],
|
|
27
|
-
});
|
|
21
|
+
const entryPoints = await resolveEntryPoints(packageDir, options);
|
|
28
22
|
const configPath = resolveConfigPath(packageDir);
|
|
29
23
|
const dependencies = [
|
|
30
24
|
'package.json',
|
|
@@ -35,17 +29,19 @@ export async function buildPackage(packageDir, options) {
|
|
|
35
29
|
compilerVersion: getCompiler().version,
|
|
36
30
|
fingerprint: await resolveToolchainFingerprint(packageDir),
|
|
37
31
|
};
|
|
38
|
-
const {
|
|
39
|
-
if (
|
|
40
|
-
await discardScratchDirs(
|
|
41
|
-
|
|
32
|
+
const { reason, currentHash } = await detectBuildChanges(packageDir, [...entryPoints, ...dependencies], emitConfig, toolchain, cachePath, hasExpectedBuildOutput(packageDir, outdir, entryPoints));
|
|
33
|
+
if (reason === 'unchanged') {
|
|
34
|
+
await discardScratchDirs(emitDir);
|
|
35
|
+
const savedMs = await recordUnchangedBuild(packageDir, currentHash, process.env);
|
|
36
|
+
return { kind: 'unchanged', ...(savedMs !== undefined && { savedMs }) };
|
|
42
37
|
}
|
|
38
|
+
options.onProgress?.({ kind: reason });
|
|
43
39
|
const readEmitMs = startTimer();
|
|
44
40
|
const emittedFileCount = await emitPackage(packageDir, entryPoints, outdir);
|
|
45
41
|
const emitMs = readEmitMs();
|
|
46
42
|
await writeCacheEntry(cachePath, currentHash);
|
|
47
43
|
await writeEmitDuration(packageDir, currentHash, emitMs);
|
|
48
|
-
|
|
44
|
+
return { kind: 'emitted', fileCount: emittedFileCount, outdir };
|
|
49
45
|
}
|
|
50
46
|
export async function computeBuildHash(packageDir, files, emitConfig, toolchain) {
|
|
51
47
|
const hash = createHash('sha256');
|
|
@@ -67,8 +63,7 @@ async function emitPackage(packageDir, entryPoints, outdir) {
|
|
|
67
63
|
const rootNames = entryPoints.map((entry) => path.resolve(packageDir, entry));
|
|
68
64
|
const sourceRoot = path.resolve(packageDir, SOURCE_ROOT);
|
|
69
65
|
const emitDir = resolveEmitDir(packageDir, outdir);
|
|
70
|
-
|
|
71
|
-
await removeScratchDirs(scratchDirs);
|
|
66
|
+
await removeScratchDirs(emitDir);
|
|
72
67
|
const emittedFiles = new Map();
|
|
73
68
|
function collect(fileName, text, writeByteOrderMark) {
|
|
74
69
|
emittedFiles.set(fileName, { text, writeByteOrderMark });
|
|
@@ -82,13 +77,7 @@ async function emitPackage(packageDir, entryPoints, outdir) {
|
|
|
82
77
|
for (const [fileName, file] of emittedFiles) {
|
|
83
78
|
stagedFiles.set(fileName, { ...file, text: rewriteSpecifiers(fileName, file.text, compilerOptions, sourceRoot) });
|
|
84
79
|
}
|
|
85
|
-
|
|
86
|
-
await rm(emitDir, { force: true, recursive: true });
|
|
87
|
-
return 0;
|
|
88
|
-
}
|
|
89
|
-
writeStagedOutput(stagedFiles, emitDir, scratchDirs.stagingDir);
|
|
90
|
-
await swapIntoPlace(emitDir, scratchDirs);
|
|
91
|
-
return stagedFiles.size;
|
|
80
|
+
return publishOutput(emitDir, stagedFiles);
|
|
92
81
|
}
|
|
93
82
|
function assertEmitSucceeded(result) {
|
|
94
83
|
if (result.emitSkipped) {
|
|
@@ -110,17 +99,6 @@ function createCachingCompilerHost(compilerOptions) {
|
|
|
110
99
|
};
|
|
111
100
|
return host;
|
|
112
101
|
}
|
|
113
|
-
async function discardScratchDirs(scratchDirs) {
|
|
114
|
-
try {
|
|
115
|
-
await removeScratchDirs(scratchDirs);
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function removeScratchDirs(scratchDirs) {
|
|
121
|
-
await rm(scratchDirs.previousDir, { force: true, recursive: true });
|
|
122
|
-
await rm(scratchDirs.stagingDir, { force: true, recursive: true });
|
|
123
|
-
}
|
|
124
102
|
function resolveEmitDir(packageDir, outdir) {
|
|
125
103
|
const resolvedDir = path.resolve(packageDir, outdir);
|
|
126
104
|
const relativePathFromPackage = path.relative(packageDir, resolvedDir);
|
|
@@ -132,24 +110,6 @@ function resolveEmitDir(packageDir, outdir) {
|
|
|
132
110
|
}
|
|
133
111
|
return resolvedDir;
|
|
134
112
|
}
|
|
135
|
-
async function swapIntoPlace(emitDir, scratchDirs) {
|
|
136
|
-
const hadPreviousOutput = existsSync(emitDir);
|
|
137
|
-
if (hadPreviousOutput) {
|
|
138
|
-
await rename(emitDir, scratchDirs.previousDir);
|
|
139
|
-
}
|
|
140
|
-
try {
|
|
141
|
-
await rename(scratchDirs.stagingDir, emitDir);
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
if (hadPreviousOutput && !existsSync(emitDir)) {
|
|
145
|
-
await rename(scratchDirs.previousDir, emitDir);
|
|
146
|
-
}
|
|
147
|
-
throw new UserError(`failed to move the built output into ${emitDir}: ${describeError(error)}`, {
|
|
148
|
-
cause: error,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
await discardScratchDirs(scratchDirs);
|
|
152
|
-
}
|
|
153
113
|
function synthesizeCompilerOptions(packageDir, outdir) {
|
|
154
114
|
const ts = getCompiler();
|
|
155
115
|
const configPath = path.join(packageDir, 'tsconfig.json');
|
|
@@ -176,38 +136,16 @@ function synthesizeCompilerOptions(packageDir, outdir) {
|
|
|
176
136
|
noEmitOnError: false,
|
|
177
137
|
};
|
|
178
138
|
}
|
|
179
|
-
function
|
|
180
|
-
const ts = getCompiler();
|
|
181
|
-
for (const [fileName, file] of stagedFiles) {
|
|
182
|
-
if (!isWithin(emitDir, fileName)) {
|
|
183
|
-
throw new Error(`the compiler emitted ${fileName}, which is outside the output directory ${emitDir}. ` +
|
|
184
|
-
"Verify the resolved tsconfig's 'outDir' and 'declarationDir'.");
|
|
185
|
-
}
|
|
186
|
-
ts.sys.writeFile(path.join(stagingDir, path.relative(emitDir, fileName)), file.text, file.writeByteOrderMark);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
async function detectBuildChanges(packageDir, files, emitConfig, toolchain, cachePath, isOutputPresent, style) {
|
|
190
|
-
const packageName = path.basename(packageDir);
|
|
139
|
+
async function detectBuildChanges(packageDir, files, emitConfig, toolchain, cachePath, isOutputPresent) {
|
|
191
140
|
const previousHash = await readCacheEntry(cachePath);
|
|
192
141
|
const currentHash = await computeBuildHash(packageDir, files, emitConfig, toolchain);
|
|
193
|
-
if (previousHash
|
|
194
|
-
|
|
195
|
-
const savedMs = await readEmitDuration(packageDir, currentHash);
|
|
196
|
-
await writeStatedOutcome(process.env, { kind: 'build-unchanged', ...(savedMs !== undefined && { savedMs }) });
|
|
197
|
-
const saving = formatSaving(savedMs ?? 0);
|
|
198
|
-
const savingClause = saving === undefined ? '' : `, ${saving}`;
|
|
199
|
-
console.info(`${STATUS_GLYPHS[style].skipped.text} ${packageName}: No changes detected. Skipping build${savingClause}.`);
|
|
200
|
-
return { changed: false, currentHash };
|
|
201
|
-
}
|
|
202
|
-
console.info(formatGlyphLine(NMR_GLYPHS, style, 'package', `${packageName}: Build output is missing. Rebuilding.`));
|
|
203
|
-
return { changed: true, currentHash };
|
|
142
|
+
if (previousHash !== currentHash) {
|
|
143
|
+
return { reason: 'inputs-changed', currentHash };
|
|
204
144
|
}
|
|
205
|
-
|
|
206
|
-
return { changed: true, currentHash };
|
|
145
|
+
return { reason: isOutputPresent ? 'unchanged' : 'output-missing', currentHash };
|
|
207
146
|
}
|
|
208
|
-
function
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return `Compiled ${fileCount} files to ${outdir.replace(/\/+$/u, '')}.`;
|
|
147
|
+
export async function recordUnchangedBuild(packageDir, digest, env) {
|
|
148
|
+
const savedMs = await readEmitDuration(packageDir, digest);
|
|
149
|
+
await writeStatedOutcome(env, { kind: 'build-unchanged', ...(savedMs !== undefined && { savedMs }) });
|
|
150
|
+
return savedMs;
|
|
213
151
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type OutputStyle } from '@williamthorsen/nmr-core';
|
|
2
|
+
import type { CleanOutcome, CleanProgress } from './clean.js';
|
|
3
|
+
/** Renders the line that closes a sweep, or `undefined` for a one-package clean, whose own line concludes it. */
|
|
4
|
+
export declare function renderCleanOutcome(outcome: CleanOutcome, style: OutputStyle): string | undefined;
|
|
5
|
+
/** Renders the line that reports a completed step of a clean. */
|
|
6
|
+
export declare function renderCleanProgress(progress: CleanProgress, style: OutputStyle): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { formatGlyphLine } from '@williamthorsen/nmr-core';
|
|
3
|
+
import { NMR_GLYPHS } from "../glyphs.js";
|
|
4
|
+
export function renderCleanOutcome(outcome, style) {
|
|
5
|
+
if (outcome.kind === 'package') {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
return formatGlyphLine(NMR_GLYPHS, style, 'clean', describeSweep(outcome.cleanedDirs.length, outcome.skippedCount));
|
|
9
|
+
}
|
|
10
|
+
export function renderCleanProgress(progress, style) {
|
|
11
|
+
const message = progress.kind === 'check-results-removed'
|
|
12
|
+
? 'Removed all recorded check results.'
|
|
13
|
+
: `${path.basename(progress.packageDir)}: Removed build output and cache.`;
|
|
14
|
+
return formatGlyphLine(NMR_GLYPHS, style, 'clean', message);
|
|
15
|
+
}
|
|
16
|
+
function describeSweep(cleanedCount, skippedCount) {
|
|
17
|
+
const packages = cleanedCount === 1 ? '1 package' : `${cleanedCount} packages`;
|
|
18
|
+
const skipClause = skippedCount === 0 ? '' : `, skipping ${skippedCount} with an empty clean override`;
|
|
19
|
+
return `Cleaned ${packages}${skipClause}.`;
|
|
20
|
+
}
|
|
@@ -1,18 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
2
|
+
/** What a clean did: one package's clean, or a sweep of every workspace package. */
|
|
3
|
+
export type CleanOutcome = {
|
|
4
|
+
kind: 'package';
|
|
5
|
+
checkResultsDir: string;
|
|
6
|
+
packageDir: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'sweep';
|
|
9
|
+
checkResultsDir: string;
|
|
10
|
+
cleanedDirs: string[];
|
|
11
|
+
skippedCount: number;
|
|
12
|
+
};
|
|
13
|
+
/** A step of a clean, reported as soon as it completes. */
|
|
14
|
+
export type CleanProgress = {
|
|
15
|
+
kind: 'check-results-removed';
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'package-cleaned';
|
|
18
|
+
packageDir: string;
|
|
19
|
+
};
|
|
20
|
+
/** What a clean needs from its caller: a listener for its progress, and the streams for an override's output. */
|
|
21
|
+
export interface CleanOptions {
|
|
22
|
+
/** Called after each step completes, so that a caller can report it before a later override runs or fails. */
|
|
23
|
+
onProgress?: (progress: CleanProgress) => void;
|
|
24
|
+
/** The stream to which a package's own `clean` override writes its errors. */
|
|
25
|
+
stderr: Writable;
|
|
26
|
+
/** The stream to which a package's own `clean` override writes its output. */
|
|
27
|
+
stdout: Writable;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Cleans the package containing `cwd`, or every workspace package when run from the monorepo root.
|
|
31
|
+
*
|
|
32
|
+
* From within a package this is the built-in clean itself: `nmr` has already resolved `clean` to `nmr-clean`
|
|
33
|
+
* before invoking it, so resolving again would apply the package's own override twice.
|
|
34
|
+
*/
|
|
35
|
+
export declare function cleanFrom(cwd: string, options: CleanOptions): Promise<CleanOutcome>;
|
|
2
36
|
/**
|
|
3
37
|
* Removes a package's build output and the build-cache entries that describe it, so the package does not keep
|
|
4
38
|
* any state that would make the next build skip. Removal is idempotent: An already-clean package is a silent
|
|
5
39
|
* no-op.
|
|
6
40
|
*/
|
|
7
|
-
export declare function cleanPackage(packageDir: string
|
|
41
|
+
export declare function cleanPackage(packageDir: string): Promise<void>;
|
|
8
42
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* From within a package this is the built-in clean itself: `nmr` has already resolved `clean` to this bin
|
|
12
|
-
* before invoking it, so resolving again would apply the package's own override twice.
|
|
43
|
+
* Runs `nmr-clean` against `argv` from `cwd` and returns the exit code to report. The command takes neither an
|
|
44
|
+
* option nor an operand, so anything but `--help` is a usage error and removes nothing.
|
|
13
45
|
*
|
|
14
46
|
* This is the default `clean` script, and it is published as a bin because, under pnpm's isolated layout,
|
|
15
47
|
* `pnpm exec` resolves only the bins of the consuming project's direct dependencies: pnpm links nmr's own bins
|
|
16
48
|
* into the consumer's `node_modules/.bin`, but not the bins of nmr's dependencies.
|
|
17
49
|
*/
|
|
18
|
-
export declare function runClean(
|
|
50
|
+
export declare function runClean(argv: string[], cwd: string): Promise<number>;
|
|
@@ -1,59 +1,81 @@
|
|
|
1
1
|
import { rm } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { UserError } from '@williamthorsen/nmr-core';
|
|
5
|
+
import { defineCommand, runCli } from '@williamthorsen/nmr-core/cli';
|
|
4
6
|
import { NMR_CLEAN_BIN } from "../bins.js";
|
|
5
|
-
import { removeCheckCache } from "../check-cache-entries.js";
|
|
7
|
+
import { removeCheckCache } from "../check-cache/check-cache-entries.js";
|
|
6
8
|
import { loadRootConfig } from "../config.js";
|
|
7
9
|
import { findContainingPackageDir } from "../context.js";
|
|
8
|
-
import { NMR_GLYPHS } from "../glyphs.js";
|
|
9
10
|
import { reportClosing } from "../helpers/reportClosing.js";
|
|
10
11
|
import { resolveChannel } from "../output-channel.js";
|
|
12
|
+
import { resolveBinStyles } from "../resolveBinStyles.js";
|
|
11
13
|
import { buildWorkspaceRegistry, resolveScript } from "../resolver.js";
|
|
12
14
|
import { runCommand } from "../runner.js";
|
|
13
15
|
import { renderChain } from "../steps.js";
|
|
14
16
|
import { findMonorepoRoot, getWorkspacePackageDirs } from "../workspace.js";
|
|
15
17
|
import { resolveBuildCachePath, resolveEmitDurationPath } from "./build-output.js";
|
|
18
|
+
import { renderCleanOutcome, renderCleanProgress } from "./clean-report.js";
|
|
16
19
|
const CLEAN_COMMAND = 'clean';
|
|
17
20
|
const BUILT_IN_CLEAN = 'nmr-clean';
|
|
18
21
|
const OUTPUT_ROOT = 'dist';
|
|
19
|
-
export async function
|
|
20
|
-
await rm(path.resolve(packageDir, OUTPUT_ROOT), { recursive: true, force: true });
|
|
21
|
-
await rm(resolveBuildCachePath(packageDir), { force: true });
|
|
22
|
-
await rm(resolveEmitDurationPath(packageDir), { force: true });
|
|
23
|
-
console.info(formatGlyphLine(NMR_GLYPHS, style, 'clean', `${path.basename(packageDir)}: Removed build output and cache.`));
|
|
24
|
-
}
|
|
25
|
-
export async function runClean(cwd, style) {
|
|
22
|
+
export async function cleanFrom(cwd, options) {
|
|
26
23
|
let monorepoRoot;
|
|
27
24
|
try {
|
|
28
25
|
monorepoRoot = findMonorepoRoot(cwd);
|
|
29
26
|
}
|
|
30
27
|
catch {
|
|
31
|
-
await clearCheckCache(cwd,
|
|
32
|
-
await
|
|
33
|
-
return;
|
|
28
|
+
await clearCheckCache(cwd, options);
|
|
29
|
+
await cleanReportedPackage(cwd, options);
|
|
30
|
+
return { kind: 'package', checkResultsDir: cwd, packageDir: cwd };
|
|
34
31
|
}
|
|
35
|
-
await clearCheckCache(monorepoRoot,
|
|
32
|
+
await clearCheckCache(monorepoRoot, options);
|
|
36
33
|
const workspacePackageDirs = getWorkspacePackageDirs(monorepoRoot);
|
|
37
34
|
const packageDir = findContainingPackageDir(cwd, workspacePackageDirs);
|
|
38
35
|
if (packageDir !== undefined) {
|
|
39
|
-
await
|
|
40
|
-
return;
|
|
36
|
+
await cleanReportedPackage(packageDir, options);
|
|
37
|
+
return { kind: 'package', checkResultsDir: monorepoRoot, packageDir };
|
|
41
38
|
}
|
|
42
|
-
|
|
39
|
+
return sweepWorkspace(monorepoRoot, workspacePackageDirs, options);
|
|
43
40
|
}
|
|
44
|
-
async function
|
|
45
|
-
await
|
|
46
|
-
|
|
41
|
+
export async function cleanPackage(packageDir) {
|
|
42
|
+
await rm(path.resolve(packageDir, OUTPUT_ROOT), { recursive: true, force: true });
|
|
43
|
+
await rm(resolveBuildCachePath(packageDir), { force: true });
|
|
44
|
+
await rm(resolveEmitDurationPath(packageDir), { force: true });
|
|
45
|
+
}
|
|
46
|
+
export async function runClean(argv, cwd) {
|
|
47
|
+
const command = defineCommand({
|
|
48
|
+
summary: 'Remove the build output and build cache of this package, or of every package from the monorepo root',
|
|
49
|
+
run: async () => {
|
|
50
|
+
const style = resolveBinStyles().stdout;
|
|
51
|
+
const outcome = await cleanFrom(cwd, {
|
|
52
|
+
onProgress: (progress) => {
|
|
53
|
+
console.info(renderCleanProgress(progress, style));
|
|
54
|
+
},
|
|
55
|
+
stderr: process.stderr,
|
|
56
|
+
stdout: process.stdout,
|
|
57
|
+
});
|
|
58
|
+
const closing = renderCleanOutcome(outcome, style);
|
|
59
|
+
if (closing !== undefined) {
|
|
60
|
+
reportClosing(closing);
|
|
61
|
+
}
|
|
62
|
+
return 0;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return runCli(argv, command, { name: NMR_CLEAN_BIN, stdout: process.stdout, stderr: process.stderr, baseDir: cwd });
|
|
47
66
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
67
|
+
async function cleanReportedPackage(packageDir, options) {
|
|
68
|
+
await cleanPackage(packageDir);
|
|
69
|
+
options.onProgress?.({ kind: 'package-cleaned', packageDir });
|
|
70
|
+
}
|
|
71
|
+
async function clearCheckCache(scopeDir, options) {
|
|
72
|
+
await removeCheckCache(scopeDir);
|
|
73
|
+
options.onProgress?.({ kind: 'check-results-removed' });
|
|
52
74
|
}
|
|
53
|
-
async function sweepWorkspace(monorepoRoot, workspacePackageDirs,
|
|
75
|
+
async function sweepWorkspace(monorepoRoot, workspacePackageDirs, options) {
|
|
54
76
|
const config = await loadRootConfig(monorepoRoot);
|
|
55
77
|
const registry = buildWorkspaceRegistry(config);
|
|
56
|
-
|
|
78
|
+
const cleanedDirs = [];
|
|
57
79
|
let skippedCount = 0;
|
|
58
80
|
for (const packageDir of workspacePackageDirs) {
|
|
59
81
|
const resolvedScript = resolveScript(CLEAN_COMMAND, registry, packageDir, false);
|
|
@@ -63,18 +85,20 @@ async function sweepWorkspace(monorepoRoot, workspacePackageDirs, style) {
|
|
|
63
85
|
continue;
|
|
64
86
|
}
|
|
65
87
|
if (resolvedCommand === BUILT_IN_CLEAN) {
|
|
66
|
-
await
|
|
67
|
-
|
|
88
|
+
await cleanReportedPackage(packageDir, options);
|
|
89
|
+
cleanedDirs.push(packageDir);
|
|
68
90
|
continue;
|
|
69
91
|
}
|
|
70
92
|
const { exitCode } = await runCommand(resolvedCommand, packageDir, {
|
|
71
93
|
bin: NMR_CLEAN_BIN,
|
|
72
|
-
channels: { stderr: resolveChannel(
|
|
94
|
+
channels: { stderr: resolveChannel(options.stderr, false), stdout: resolveChannel(options.stdout, false) },
|
|
95
|
+
stderr: options.stderr,
|
|
96
|
+
stdout: options.stdout,
|
|
73
97
|
});
|
|
74
98
|
if (exitCode !== 0) {
|
|
75
99
|
throw new UserError(`\`${resolvedCommand}\` failed in ${path.basename(packageDir)} with exit code ${exitCode}.`);
|
|
76
100
|
}
|
|
77
|
-
|
|
101
|
+
cleanedDirs.push(packageDir);
|
|
78
102
|
}
|
|
79
|
-
|
|
103
|
+
return { kind: 'sweep', checkResultsDir: monorepoRoot, cleanedDirs, skippedCount };
|
|
80
104
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `nmr-compile` against `argv` for the package at `packageDir` and returns the exit code to report. The command
|
|
3
|
+
* takes neither an option nor an operand, so anything but `--help` is a usage error and compiles nothing.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runCompile(argv: string[], packageDir: string): Promise<number>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import { defineCommand, runCli } from '@williamthorsen/nmr-core/cli';
|
|
4
|
+
import { NMR_COMPILE_BIN } from "../bins.js";
|
|
5
|
+
import { loadWorkspaceConfig } from "../config.js";
|
|
6
|
+
import { resolveBinStyles } from "../resolveBinStyles.js";
|
|
7
|
+
import { buildPackage } from "./build.js";
|
|
8
|
+
import { renderBuildOutcome, renderBuildProgress } from "./build-report.js";
|
|
9
|
+
export async function runCompile(argv, packageDir) {
|
|
10
|
+
const command = defineCommand({
|
|
11
|
+
summary: "Compile the package's src tree to dist/esm",
|
|
12
|
+
run: async () => {
|
|
13
|
+
const { stdout } = resolveBinStyles();
|
|
14
|
+
const { build } = await loadWorkspaceConfig(packageDir);
|
|
15
|
+
const packageName = path.basename(packageDir);
|
|
16
|
+
const outcome = await buildPackage(packageDir, {
|
|
17
|
+
onProgress: (progress) => {
|
|
18
|
+
console.info(renderBuildProgress(progress, packageName, stdout));
|
|
19
|
+
},
|
|
20
|
+
...(build?.extraIgnorePatterns !== undefined && { extraIgnorePatterns: build.extraIgnorePatterns }),
|
|
21
|
+
});
|
|
22
|
+
console.info(renderBuildOutcome(outcome, packageName, stdout));
|
|
23
|
+
return 0;
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
return runCli(argv, command, {
|
|
27
|
+
name: NMR_COMPILE_BIN,
|
|
28
|
+
stdout: process.stdout,
|
|
29
|
+
stderr: process.stderr,
|
|
30
|
+
baseDir: packageDir,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -2,7 +2,8 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, statSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
5
|
-
import { NO_CACHE_ENV_VAR } from "../check-cache.js";
|
|
5
|
+
import { NO_CACHE_ENV_VAR } from "../check-cache/check-cache.js";
|
|
6
|
+
import { isEnvSwitchOn } from "../env-switch.js";
|
|
6
7
|
export const FMT_CACHE_DIRECTORY = path.join('node_modules', '.cache', 'prettier', 'nmr-fmt');
|
|
7
8
|
const LOCKFILE_NAMES = ['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock', 'bun.lock', 'bun.lockb'];
|
|
8
9
|
const NO_LOCKFILE_MARKER = 'nolock';
|
|
@@ -10,7 +11,7 @@ const HASH_LENGTH = 16;
|
|
|
10
11
|
const CACHE_FILE_PATTERN = /^([0-9a-f]{16})\.([0-9a-f]{16}|nolock)\.json$/;
|
|
11
12
|
export function prepareFmtCache(options) {
|
|
12
13
|
const { cwd, env, repositoryRoot, shouldBypassCache } = options;
|
|
13
|
-
if (shouldBypassCache || env
|
|
14
|
+
if (shouldBypassCache || isEnvSwitchOn(env, NO_CACHE_ENV_VAR))
|
|
14
15
|
return { kind: 'uncached' };
|
|
15
16
|
try {
|
|
16
17
|
if (statSync(path.join(repositoryRoot, 'node_modules'), { throwIfNoEntry: false })?.isDirectory() !== true) {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { type SpawnInherited } from './spawn-inherited.js';
|
|
1
2
|
export type FormatMode = 'check' | 'write';
|
|
2
3
|
/**
|
|
3
4
|
* Runs `nmr-fmt` against `argv` and returns the exit code to report: It formats or checks the files that git
|
|
4
5
|
* reports for `cwd`. A repository without a Prettier config of its own is formatted with the house config. The run
|
|
5
|
-
* uses Prettier's content-keyed cache unless `--no-cache` or `NMR_NO_CACHE=1` bypasses it
|
|
6
|
+
* uses Prettier's content-keyed cache unless `--no-cache` or `NMR_NO_CACHE=1` bypasses it, and an `NMR_NO_CACHE`
|
|
7
|
+
* that is neither on nor off is rejected as a usage error.
|
|
6
8
|
*
|
|
7
9
|
* Trailing arguments are git pathspecs, not Prettier flags; an unrecognized option is rejected rather
|
|
8
10
|
* than passed along, since git would read it as a pathspec matching nothing and the run would report
|
|
9
11
|
* success over an empty selection. Every argument after `--` is a pathspec, even one that starts
|
|
10
12
|
* with `-`.
|
|
11
13
|
*/
|
|
12
|
-
export declare function runFmt(argv: string[], cwd?: string): Promise<number>;
|
|
14
|
+
export declare function runFmt(argv: string[], cwd?: string, env?: NodeJS.ProcessEnv): Promise<number>;
|
|
13
15
|
/** @internal */
|
|
14
16
|
export interface RunPrettierOptions {
|
|
15
17
|
cliPath: string;
|
|
@@ -23,6 +25,8 @@ export interface RunPrettierOptions {
|
|
|
23
25
|
cwd: string;
|
|
24
26
|
/** Overridable so that the multi-batch path is reachable without a fixture that hits the real ceiling. */
|
|
25
27
|
budgetBytes?: number;
|
|
28
|
+
/** Runs the Prettier CLI on the caller's stdio. */
|
|
29
|
+
spawn?: SpawnInherited;
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
28
32
|
* Runs Prettier over the selection, returning the first non-zero exit code. Every batch runs even after
|
package/dist/esm/commands/fmt.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
|
-
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
2
|
import { createRequire } from 'node:module';
|
|
5
3
|
import path from 'node:path';
|
|
6
4
|
import process from 'node:process';
|
|
@@ -9,8 +7,12 @@ import { isRecord, reportError } from '@williamthorsen/nmr-core';
|
|
|
9
7
|
import { defineCommand, runCli, UsageError } from '@williamthorsen/nmr-core/cli';
|
|
10
8
|
import { describeError } from '@williamthorsen/toolbelt.errors';
|
|
11
9
|
import { NMR_FMT_BIN } from "../bins.js";
|
|
10
|
+
import { NO_CACHE_ENV_VAR } from "../check-cache/check-cache.js";
|
|
11
|
+
import { readEnvSwitch } from "../env-switch.js";
|
|
12
12
|
import { prepareFmtCache } from "./fmt-cache.js";
|
|
13
13
|
import { resolveFormatTargets } from "./format-targets.js";
|
|
14
|
+
import { BROKEN_MANIFEST_FIX, findPackageManifest, resolveDeclaredCli, } from "./package-manifest.js";
|
|
15
|
+
import { resolveInheritedExitCode, spawnInherited } from "./spawn-inherited.js";
|
|
14
16
|
const PRETTIER_PACKAGE = 'prettier';
|
|
15
17
|
const DEFAULT_CONFIG_PATH = fileURLToPath(new URL(`../prettier-default.config${path.extname(fileURLToPath(import.meta.url))}`, import.meta.url));
|
|
16
18
|
const ARGUMENT_BUDGET_BYTES = 100_000;
|
|
@@ -18,7 +20,7 @@ const MODE_ARGS = {
|
|
|
18
20
|
check: ['--check'],
|
|
19
21
|
write: ['--list-different', '--write'],
|
|
20
22
|
};
|
|
21
|
-
export async function runFmt(argv, cwd = process.cwd()) {
|
|
23
|
+
export async function runFmt(argv, cwd = process.cwd(), env = process.env) {
|
|
22
24
|
const command = defineCommand({
|
|
23
25
|
summary: 'Format or check the files that git lists',
|
|
24
26
|
flags: {
|
|
@@ -31,12 +33,20 @@ export async function runFmt(argv, cwd = process.cwd()) {
|
|
|
31
33
|
if (flags.check === flags.write) {
|
|
32
34
|
throw new UsageError(flags.check ? 'Pass --check or --write, not both.' : 'Pass --check or --write.');
|
|
33
35
|
}
|
|
34
|
-
|
|
36
|
+
const noCache = readEnvSwitch(env, NO_CACHE_ENV_VAR);
|
|
37
|
+
if (!noCache.ok) {
|
|
38
|
+
throw new UsageError(noCache.error);
|
|
39
|
+
}
|
|
40
|
+
return formatFiles({
|
|
41
|
+
mode: flags.check ? 'check' : 'write',
|
|
42
|
+
pathspecs: operands.pathspec,
|
|
43
|
+
shouldBypassCache: flags.noCache || noCache.isOn,
|
|
44
|
+
}, cwd, env);
|
|
35
45
|
},
|
|
36
46
|
});
|
|
37
47
|
return runCli(argv, command, { name: NMR_FMT_BIN, stdout: process.stdout, stderr: process.stderr, baseDir: cwd });
|
|
38
48
|
}
|
|
39
|
-
async function formatFiles(request, cwd) {
|
|
49
|
+
async function formatFiles(request, cwd, env) {
|
|
40
50
|
const resolvedTargets = resolveFormatTargets(cwd, request.pathspecs);
|
|
41
51
|
if (!resolvedTargets.ok) {
|
|
42
52
|
reportError(NMR_FMT_BIN, resolvedTargets.error);
|
|
@@ -70,7 +80,7 @@ async function formatFiles(request, cwd) {
|
|
|
70
80
|
}
|
|
71
81
|
const cache = prepareFmtCache({
|
|
72
82
|
cwd,
|
|
73
|
-
env
|
|
83
|
+
env,
|
|
74
84
|
repositoryRoot,
|
|
75
85
|
shouldBypassCache: request.shouldBypassCache,
|
|
76
86
|
});
|
|
@@ -92,17 +102,36 @@ function resolvePrettierCli(cwd) {
|
|
|
92
102
|
ok: false,
|
|
93
103
|
error: `\`${PRETTIER_PACKAGE}\` could not be resolved from this repository or from nmr's own installation, which declares it as a dependency. Reinstall \`@williamthorsen/nmr\`.`,
|
|
94
104
|
};
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
const repositoryLookup = findPackageManifest(path.join(cwd, 'package.json'), PRETTIER_PACKAGE);
|
|
106
|
+
const copy = repositoryLookup.kind === 'absent'
|
|
107
|
+
? {
|
|
108
|
+
lookup: findPackageManifest(import.meta.url, PRETTIER_PACKAGE),
|
|
109
|
+
origin: "nmr's installation",
|
|
110
|
+
reinstallStep: 'Reinstall `@williamthorsen/nmr`.',
|
|
111
|
+
}
|
|
112
|
+
: {
|
|
113
|
+
lookup: repositoryLookup,
|
|
114
|
+
origin: 'this repository',
|
|
115
|
+
reinstallStep: `Reinstall this repository's \`${PRETTIER_PACKAGE}\` dependency.`,
|
|
116
|
+
};
|
|
117
|
+
const { lookup } = copy;
|
|
118
|
+
if (lookup.kind === 'absent')
|
|
104
119
|
return missingResult;
|
|
105
|
-
|
|
120
|
+
if (lookup.kind === 'broken') {
|
|
121
|
+
return {
|
|
122
|
+
ok: false,
|
|
123
|
+
error: `\`${PRETTIER_PACKAGE}\` could not be loaded from ${copy.origin}: ${lookup.cause}. ${BROKEN_MANIFEST_FIX}`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const { manifest, manifestPath } = lookup;
|
|
127
|
+
const cliPath = resolveDeclaredCli(manifest, manifestPath, PRETTIER_PACKAGE);
|
|
128
|
+
if (cliPath === undefined) {
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
error: `\`${PRETTIER_PACKAGE}\` at ${path.dirname(manifestPath)} does not declare a CLI. ${copy.reinstallStep}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return { ok: true, cliPath, manifestPath };
|
|
106
135
|
}
|
|
107
136
|
async function findRepositoryConfig(manifestPath, cwd) {
|
|
108
137
|
try {
|
|
@@ -122,7 +151,7 @@ async function findRepositoryConfig(manifestPath, cwd) {
|
|
|
122
151
|
}
|
|
123
152
|
}
|
|
124
153
|
export function runPrettier(options) {
|
|
125
|
-
const { cacheLocation, cliPath, configPath, mode, files, ignorePaths, cwd, budgetBytes = ARGUMENT_BUDGET_BYTES, } = options;
|
|
154
|
+
const { cacheLocation, cliPath, configPath, mode, files, ignorePaths, cwd, budgetBytes = ARGUMENT_BUDGET_BYTES, spawn = spawnInherited, } = options;
|
|
126
155
|
const prettierArgs = [
|
|
127
156
|
cliPath,
|
|
128
157
|
...(configPath === undefined ? [] : ['--config', configPath]),
|
|
@@ -136,12 +165,12 @@ export function runPrettier(options) {
|
|
|
136
165
|
];
|
|
137
166
|
let firstFailureStatus = 0;
|
|
138
167
|
for (const batch of batchWithinBudget(files, budgetBytes)) {
|
|
139
|
-
const result =
|
|
168
|
+
const result = spawn(process.execPath, [...prettierArgs, ...batch], { cwd });
|
|
140
169
|
if (result.error) {
|
|
141
170
|
reportError(NMR_FMT_BIN, `could not run \`${PRETTIER_PACKAGE}\` (${result.error.message}).`);
|
|
142
171
|
return 1;
|
|
143
172
|
}
|
|
144
|
-
const status = result
|
|
173
|
+
const status = resolveInheritedExitCode(result);
|
|
145
174
|
if (status !== 0 && firstFailureStatus === 0) {
|
|
146
175
|
firstFailureStatus = status;
|
|
147
176
|
}
|
|
@@ -166,11 +195,3 @@ function batchWithinBudget(files, budgetBytes) {
|
|
|
166
195
|
batches.push(batch);
|
|
167
196
|
return batches;
|
|
168
197
|
}
|
|
169
|
-
function resolveFrom(parent, specifier) {
|
|
170
|
-
try {
|
|
171
|
-
return createRequire(parent).resolve(specifier);
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
return undefined;
|
|
175
|
-
}
|
|
176
|
-
}
|