@_linked/cli 1.43.0 → 1.44.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/CHANGELOG.md +21 -0
- package/README.md +11 -8
- package/defaults/package/package.json +4 -0
- package/lib/esm/cli.js +4 -10
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/client-dep-includes.d.ts +9 -3
- package/lib/esm/client-dep-includes.d.ts.map +1 -1
- package/lib/esm/client-dep-includes.js +10 -4
- package/lib/esm/client-dep-includes.js.map +1 -1
- package/lib/esm/commands/localize.d.ts +1 -1
- package/lib/esm/commands/localize.d.ts.map +1 -1
- package/lib/esm/commands/localize.js +15 -2
- package/lib/esm/commands/localize.js.map +1 -1
- package/lib/esm/localize/ensure.d.ts +4 -2
- package/lib/esm/localize/ensure.d.ts.map +1 -1
- package/lib/esm/localize/ensure.js +26 -41
- package/lib/esm/localize/ensure.js.map +1 -1
- package/lib/esm/localize/list.d.ts +2 -0
- package/lib/esm/localize/list.d.ts.map +1 -1
- package/lib/esm/localize/list.js +35 -1
- package/lib/esm/localize/list.js.map +1 -1
- package/lib/esm/localize/localize.d.ts.map +1 -1
- package/lib/esm/localize/localize.js +1 -1
- package/lib/esm/localize/localize.js.map +1 -1
- package/lib/esm/localize/manifest.d.ts +9 -0
- package/lib/esm/localize/manifest.d.ts.map +1 -1
- package/lib/esm/localize/manifest.js +2 -2
- package/lib/esm/localize/manifest.js.map +1 -1
- package/lib/esm/localize/one-copy-hook.d.ts +16 -0
- package/lib/esm/localize/one-copy-hook.d.ts.map +1 -0
- package/lib/esm/localize/one-copy-hook.js +20 -0
- package/lib/esm/localize/one-copy-hook.js.map +1 -0
- package/lib/esm/localize/prune.d.ts +115 -8
- package/lib/esm/localize/prune.d.ts.map +1 -1
- package/lib/esm/localize/prune.js +355 -126
- package/lib/esm/localize/prune.js.map +1 -1
- package/lib/esm/localize/relink.d.ts +3 -1
- package/lib/esm/localize/relink.d.ts.map +1 -1
- package/lib/esm/localize/relink.js +10 -5
- package/lib/esm/localize/relink.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure.js","sourceRoot":"","sources":["../../../src/localize/ensure.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One copy, always: every package the app provides loads once, whichever tool\n * runs the code -- Vite, `tsc`, plain Node, `tsx`, a test runner.\n *\n * Two halves:\n *\n * - **`ensure(entry)`** -- the ONLY way a checkout gets installed: `npm\n * install` inside it, then prune it (prune.ts). localize's install step,\n * `--relink`'s reinstall and `linked localize --reinstall <pkg>` all go\n * through it, so the copies an install puts back exist only until it\n * returns. Hand-running `npm install` in a checkout is what `--reinstall`\n * replaces.\n * - **`checkOneCopy(appRoot)`** -- the run-time check. Before `linked start`,\n * `script`, `call` and `build-all` (a commander `preAction` in cli.ts), and\n * as `linked localize --ensure` for an app's npm `pre*` scripts. Stat-only:\n * for every recorded checkout and every name the app provides, does\n * `<checkout>/node_modules/<name>` exist with a real path other than the\n * app's copy? Only then does it prune -- through prune's guarded path, so a\n * copy whose ranges the app does not satisfy stays -- and it says what it\n * removed in one line. It never runs npm, prints nothing when there is\n * nothing to do (or no manifest), and never throws: a run command must not\n * fail over a developer's private checkout state.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {\n EXIT_INSTALL_FAILED,\n EXIT_REFUSED,\n EXIT_WARNED,\n LocalizeError,\n} from './errors.js';\nimport {manifestPath, readManifest} from './manifest.js';\nimport type {ManifestEntry} from './manifest.js';\nimport {readJson} from './fsops.js';\nimport {\n nodeModulesRoots,\n pruneProvided,\n realOrSelf,\n shouldPrune,\n} from './prune.js';\nimport type {PruneOptions} from './prune.js';\nimport {providedPackages} from './provided.js';\nimport {defaultDeps} from './run.js';\nimport type {Deps} from './run.js';\nimport {reportError} from './localize.js';\n\n/**\n * `npm install` inside the checkout at `entry.path`, then prune it.\n *\n * The package's name is read from the checkout's own `package.json`; the\n * other localized packages (siblings) from the manifest, so a checkout being\n * localized right now prunes before the manifest records it.\n *\n * @returns 0, or `EXIT_WARNED` when the prune failed (the install stands).\n * @throws {LocalizeError} `EXIT_INSTALL_FAILED` when `npm install` fails.\n */\nexport function ensure(\n entry: Pick<ManifestEntry, 'path' | 'subdir'>,\n deps: Deps,\n opts: PruneOptions = {},\n): number {\n const pkgDir = path.join(deps.appRoot, entry.path);\n deps.log(`[localize] npm install in ${entry.path}`);\n const install = deps.run('npm', ['install', '--no-audit', '--no-fund'], {\n cwd: pkgDir,\n });\n if (install.status !== 0) {\n throw new LocalizeError(\n `npm install failed in ${entry.path}:\\n${(install.stderr || install.stdout).trim()}`,\n EXIT_INSTALL_FAILED,\n );\n }\n if (!shouldPrune(opts)) return 0;\n\n const name = readJson(path.join(pkgDir, 'package.json'))?.name;\n if (typeof name !== 'string') return 0;\n try {\n const entries = {...recordedEntries(deps), [name]: entry as ManifestEntry};\n pruneProvided(entries, opts, deps, {owners: [name]});\n return 0;\n } catch (e) {\n deps.warn(\n `[localize] pruning ${entry.path} failed, its node_modules are as npm left them: ${e.message}`,\n );\n return EXIT_WARNED;\n }\n}\n\n/** `linked localize --reinstall <pkg>`: `ensure` for one recorded package. */\nexport function reinstall(\n name: string,\n opts: PruneOptions,\n deps: Deps,\n): number {\n try {\n const entry = readManifest(deps.appRoot, deps).entries[name];\n if (!entry) {\n throw new LocalizeError(\n `${name} is not localized here, so there is no checkout to reinstall. ` +\n '`linked localize --list` shows what is.',\n EXIT_REFUSED,\n );\n }\n if (!fs.existsSync(path.join(deps.appRoot, entry.path, 'package.json'))) {\n throw new LocalizeError(\n `${name} is recorded at ${entry.path}, which has no package.json.`,\n EXIT_REFUSED,\n );\n }\n return ensure(entry, deps, opts);\n } catch (e) {\n return reportError(e, deps);\n }\n}\n\n/**\n * The run-time check: remove every recorded checkout's own copy of what the\n * app provides. Stat-only until there is something to remove.\n *\n * @returns what was removed, as `<checkout>/node_modules/<name>@<version>`.\n */\nexport function checkOneCopy(\n appRoot: string = process.cwd(),\n deps: Pick<Deps, 'log' | 'warn'> = defaultDeps(appRoot),\n): {pruned: string[]} {\n try {\n if (!fs.existsSync(manifestPath(appRoot))) return {pruned: []};\n const entries = readManifest(appRoot, {warn: () => {}}).entries;\n const owners = Object.keys(entries);\n if (!owners.length) return {pruned: []};\n\n // The app's copy of each provided name, by real path.\n const appReal = new Map<string, string>();\n for (const name of providedPackages(appRoot, owners).names) {\n const dir = path.join(appRoot, 'node_modules', name);\n if (fs.existsSync(dir)) appReal.set(name, realOrSelf(dir));\n }\n\n const hitOwners = new Set<string>();\n const hitNames = new Set<string>();\n for (const [owner, entry] of Object.entries(entries)) {\n const pkgDir = path.join(appRoot, entry.path);\n for (const nm of nodeModulesRoots(pkgDir, entry)) {\n for (const [name, real] of appReal) {\n if (name === owner) continue;\n const copy = path.join(nm, name);\n if (fs.existsSync(copy) && realOrSelf(copy) !== real) {\n hitOwners.add(owner);\n hitNames.add(name);\n }\n }\n }\n }\n if (!hitOwners.size) return {pruned: []};\n\n // Prune's own report is per checkout and also speaks of what it keeps;\n // here only what went is worth a line, on every run command.\n const quiet = {appRoot, log: () => {}, warn: () => {}};\n const {removed} = pruneProvided(entries, {}, quiet, {\n owners: [...hitOwners],\n deps: [...hitNames],\n });\n const pruned = removed.map(\n (r) => `${r.owner}/node_modules/${r.dep}@${r.version}`,\n );\n if (pruned.length) {\n deps.log(\n `[localize] one copy: removed ${pruned.join(', ')} — the app provides ` +\n `${pruned.length === 1 ? 'it' : 'them'}.`,\n );\n }\n return {pruned};\n } catch (e) {\n deps.warn(\n `[localize] one-copy check failed, nothing more was removed: ${e?.message ?? e}`,\n );\n return {pruned: []};\n }\n}\n\nfunction recordedEntries(deps: Deps): Record<string, ManifestEntry> {\n try {\n return readManifest(deps.appRoot, {warn: () => {}}).entries;\n } catch {\n return {};\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ensure.js","sourceRoot":"","sources":["../../../src/localize/ensure.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One copy, always: every package the app provides loads once, whichever tool\n * runs the code -- Vite, `tsc`, plain Node, `tsx`, a test runner.\n *\n * Two halves:\n *\n * - **`ensure(entry)`** -- the ONLY way a checkout gets installed: `npm\n * install` inside it, then prune it (prune.ts). localize's install step,\n * `--relink`'s reinstall and `linked localize --reinstall <pkg>` all go\n * through it, so the copies an install puts back exist only until it\n * returns. Hand-running `npm install` in a checkout is what `--reinstall`\n * replaces.\n * - **`checkOneCopy(appRoot)`** -- the run-time check. Before `linked start`,\n * `script`, `call` and `build-all` (a commander `preAction` in cli.ts), and\n * as `linked localize --ensure` for an app's npm `pre*` scripts. It plans\n * the prune (prune.ts `planPrune`) without touching anything -- per-owner\n * candidates, the same range guard, the same \"would its dependencies\n * resolve elsewhere\" check -- and only when that plan removes something does\n * it prune, and say so in one line on stderr. A copy prune would keep costs\n * a stat and, at most, one requirement index per `node_modules` (read from\n * npm's hidden lockfile), so a tree full of kept copies stays cheap. It\n * never runs npm, prints nothing when there is nothing to do (or no\n * manifest), skips a checkout recorded with `prune: false`, and never\n * throws: a run command must not fail over a developer's private checkout\n * state.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {\n EXIT_INSTALL_FAILED,\n EXIT_REFUSED,\n EXIT_WARNED,\n LocalizeError,\n} from './errors.js';\nimport {manifestPath, readManifest} from './manifest.js';\nimport type {ManifestEntry} from './manifest.js';\nimport {readJson} from './fsops.js';\nimport {\n newPruneCache,\n planPrune,\n pruneProvided,\n prunesEntry,\n shouldPrune,\n} from './prune.js';\nimport type {PruneOptions} from './prune.js';\nimport {defaultDeps} from './run.js';\nimport type {Deps} from './run.js';\nimport {reportError} from './localize.js';\n\n/**\n * `npm install` inside the checkout at `entry.path`, then prune it.\n *\n * The package's name is read from the checkout's own `package.json`; the\n * other localized packages (siblings) from the manifest, so a checkout being\n * localized right now prunes before the manifest records it.\n *\n * @returns 0, or `EXIT_WARNED` when the prune failed (the install stands).\n * @throws {LocalizeError} `EXIT_INSTALL_FAILED` when `npm install` fails.\n */\nexport function ensure(\n entry: Pick<ManifestEntry, 'path' | 'subdir' | 'prune'>,\n deps: Deps,\n opts: PruneOptions = {},\n): number {\n const pkgDir = path.join(deps.appRoot, entry.path);\n deps.log(`[localize] npm install in ${entry.path}`);\n const install = deps.run('npm', ['install', '--no-audit', '--no-fund'], {\n cwd: pkgDir,\n });\n if (install.status !== 0) {\n throw new LocalizeError(\n `npm install failed in ${entry.path}:\\n${(install.stderr || install.stdout).trim()}`,\n EXIT_INSTALL_FAILED,\n );\n }\n if (!shouldPrune(opts) || !prunesEntry(entry)) return 0;\n\n const name = readJson(path.join(pkgDir, 'package.json'))?.name;\n if (typeof name !== 'string') return 0;\n try {\n const entries = {...recordedEntries(deps), [name]: entry as ManifestEntry};\n pruneProvided(entries, opts, deps, {owners: [name]});\n return 0;\n } catch (e) {\n deps.warn(\n `[localize] pruning ${entry.path} failed, its node_modules are as npm left them: ${e.message}`,\n );\n return EXIT_WARNED;\n }\n}\n\n/** `linked localize --reinstall <pkg>`: `ensure` for one recorded package. */\nexport function reinstall(\n name: string,\n opts: PruneOptions,\n deps: Deps,\n): number {\n try {\n const entry = readManifest(deps.appRoot, deps).entries[name];\n if (!entry) {\n throw new LocalizeError(\n `${name} is not localized here, so there is no checkout to reinstall. ` +\n '`linked localize --list` shows what is.',\n EXIT_REFUSED,\n );\n }\n if (!fs.existsSync(path.join(deps.appRoot, entry.path, 'package.json'))) {\n throw new LocalizeError(\n `${name} is recorded at ${entry.path}, which has no package.json.`,\n EXIT_REFUSED,\n );\n }\n return ensure(entry, deps, opts);\n } catch (e) {\n return reportError(e, deps);\n }\n}\n\n/**\n * The run-time check: remove every recorded checkout's own copy of what the\n * app provides -- exactly what `pruneProvided` would remove, decided first\n * without it, so the common case (nothing to remove, some copies kept) never\n * reaches the prune.\n *\n * @returns what was removed, as `<checkout>/node_modules/<name>@<version>`.\n */\nexport function checkOneCopy(\n appRoot: string = process.cwd(),\n deps: Pick<Deps, 'log' | 'warn'> = defaultDeps(appRoot),\n): {pruned: string[]} {\n try {\n if (!fs.existsSync(manifestPath(appRoot))) return {pruned: []};\n const entries = readManifest(appRoot, {warn: () => {}}).entries;\n const owners = Object.keys(entries);\n if (!owners.length) return {pruned: []};\n\n if (!Object.values(entries).some(prunesEntry)) return {pruned: []};\n\n const cache = newPruneCache();\n const plan = planPrune(entries, {appRoot}, {}, cache);\n if (!plan.remove.length) return {pruned: []};\n\n // Prune's own report is per checkout and also speaks of what it keeps;\n // here only what went is worth a line, on every run command.\n const quiet = {appRoot, log: () => {}, warn: () => {}};\n const {removed} = pruneProvided(\n entries,\n {},\n quiet,\n {\n owners: [...new Set(plan.remove.map((d) => d.ownerName))],\n deps: [...new Set(plan.remove.map((d) => d.dep))],\n },\n cache,\n );\n const pruned = removed.map((r) => `${r.where}@${r.version}`);\n if (pruned.length) {\n deps.warn(\n `[localize] one copy: removed ${pruned.join(', ')} — the app provides ` +\n `${pruned.length === 1 ? 'it' : 'them'}.`,\n );\n }\n return {pruned};\n } catch (e) {\n deps.warn(\n `[localize] one-copy check failed, nothing more was removed: ${e?.message ?? e}`,\n );\n return {pruned: []};\n }\n}\n\nfunction recordedEntries(deps: Deps): Record<string, ManifestEntry> {\n try {\n return readManifest(deps.appRoot, {warn: () => {}}).entries;\n } catch {\n return {};\n }\n}\n"]}
|
|
@@ -6,6 +6,8 @@ export interface ListRow {
|
|
|
6
6
|
path: string;
|
|
7
7
|
branch: string;
|
|
8
8
|
note: string;
|
|
9
|
+
/** A linked checkout: the copies pruning keeps in it, each with its reason. */
|
|
10
|
+
kept?: string[];
|
|
9
11
|
}
|
|
10
12
|
/** @returns {{rows: object[], notLinked: number}} */
|
|
11
13
|
export declare function collect(deps: Deps): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/localize/list.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/localize/list.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,UAAU,CAAC;AAEnC,qFAAqF;AACrF,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EACD,QAAQ,GACR,kBAAkB,GAClB,YAAY,GACZ,WAAW,GACX,WAAW,GACX,YAAY,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,qDAAqD;AACrD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG;IAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAuGxE;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAsDhE"}
|
package/lib/esm/localize/list.js
CHANGED
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
* localized, and one that is not loads nobody's code while looking as if it
|
|
13
13
|
* did.
|
|
14
14
|
*
|
|
15
|
+
* For a linked checkout it also says what pruning would keep in that
|
|
16
|
+
* checkout's `node_modules` and why (prune.ts `planPrune`, nothing removed),
|
|
17
|
+
* or that pruning is off for it (`prune: false`): localize, adopt and
|
|
18
|
+
* `--relink` only summarise kept copies, and this is where the reasons are.
|
|
19
|
+
*
|
|
15
20
|
* Never writes. Exits 0, unless `--check` and something recorded is not
|
|
16
21
|
* actually linked.
|
|
17
22
|
*/
|
|
@@ -20,6 +25,7 @@ import path from 'node:path';
|
|
|
20
25
|
import { MANIFEST_FILENAME, readManifest } from './manifest.js';
|
|
21
26
|
import { isInside, linkTarget, readJson, scanLinks } from './fsops.js';
|
|
22
27
|
import { reportError } from './localize.js';
|
|
28
|
+
import { explainKept, planPrune, prunesEntry } from './prune.js';
|
|
23
29
|
/** @returns {{rows: object[], notLinked: number}} */
|
|
24
30
|
export function collect(deps) {
|
|
25
31
|
const manifest = readManifest(deps.appRoot, deps);
|
|
@@ -34,7 +40,7 @@ export function collect(deps) {
|
|
|
34
40
|
state: 'linked',
|
|
35
41
|
path: entry.path,
|
|
36
42
|
branch: entry.branch,
|
|
37
|
-
note: '',
|
|
43
|
+
note: prunesEntry(entry) ? '' : 'prune: off',
|
|
38
44
|
});
|
|
39
45
|
}
|
|
40
46
|
else if (!fs.existsSync(checkout)) {
|
|
@@ -102,6 +108,23 @@ export function collect(deps) {
|
|
|
102
108
|
note: `directory not in ${MANIFEST_FILENAME}`,
|
|
103
109
|
});
|
|
104
110
|
}
|
|
111
|
+
// What pruning keeps, per linked checkout. Informational: a failure here
|
|
112
|
+
// must not cost the listing.
|
|
113
|
+
try {
|
|
114
|
+
const plan = planPrune(manifest.entries, deps);
|
|
115
|
+
for (const row of rows) {
|
|
116
|
+
if (row.state !== 'linked')
|
|
117
|
+
continue;
|
|
118
|
+
const kept = plan.keep.filter((k) => k.ownerName === row.name);
|
|
119
|
+
if (!kept.length)
|
|
120
|
+
continue;
|
|
121
|
+
row.kept = kept.map(explainKept);
|
|
122
|
+
row.note = `kept ${kept.length} own ${kept.length === 1 ? 'copy' : 'copies'}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (_a) {
|
|
126
|
+
/* listed without it */
|
|
127
|
+
}
|
|
105
128
|
const notLinked = rows.filter((r) => r.state === 'not-linked' || r.state === 'checkout-missing').length;
|
|
106
129
|
return { rows, notLinked };
|
|
107
130
|
}
|
|
@@ -131,12 +154,23 @@ export function list(opts, deps) {
|
|
|
131
154
|
pad(11, r.branch) +
|
|
132
155
|
r.note);
|
|
133
156
|
}
|
|
157
|
+
const withKept = rows.filter((r) => { var _a; return (_a = r.kept) === null || _a === void 0 ? void 0 : _a.length; });
|
|
158
|
+
if (withKept.length) {
|
|
159
|
+
deps.log('');
|
|
160
|
+
deps.log("Kept in a checkout's own node_modules (the app's copy cannot replace them, so the app loads two):");
|
|
161
|
+
for (const r of withKept)
|
|
162
|
+
for (const k of r.kept)
|
|
163
|
+
deps.log(` ${k}`);
|
|
164
|
+
}
|
|
134
165
|
const count = (s) => rows.filter((r) => r.state === s).length;
|
|
135
166
|
const parts = [`${count('linked')} linked`, `${notLinked} not linked`];
|
|
136
167
|
if (count('untracked'))
|
|
137
168
|
parts.push(`${count('untracked')} untracked link`);
|
|
138
169
|
if (count('malformed'))
|
|
139
170
|
parts.push(`${count('malformed')} malformed entry`);
|
|
171
|
+
const keptTotal = withKept.reduce((n, r) => n + r.kept.length, 0);
|
|
172
|
+
if (keptTotal)
|
|
173
|
+
parts.push(`${keptTotal} kept ${keptTotal === 1 ? 'copy' : 'copies'}`);
|
|
140
174
|
if (count('unrecorded'))
|
|
141
175
|
parts.push(`${count('unrecorded')} unrecorded ${count('unrecorded') === 1 ? 'directory' : 'directories'}`);
|
|
142
176
|
deps.log('');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/localize/list.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `--list` -- read the SYMLINKS, then reconcile against the manifest.\n *\n * The manifest records INTENT; the symlink is TRUTH. They can disagree -- most\n * commonly because `npm ci` deleted `node_modules` and exited 0 -- so this\n * reads the links first and reports the disagreement rather than assuming.\n * The four states are distinguished deliberately: both of the silent failures\n * this tool was built to end were disagreements between intent and truth.\n *\n * It also flags a directory in the checkout directory (`packages-local/`) that\n * nothing records and nothing links: every checkout there is meant to be\n * localized, and one that is not loads nobody's code while looking as if it\n * did.\n *\n * Never writes. Exits 0, unless `--check` and something recorded is not\n * actually linked.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {MANIFEST_FILENAME, readManifest} from './manifest.js';\nimport {isInside, linkTarget, readJson, scanLinks} from './fsops.js';\nimport {reportError} from './localize.js';\nimport type {Deps} from './run.js';\n\n/** One row of `--list`: a recorded package, or a link the manifest does not know. */\nexport interface ListRow {\n name: string;\n state:\n | 'linked'\n | 'checkout-missing'\n | 'not-linked'\n | 'malformed'\n | 'untracked'\n | 'unrecorded';\n path: string;\n branch: string;\n note: string;\n}\n\n/** @returns {{rows: object[], notLinked: number}} */\nexport function collect(deps: Deps): {rows: ListRow[]; notLinked: number} {\n const manifest = readManifest(deps.appRoot, deps);\n const dir = path.join(deps.appRoot, manifest.dir);\n const rows: ListRow[] = [];\n\n for (const [name, entry] of Object.entries(manifest.entries)) {\n const checkout = path.join(deps.appRoot, entry.path);\n const target = linkTarget(deps.appRoot, name);\n\n if (target && isInside(target, dir)) {\n rows.push({\n name,\n state: 'linked',\n path: entry.path,\n branch: entry.branch,\n note: '',\n });\n } else if (!fs.existsSync(checkout)) {\n // Recorded, but nothing on disk. `localize <name>` re-clones it when the\n // entry has a repo or the package is published; otherwise it is restored by hand.\n rows.push({\n name,\n state: 'checkout-missing',\n path: entry.path,\n branch: '—',\n note: 'CHECKOUT MISSING',\n });\n } else {\n // Intent and checkout present, symlink gone. This is what `npm ci`\n // leaves behind, and it is the state that costs hours.\n rows.push({\n name,\n state: 'not-linked',\n path: entry.path,\n branch: entry.branch,\n note: 'checkout present',\n });\n }\n }\n\n for (const m of manifest.malformed) {\n rows.push({\n name: m.name,\n state: 'malformed',\n path: '—',\n branch: '—',\n note: `malformed entry (${m.reason})`,\n });\n }\n\n // A symlink out of node_modules that the manifest does not know about.\n // Reported, never touched.\n const untrackedTargets: string[] = [];\n for (const {name, target} of scanLinks(deps.appRoot)) {\n if (manifest.entries[name]) continue;\n untrackedTargets.push(target);\n rows.push({\n name,\n state: 'untracked',\n path: path.relative(deps.appRoot, target),\n branch: '—',\n note: `not in ${MANIFEST_FILENAME}`,\n });\n }\n\n // A directory in the checkout directory with no record (and no link, which\n // the row above already reports).\n const recorded = Object.values(manifest.entries).map((e) =>\n real(path.join(deps.appRoot, e.path)),\n );\n for (const sub of directoriesIn(dir)) {\n const abs = real(path.join(dir, sub));\n if (recorded.some((r) => r === abs || isInside(r, abs))) continue;\n if (untrackedTargets.some((t) => t === abs || isInside(t, abs))) continue;\n const pkg = readJson(path.join(abs, 'package.json'));\n rows.push({\n name: typeof pkg?.name === 'string' ? pkg.name : '—',\n state: 'unrecorded',\n path: path.join(manifest.dir, sub),\n branch: '—',\n note: `directory not in ${MANIFEST_FILENAME}`,\n });\n }\n\n const notLinked = rows.filter(\n (r) => r.state === 'not-linked' || r.state === 'checkout-missing',\n ).length;\n return {rows, notLinked};\n}\n\nexport function list(opts: {check?: boolean}, deps: Deps): number {\n let result;\n try {\n result = collect(deps);\n } catch (e) {\n return reportError(e, deps);\n }\n const {rows, notLinked} = result;\n\n if (!rows.length) return 0; // nothing localized, nothing to say\n\n const pad = (n, s) => s.padEnd(n);\n const nameW = Math.max(...rows.map((r) => r.name.length)) + 2;\n const pathW = Math.max(...rows.map((r) => r.path.length)) + 2;\n for (const r of rows) {\n const label =\n r.state === 'linked' || r.state === 'untracked'\n ? 'linked'\n : r.state === 'unrecorded'\n ? 'UNRECORDED'\n : 'NOT LINKED';\n deps.log(\n pad(nameW, r.name) +\n pad(12, label) +\n pad(pathW, r.path) +\n pad(11, r.branch) +\n r.note,\n );\n }\n\n const count = (s) => rows.filter((r) => r.state === s).length;\n const parts = [`${count('linked')} linked`, `${notLinked} not linked`];\n if (count('untracked')) parts.push(`${count('untracked')} untracked link`);\n if (count('malformed')) parts.push(`${count('malformed')} malformed entry`);\n if (count('unrecorded'))\n parts.push(\n `${count('unrecorded')} unrecorded ${count('unrecorded') === 1 ? 'directory' : 'directories'}`,\n );\n deps.log('');\n deps.log(parts.join(' · '));\n\n return opts.check && notLinked > 0 ? 1 : 0;\n}\n\n/** The (non-hidden) directories directly in `dir`, following links; none when it is absent. */\nfunction directoriesIn(dir: string): string[] {\n let names: string[];\n try {\n names = fs.readdirSync(dir);\n } catch {\n return [];\n }\n return names.filter((n) => {\n if (n.startsWith('.')) return false;\n try {\n return fs.statSync(path.join(dir, n)).isDirectory();\n } catch {\n return false;\n }\n });\n}\n\nfunction real(p: string): string {\n try {\n return fs.realpathSync(p);\n } catch {\n return p;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/localize/list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAC,iBAAiB,EAAE,YAAY,EAAC,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC;AACrE,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,YAAY,CAAC;AAoB/D,qDAAqD;AACrD,MAAM,UAAU,OAAO,CAAC,IAAU;IAChC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,IAAI,GAAc,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAE9C,IAAI,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI;gBACJ,KAAK,EAAE,QAAQ;gBACf,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY;aAC7C,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,yEAAyE;YACzE,kFAAkF;YAClF,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI;gBACJ,KAAK,EAAE,kBAAkB;gBACzB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,mEAAmE;YACnE,uDAAuD;YACvD,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI;gBACJ,KAAK,EAAE,YAAY;gBACnB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,GAAG;YACT,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,oBAAoB,CAAC,CAAC,MAAM,GAAG;SACtC,CAAC,CAAC;IACL,CAAC;IAED,uEAAuE;IACvE,2BAA2B;IAC3B,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,KAAK,MAAM,EAAC,IAAI,EAAE,MAAM,EAAC,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACrC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC;YACR,IAAI;YACJ,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;YACzC,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,UAAU,iBAAiB,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED,2EAA2E;IAC3E,kCAAkC;IAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACzD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CACtC,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAAE,SAAS;QAClE,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAAE,SAAS;QAC1E,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,OAAO,CAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,IAAI,CAAA,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG;YACpD,KAAK,EAAE,YAAY;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;YAClC,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,oBAAoB,iBAAiB,EAAE;SAC9C,CAAC,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,6BAA6B;IAC7B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,KAAK,KAAK,QAAQ;gBAAE,SAAS;YACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/D,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,SAAS;YAC3B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACjC,GAAG,CAAC,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAChF,CAAC;IACH,CAAC;IAAC,WAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,IAAI,CAAC,CAAC,KAAK,KAAK,kBAAkB,CAClE,CAAC,MAAM,CAAC;IACT,OAAO,EAAC,IAAI,EAAE,SAAS,EAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAuB,EAAE,IAAU;IACtD,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,EAAC,IAAI,EAAE,SAAS,EAAC,GAAG,MAAM,CAAC;IAEjC,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC,CAAC,oCAAoC;IAEhE,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,KAAK,GACT,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,WAAW;YAC7C,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY;gBACxB,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,YAAY,CAAC;QACrB,IAAI,CAAC,GAAG,CACN,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC;YAChB,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC;YACd,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC;YAClB,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;YACjB,CAAC,CAAC,IAAI,CACT,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,WAAC,OAAA,MAAA,CAAC,CAAC,IAAI,0CAAE,MAAM,CAAA,EAAA,CAAC,CAAC;IACpD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CACN,mGAAmG,CACpG,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAK;gBAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9D,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,SAAS,aAAa,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,WAAW,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;IAC3E,IAAI,KAAK,CAAC,WAAW,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;IAC5E,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACnE,IAAI,SAAS;QACX,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,SAAS,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACzE,IAAI,KAAK,CAAC,YAAY,CAAC;QACrB,KAAK,CAAC,IAAI,CACR,GAAG,KAAK,CAAC,YAAY,CAAC,eAAe,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,EAAE,CAC/F,CAAC;IACJ,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAE5B,OAAO,IAAI,CAAC,KAAK,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,+FAA+F;AAC/F,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACxB,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,CAAC;YACH,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACtD,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,IAAI,CAAC,CAAS;IACrB,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC","sourcesContent":["/**\n * `--list` -- read the SYMLINKS, then reconcile against the manifest.\n *\n * The manifest records INTENT; the symlink is TRUTH. They can disagree -- most\n * commonly because `npm ci` deleted `node_modules` and exited 0 -- so this\n * reads the links first and reports the disagreement rather than assuming.\n * The four states are distinguished deliberately: both of the silent failures\n * this tool was built to end were disagreements between intent and truth.\n *\n * It also flags a directory in the checkout directory (`packages-local/`) that\n * nothing records and nothing links: every checkout there is meant to be\n * localized, and one that is not loads nobody's code while looking as if it\n * did.\n *\n * For a linked checkout it also says what pruning would keep in that\n * checkout's `node_modules` and why (prune.ts `planPrune`, nothing removed),\n * or that pruning is off for it (`prune: false`): localize, adopt and\n * `--relink` only summarise kept copies, and this is where the reasons are.\n *\n * Never writes. Exits 0, unless `--check` and something recorded is not\n * actually linked.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {MANIFEST_FILENAME, readManifest} from './manifest.js';\nimport {isInside, linkTarget, readJson, scanLinks} from './fsops.js';\nimport {reportError} from './localize.js';\nimport {explainKept, planPrune, prunesEntry} from './prune.js';\nimport type {Deps} from './run.js';\n\n/** One row of `--list`: a recorded package, or a link the manifest does not know. */\nexport interface ListRow {\n name: string;\n state:\n | 'linked'\n | 'checkout-missing'\n | 'not-linked'\n | 'malformed'\n | 'untracked'\n | 'unrecorded';\n path: string;\n branch: string;\n note: string;\n /** A linked checkout: the copies pruning keeps in it, each with its reason. */\n kept?: string[];\n}\n\n/** @returns {{rows: object[], notLinked: number}} */\nexport function collect(deps: Deps): {rows: ListRow[]; notLinked: number} {\n const manifest = readManifest(deps.appRoot, deps);\n const dir = path.join(deps.appRoot, manifest.dir);\n const rows: ListRow[] = [];\n\n for (const [name, entry] of Object.entries(manifest.entries)) {\n const checkout = path.join(deps.appRoot, entry.path);\n const target = linkTarget(deps.appRoot, name);\n\n if (target && isInside(target, dir)) {\n rows.push({\n name,\n state: 'linked',\n path: entry.path,\n branch: entry.branch,\n note: prunesEntry(entry) ? '' : 'prune: off',\n });\n } else if (!fs.existsSync(checkout)) {\n // Recorded, but nothing on disk. `localize <name>` re-clones it when the\n // entry has a repo or the package is published; otherwise it is restored by hand.\n rows.push({\n name,\n state: 'checkout-missing',\n path: entry.path,\n branch: '—',\n note: 'CHECKOUT MISSING',\n });\n } else {\n // Intent and checkout present, symlink gone. This is what `npm ci`\n // leaves behind, and it is the state that costs hours.\n rows.push({\n name,\n state: 'not-linked',\n path: entry.path,\n branch: entry.branch,\n note: 'checkout present',\n });\n }\n }\n\n for (const m of manifest.malformed) {\n rows.push({\n name: m.name,\n state: 'malformed',\n path: '—',\n branch: '—',\n note: `malformed entry (${m.reason})`,\n });\n }\n\n // A symlink out of node_modules that the manifest does not know about.\n // Reported, never touched.\n const untrackedTargets: string[] = [];\n for (const {name, target} of scanLinks(deps.appRoot)) {\n if (manifest.entries[name]) continue;\n untrackedTargets.push(target);\n rows.push({\n name,\n state: 'untracked',\n path: path.relative(deps.appRoot, target),\n branch: '—',\n note: `not in ${MANIFEST_FILENAME}`,\n });\n }\n\n // A directory in the checkout directory with no record (and no link, which\n // the row above already reports).\n const recorded = Object.values(manifest.entries).map((e) =>\n real(path.join(deps.appRoot, e.path)),\n );\n for (const sub of directoriesIn(dir)) {\n const abs = real(path.join(dir, sub));\n if (recorded.some((r) => r === abs || isInside(r, abs))) continue;\n if (untrackedTargets.some((t) => t === abs || isInside(t, abs))) continue;\n const pkg = readJson(path.join(abs, 'package.json'));\n rows.push({\n name: typeof pkg?.name === 'string' ? pkg.name : '—',\n state: 'unrecorded',\n path: path.join(manifest.dir, sub),\n branch: '—',\n note: `directory not in ${MANIFEST_FILENAME}`,\n });\n }\n\n // What pruning keeps, per linked checkout. Informational: a failure here\n // must not cost the listing.\n try {\n const plan = planPrune(manifest.entries, deps);\n for (const row of rows) {\n if (row.state !== 'linked') continue;\n const kept = plan.keep.filter((k) => k.ownerName === row.name);\n if (!kept.length) continue;\n row.kept = kept.map(explainKept);\n row.note = `kept ${kept.length} own ${kept.length === 1 ? 'copy' : 'copies'}`;\n }\n } catch {\n /* listed without it */\n }\n\n const notLinked = rows.filter(\n (r) => r.state === 'not-linked' || r.state === 'checkout-missing',\n ).length;\n return {rows, notLinked};\n}\n\nexport function list(opts: {check?: boolean}, deps: Deps): number {\n let result;\n try {\n result = collect(deps);\n } catch (e) {\n return reportError(e, deps);\n }\n const {rows, notLinked} = result;\n\n if (!rows.length) return 0; // nothing localized, nothing to say\n\n const pad = (n, s) => s.padEnd(n);\n const nameW = Math.max(...rows.map((r) => r.name.length)) + 2;\n const pathW = Math.max(...rows.map((r) => r.path.length)) + 2;\n for (const r of rows) {\n const label =\n r.state === 'linked' || r.state === 'untracked'\n ? 'linked'\n : r.state === 'unrecorded'\n ? 'UNRECORDED'\n : 'NOT LINKED';\n deps.log(\n pad(nameW, r.name) +\n pad(12, label) +\n pad(pathW, r.path) +\n pad(11, r.branch) +\n r.note,\n );\n }\n\n const withKept = rows.filter((r) => r.kept?.length);\n if (withKept.length) {\n deps.log('');\n deps.log(\n \"Kept in a checkout's own node_modules (the app's copy cannot replace them, so the app loads two):\",\n );\n for (const r of withKept) for (const k of r.kept!) deps.log(` ${k}`);\n }\n\n const count = (s) => rows.filter((r) => r.state === s).length;\n const parts = [`${count('linked')} linked`, `${notLinked} not linked`];\n if (count('untracked')) parts.push(`${count('untracked')} untracked link`);\n if (count('malformed')) parts.push(`${count('malformed')} malformed entry`);\n const keptTotal = withKept.reduce((n, r) => n + r.kept!.length, 0);\n if (keptTotal)\n parts.push(`${keptTotal} kept ${keptTotal === 1 ? 'copy' : 'copies'}`);\n if (count('unrecorded'))\n parts.push(\n `${count('unrecorded')} unrecorded ${count('unrecorded') === 1 ? 'directory' : 'directories'}`,\n );\n deps.log('');\n deps.log(parts.join(' · '));\n\n return opts.check && notLinked > 0 ? 1 : 0;\n}\n\n/** The (non-hidden) directories directly in `dir`, following links; none when it is absent. */\nfunction directoriesIn(dir: string): string[] {\n let names: string[];\n try {\n names = fs.readdirSync(dir);\n } catch {\n return [];\n }\n return names.filter((n) => {\n if (n.startsWith('.')) return false;\n try {\n return fs.statSync(path.join(dir, n)).isDirectory();\n } catch {\n return false;\n }\n });\n}\n\nfunction real(p: string): string {\n try {\n return fs.realpathSync(p);\n } catch {\n return p;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localize.d.ts","sourceRoot":"","sources":["../../../src/localize/localize.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,UAAU,CAAC;AAInC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAW7C;;;;;;;GAOG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAC,CAAC;CAC9C;AAED,MAAM,MAAM,OAAO,GAAG,CACpB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,KACP,SAAS,CAAC;AAEf,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,GACT,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,OAAO,GACX,MAAM,CAgDR;AAuFD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,EACE,OAAO,EACP,KAAK,EACL,MAAM,EACN,MAAM,EACN,IAAI,EACJ,MAAM,GACP,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,EACD,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,EACV,IAAI,SAAI,GACP;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAC,CAAA;CAAC,
|
|
1
|
+
{"version":3,"file":"localize.d.ts","sourceRoot":"","sources":["../../../src/localize/localize.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,UAAU,CAAC;AAInC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,YAAY,CAAC;AAW7C;;;;;;;GAOG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,uDAAuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAC,CAAC;CAC9C;AAED,MAAM,MAAM,OAAO,GAAG,CACpB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,KACP,SAAS,CAAC;AAEf,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,GACT,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,OAAO,GACX,MAAM,CAgDR;AAuFD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,EACE,OAAO,EACP,KAAK,EACL,MAAM,EACN,MAAM,EACN,IAAI,EACJ,MAAM,GACP,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,EACD,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,EACV,IAAI,SAAI,GACP;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAC,CAAA;CAAC,CAsC7D;AAiFD,uFAAuF;AACvF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,EACvB,IAAI,EAAE,IAAI,GACT,IAAI,CAqBN;AA0BD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACrC,IAAI,EAAE,IAAI,GACT,MAAM,CAUR;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,MAAM,CAMzE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAU/D;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAC1B,MAAM,GAAG,SAAS,CAQpB"}
|
|
@@ -187,7 +187,7 @@ export function installLinkAndRecord({ npmName, clone, relPkg, pkgDir, repo, sub
|
|
|
187
187
|
code,
|
|
188
188
|
entry: {
|
|
189
189
|
name: npmName,
|
|
190
|
-
value: Object.assign(Object.assign(Object.assign(Object.assign({}, (repo ? { repo } : {})), { path: relPkg, branch }), (subdir ? { subdir } : {})), (range ? { range } : {})),
|
|
190
|
+
value: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (repo ? { repo } : {})), { path: relPkg, branch }), (subdir ? { subdir } : {})), (range ? { range } : {})), (shouldPrune(opts) ? {} : { prune: false })),
|
|
191
191
|
},
|
|
192
192
|
};
|
|
193
193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localize.js","sourceRoot":"","sources":["../../../src/localize/localize.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `localize` -- turn an npm-installed dependency into an editable git checkout.\n *\n * The loop, in five steps, none of which involve npm learning anything:\n *\n * 1. npm name -> registry `repository` (see resolve.ts)\n * 2. `git clone` into `<dir>/<name>`\n * 3. **`npm install` INSIDE the checkout**, then prune it (`ensure`)\n * 4. `fs.symlink` node_modules/<name> -> the checkout\n * 5. record it in a gitignored manifest\n *\n * `adopt` (adopt.ts) enters at step 3 with a checkout that is already there,\n * and shares everything from there on: `forEachName` and `installLinkAndRecord`\n * below.\n *\n * Step 3 is the one that is easy to \"simplify\" and must not be. Installing\n * from the parent instead -- `npm install <path> --no-save` -- hard-failed an\n * app's boot on a missing peer dependency, because module resolution happens\n * from the symlink's REAL path, whose ancestors have no `node_modules`. The\n * checkout needs its own installed tree. `tests/unit/localize/real-localize.test.ts` runs a\n * real clone and a real install and asserts the dependency landed inside the\n * checkout, so a reimplementation that moves the install back out fails there.\n *\n * A clone, not a copy: a published tarball has no `src/`, so copying the\n * installed package cannot give you something to edit.\n *\n * What localize NEVER does: run an install at the consumer root, or edit\n * `package.json`, `package-lock.json`, `.gitignore`, `workspaces` or any\n * bundler config. It asserts it did not before exiting 0.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {\n EXIT_INSTALL_FAILED,\n EXIT_NOT_FOUND,\n EXIT_MANIFEST_DIRTY,\n EXIT_REFUSED,\n EXIT_WARNED,\n LocalizeError,\n} from './errors.js';\nimport {\n DEFAULT_DIR,\n SCHEMA_VERSION,\n readManifest,\n writeManifest,\n} from './manifest.js';\nimport type {ManifestEntry} from './manifest.js';\nimport type {Deps} from './run.js';\nimport {checkoutNameFor, resolvePackage} from './resolve.js';\nimport {pruneProvided, shouldPrune} from './prune.js';\nimport {ensure} from './ensure.js';\nimport type {PruneOptions} from './prune.js';\nimport {\n diffManifests,\n isGitCheckout,\n isInside,\n isSymlink,\n readJson,\n snapshotManifests,\n writeLink,\n} from './fsops.js';\n\n/**\n * @param {string[]} names full npm package names\n * @param {object} opts `{force, dir, repo, subdir, build, prune}` -- `prune`\n * defaults to true; see prune.ts\n * @param {object} deps `{appRoot, run, log, warn, error}`\n * @returns {number} the process exit code: the HIGHEST of the per-name codes,\n * since each name is atomic and a failure on name 2 does not undo name 1.\n */\nexport interface LocalizeOptions extends PruneOptions {\n force?: boolean;\n /** Where checkouts live, relative to the app root (default `packages-local`). */\n dir?: string;\n repo?: string;\n subdir?: string;\n /** Run in the checkout after installing; absent or empty runs nothing. */\n build?: string;\n}\n\n/** What one name's work returns to the shared loop. */\nexport interface OneResult {\n code: number;\n entry?: {name: string; value: ManifestEntry};\n}\n\nexport type OneName = (\n name: string,\n dir: string,\n recorded: ManifestEntry | undefined,\n opts: LocalizeOptions,\n deps: Deps,\n) => OneResult;\n\nexport function localize(\n names: string[],\n opts: LocalizeOptions,\n deps: Deps,\n): number {\n return forEachName(names, opts, deps, localizeOne);\n}\n\n/**\n * The loop `localize` and `adopt` share: read the manifest once, run `one` per\n * name, write the manifest after each, then assert the links and the\n * consumer's untouched manifests.\n *\n * @param {(name: string, dir: string, recorded: object|undefined, opts: object, deps: object)\n * => {code: number, entry?: {name: string, value: object}}} one\n */\nexport function forEachName(\n names: string[],\n opts: LocalizeOptions,\n deps: Deps,\n one: OneName,\n): number {\n // Taken BEFORE anything runs: the post-condition is about what THIS run\n // changed, not about what the tree looked like at HEAD.\n const before = snapshotManifests(deps.appRoot);\n\n let manifest;\n try {\n manifest = readManifest(deps.appRoot, deps);\n } catch (e) {\n return reportError(e, deps);\n }\n\n const dir = opts.dir ?? manifest.dir ?? DEFAULT_DIR;\n const entries = {...manifest.entries};\n let code = 0;\n\n for (const name of names) {\n try {\n const result = one(name, dir, entries[name], opts, deps);\n if (result.entry) entries[result.entry.name] = result.entry.value;\n code = Math.max(code, result.code);\n // Written after EACH name, so an interruption keeps what already worked.\n writeManifest(deps.appRoot, {\n version: SCHEMA_VERSION,\n dir,\n packages: entries,\n });\n } catch (e) {\n code = Math.max(code, reportError(e, deps));\n }\n }\n\n // Over EVERY localized checkout, not just the ones named: localizing `B`\n // is what makes `A`'s registry copy of `B` redundant.\n if (shouldPrune(opts)) {\n try {\n pruneProvided(entries, opts, deps);\n } catch (e) {\n deps.warn(\n `[localize] pruning failed, the checkouts' node_modules are as npm left them: ${e.message}`,\n );\n code = Math.max(code, EXIT_WARNED);\n }\n }\n\n code = Math.max(code, assertLinked(entries, deps));\n code = Math.max(code, assertManifestsUntouched(before, deps));\n return code;\n}\n\nfunction localizeOne(\n name: string,\n dir: string,\n recorded: ManifestEntry | undefined,\n opts: LocalizeOptions,\n deps: Deps,\n): OneResult {\n // An override recorded by an earlier run is reused, so `--repo` is a\n // one-time cost rather than something to remember on every invocation.\n const override = opts.repo\n ? {repo: opts.repo, subdir: opts.subdir}\n : recorded?.repo && !looksLikeOrgSlug(recorded.repo)\n ? {repo: recorded.repo, subdir: recorded.subdir}\n : undefined;\n\n const resolved = resolveOrSuggestAdopt(name, dir, override, deps);\n let code = 0;\n\n const relClone = path.join(dir, resolved.checkoutName);\n const clone = path.join(deps.appRoot, relClone);\n // When the repository holds more than this package, the CHECKOUT is the\n // clone but the PACKAGE is a directory inside it: that is where the install\n // runs and that is what the symlink points at.\n const relPkg = resolved.subdir\n ? path.join(relClone, resolved.subdir)\n : relClone;\n const pkgDir = path.join(deps.appRoot, relPkg);\n\n guardForeignLink(resolved.npmName, dir, opts, deps);\n\n if (isGitCheckout(clone)) {\n code = Math.max(code, refresh(relClone, clone, deps));\n if (code === EXIT_WARNED) return {code}; // a non-fast-forward is reported, never forced\n } else {\n fs.mkdirSync(path.dirname(clone), {recursive: true});\n deps.log(`[localize] cloning ${resolved.repo} -> ${relClone}`);\n const r = deps.run('git', ['clone', resolved.repo, clone]);\n if (r.status !== 0) {\n throw new LocalizeError(\n `git clone ${resolved.repo} failed:\\n${(r.stderr || r.stdout).trim()}`,\n EXIT_REFUSED,\n );\n }\n }\n\n if (!fs.existsSync(path.join(pkgDir, 'package.json'))) {\n throw new LocalizeError(\n `${relPkg} has no package.json, so it is not the package \"${name}\".\\n` +\n (resolved.subdir\n ? `The registry says \"${name}\" lives in \"${resolved.subdir}\" of ${resolved.repo}, and it does not.`\n : `${resolved.repo} looks like a monorepo root. Say where the package lives:\\n` +\n ` linked localize ${name} --repo ${resolved.repo} --subdir <path-inside-the-repo>`),\n EXIT_REFUSED,\n );\n }\n\n // The checkout's own package.json is authoritative about the name: a\n // mismatch means the symlink would be written under a name nothing imports.\n const declared = readJson(path.join(pkgDir, 'package.json'))?.name;\n if (declared && declared !== resolved.npmName) {\n throw new LocalizeError(\n `${relPkg} declares itself as \"${declared}\", not \"${name}\".\\n` +\n (resolved.subdir\n ? `The registry's repository.directory for \"${name}\" points at the wrong package.`\n : `${resolved.repo} is probably a monorepo. Point at the right directory:\\n` +\n ` linked localize ${name} --repo ${resolved.repo} --subdir <path-inside-the-repo>`),\n EXIT_REFUSED,\n );\n }\n\n return installLinkAndRecord(\n {\n npmName: resolved.npmName,\n clone,\n relPkg,\n pkgDir,\n repo: resolved.repo,\n subdir: resolved.subdir,\n },\n opts,\n deps,\n code,\n );\n}\n\n/**\n * Everything after the checkout exists, shared by `localize` and `adopt`:\n * install inside it, run the configured build, link it, and describe the\n * manifest entry. Nothing here knows how the checkout got there.\n *\n * `repo` may be absent -- an adopted checkout with no remote is recorded\n * without one.\n */\nexport function installLinkAndRecord(\n {\n npmName,\n clone,\n relPkg,\n pkgDir,\n repo,\n subdir,\n }: {\n npmName: string;\n clone: string;\n relPkg: string;\n pkgDir: string;\n repo?: string;\n subdir?: string;\n },\n opts: LocalizeOptions,\n deps: Deps,\n code = 0,\n): {code: number; entry: {name: string; value: ManifestEntry}} {\n // THE constraint. Read the module header before changing this. `ensure`\n // installs inside the checkout and prunes it as one step (ensure.ts).\n try {\n code = Math.max(code, ensure({path: relPkg, subdir}, deps, opts));\n } catch (e) {\n if (e instanceof LocalizeError && e.code === EXIT_INSTALL_FAILED)\n e.message += `\\nThe checkout is left on disk. Nothing was linked and nothing was recorded.`;\n throw e;\n }\n\n // The build is the one thing localize does not know how to do, so it is\n // configuration rather than behaviour. A failure is a WARNING: a package\n // whose build is broken is exactly what you are about to fix, and refusing\n // to link it would be perverse.\n if (runBuild(relPkg, pkgDir, opts, deps) === 'failed')\n code = Math.max(code, EXIT_WARNED);\n\n writeLink(deps.appRoot, npmName, pkgDir);\n const branch = currentBranch(clone, deps);\n deps.log(`[localize] linked ${npmName} -> ${relPkg} (branch ${branch})`);\n\n const range = declaredRange(npmName, deps);\n return {\n code,\n entry: {\n name: npmName,\n value: {\n ...(repo ? {repo} : {}),\n path: relPkg,\n branch,\n ...(subdir ? {subdir} : {}),\n ...(range ? {range} : {}),\n },\n },\n };\n}\n\n/**\n * A registry lookup that fails while a git checkout already sits where the\n * clone would go is almost always a package that was never published -- one\n * made locally. Say how to link it as it is rather than leave the developer\n * guessing at a `--repo`.\n */\nfunction resolveOrSuggestAdopt(name, dir, override, deps) {\n try {\n return resolvePackage(name, deps, override);\n } catch (e) {\n const relClone = path.join(dir, checkoutNameFor(name));\n if (\n e instanceof LocalizeError &&\n e.code === EXIT_NOT_FOUND &&\n isGitCheckout(path.join(deps.appRoot, relClone))\n ) {\n e.message +=\n `\\n${relClone} is already a git checkout. To link it as it is, with no registry lookup:\\n` +\n ` linked localize ${name} --adopt`;\n }\n throw e;\n }\n}\n\n/** Older manifests recorded `owner/repo`; those are re-resolved rather than cloned blind. */\nfunction looksLikeOrgSlug(repo) {\n return /^[\\w.-]+\\/[\\w.-]+$/.test(repo);\n}\n\n/**\n * Reuse an existing clone. A dirty tree is reused WITHOUT pulling and said so;\n * a clean one is fast-forwarded; a non-fast-forward is reported and skipped\n * rather than forced, because the developer's commits are the entire point.\n */\nfunction refresh(relPath, clone, deps) {\n const status = deps.run('git', ['status', '--porcelain'], {cwd: clone});\n const modified = status.stdout.split('\\n').filter((l) => l.trim()).length;\n if (modified > 0) {\n deps.log(\n `[localize] ${relPath}: ${modified} modified file${modified === 1 ? '' : 's'} — not pulling`,\n );\n return 0;\n }\n const pull = deps.run('git', ['pull', '--ff-only'], {cwd: clone});\n if (pull.status !== 0) {\n deps.warn(\n `[localize] ${relPath}: \\`git pull --ff-only\\` failed (not a fast-forward) — skipped, not ` +\n `forced. Reconcile it by hand:\\n${(pull.stderr || pull.stdout).trim()}`,\n );\n return EXIT_WARNED;\n }\n return 0;\n}\n\n/**\n * Run the configured build command, if there is one.\n *\n * localize has no opinion about how a checkout is built, and does not look for\n * a builder. `--build \"<cmd>\"`, or a `build` field in the manifest, or\n * `{build}` in the programmatic options. Absent -- the common case, and the\n * case for anything whose dev loop reads source directly -- nothing runs and\n * nothing is said.\n */\nfunction runBuild(relPath, pkgDir, opts, deps) {\n const cmd = opts.build;\n if (!cmd) return 'skipped';\n deps.log(`[localize] ${relPath}: ${cmd}`);\n const r = deps.run(cmd, [], {cwd: pkgDir, shell: true});\n if (r.status !== 0) {\n deps.warn(\n `[localize] ${relPath}: \\`${cmd}\\` failed. The package is linked and recorded anyway — ` +\n `a package whose build is broken is exactly what you are about to fix.\\n` +\n `${(r.stderr || r.stdout).trim()}`,\n );\n return 'failed';\n }\n return 'ok';\n}\n\n/** Refuse when `node_modules/<name>` is already a symlink pointing outside `<dir>`. */\nexport function guardForeignLink(\n npmName: string,\n dir: string,\n opts: {force?: boolean},\n deps: Deps,\n): void {\n const link = path.join(deps.appRoot, 'node_modules', npmName);\n if (!isSymlink(link)) return;\n let target;\n try {\n target = fs.realpathSync(link);\n } catch {\n return; // a dangling link is ours to replace\n }\n if (isInside(target, path.join(deps.appRoot, dir))) return;\n if (opts.force) {\n deps.warn(\n `[localize] --force: overwriting the existing link ${npmName} -> ${target}`,\n );\n return;\n }\n throw new LocalizeError(\n `node_modules/${npmName} is already a symlink to ${target}, which is outside ${dir}.\\n` +\n `Refusing to overwrite someone else's link. Pass --force to replace it.`,\n EXIT_REFUSED,\n );\n}\n\n/** Every recorded package is actually linked where the manifest says it is. */\nfunction assertLinked(entries: Record<string, ManifestEntry>, deps: Deps) {\n let code = 0;\n for (const [name, entry] of Object.entries(entries)) {\n const link = path.join(deps.appRoot, 'node_modules', name);\n const expected = path.join(deps.appRoot, entry.path);\n if (!isSymlink(link)) {\n deps.warn(\n `[localize] ${name} is recorded but node_modules/${name} is not a symlink.`,\n );\n code = Math.max(code, EXIT_WARNED);\n continue;\n }\n if (!fs.existsSync(expected)) continue; // \"checkout missing\" is a --list state, not a failure\n if (fs.realpathSync(link) !== fs.realpathSync(expected)) {\n deps.warn(\n `[localize] ${name} links to ${fs.realpathSync(link)} but the manifest records ${entry.path}.`,\n );\n code = Math.max(code, EXIT_WARNED);\n }\n }\n return code;\n}\n\n/**\n * The property the whole design rests on: this run changed neither manifest.\n *\n * Content hashes, not `git status`. `git status` compares against HEAD, so in\n * any tree with an uncommitted `package.json` it reports a modification the\n * command did not make -- an earlier tool shipped exactly that and reported\n * correct runs as failures.\n */\nexport function assertManifestsUntouched(\n before: Record<string, string | null>,\n deps: Deps,\n): number {\n const changed = diffManifests(before, snapshotManifests(deps.appRoot));\n if (!changed.length) return 0;\n deps.error(\n `[localize] the consumer's manifests changed while this command ran:\\n` +\n changed.map((c) => ` ${c}`).join('\\n') +\n `\\nThis is the exact failure localize exists to prevent. Revert those files; nothing in ` +\n `localize is supposed to touch them.`,\n );\n return EXIT_MANIFEST_DIRTY;\n}\n\nexport function reportError(e: unknown, deps: Pick<Deps, 'error'>): number {\n if (e instanceof LocalizeError) {\n deps.error(`[localize] ${e.message}`);\n return e.code;\n }\n throw e;\n}\n\n/**\n * The checked-out branch, or `HEAD` when detached. `symbolic-ref` first,\n * because it also names the branch of a repository with no commits yet --\n * `rev-parse --abbrev-ref` fails there, and `create-package` adopts a fresh\n * `git init` before its first commit.\n */\nexport function currentBranch(clone: string, deps: Deps): string {\n const sym = deps.run('git', ['symbolic-ref', '--short', '-q', 'HEAD'], {\n cwd: clone,\n });\n if (sym.status === 0 && sym.stdout.trim()) return sym.stdout.trim();\n const r = deps.run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {\n cwd: clone,\n });\n const b = r.stdout.trim();\n return r.status === 0 && b ? b : 'HEAD';\n}\n\nexport function declaredRange(\n name: string,\n deps: Pick<Deps, 'appRoot'>,\n): string | undefined {\n const pkg = readJson(path.join(deps.appRoot, 'package.json'));\n if (!pkg) return undefined;\n return (\n pkg.dependencies?.[name] ??\n pkg.devDependencies?.[name] ??\n pkg.optionalDependencies?.[name]\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"localize.js","sourceRoot":"","sources":["../../../src/localize/localize.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `localize` -- turn an npm-installed dependency into an editable git checkout.\n *\n * The loop, in five steps, none of which involve npm learning anything:\n *\n * 1. npm name -> registry `repository` (see resolve.ts)\n * 2. `git clone` into `<dir>/<name>`\n * 3. **`npm install` INSIDE the checkout**, then prune it (`ensure`)\n * 4. `fs.symlink` node_modules/<name> -> the checkout\n * 5. record it in a gitignored manifest\n *\n * `adopt` (adopt.ts) enters at step 3 with a checkout that is already there,\n * and shares everything from there on: `forEachName` and `installLinkAndRecord`\n * below.\n *\n * Step 3 is the one that is easy to \"simplify\" and must not be. Installing\n * from the parent instead -- `npm install <path> --no-save` -- hard-failed an\n * app's boot on a missing peer dependency, because module resolution happens\n * from the symlink's REAL path, whose ancestors have no `node_modules`. The\n * checkout needs its own installed tree. `tests/unit/localize/real-localize.test.ts` runs a\n * real clone and a real install and asserts the dependency landed inside the\n * checkout, so a reimplementation that moves the install back out fails there.\n *\n * A clone, not a copy: a published tarball has no `src/`, so copying the\n * installed package cannot give you something to edit.\n *\n * What localize NEVER does: run an install at the consumer root, or edit\n * `package.json`, `package-lock.json`, `.gitignore`, `workspaces` or any\n * bundler config. It asserts it did not before exiting 0.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {\n EXIT_INSTALL_FAILED,\n EXIT_NOT_FOUND,\n EXIT_MANIFEST_DIRTY,\n EXIT_REFUSED,\n EXIT_WARNED,\n LocalizeError,\n} from './errors.js';\nimport {\n DEFAULT_DIR,\n SCHEMA_VERSION,\n readManifest,\n writeManifest,\n} from './manifest.js';\nimport type {ManifestEntry} from './manifest.js';\nimport type {Deps} from './run.js';\nimport {checkoutNameFor, resolvePackage} from './resolve.js';\nimport {pruneProvided, shouldPrune} from './prune.js';\nimport {ensure} from './ensure.js';\nimport type {PruneOptions} from './prune.js';\nimport {\n diffManifests,\n isGitCheckout,\n isInside,\n isSymlink,\n readJson,\n snapshotManifests,\n writeLink,\n} from './fsops.js';\n\n/**\n * @param {string[]} names full npm package names\n * @param {object} opts `{force, dir, repo, subdir, build, prune}` -- `prune`\n * defaults to true; see prune.ts\n * @param {object} deps `{appRoot, run, log, warn, error}`\n * @returns {number} the process exit code: the HIGHEST of the per-name codes,\n * since each name is atomic and a failure on name 2 does not undo name 1.\n */\nexport interface LocalizeOptions extends PruneOptions {\n force?: boolean;\n /** Where checkouts live, relative to the app root (default `packages-local`). */\n dir?: string;\n repo?: string;\n subdir?: string;\n /** Run in the checkout after installing; absent or empty runs nothing. */\n build?: string;\n}\n\n/** What one name's work returns to the shared loop. */\nexport interface OneResult {\n code: number;\n entry?: {name: string; value: ManifestEntry};\n}\n\nexport type OneName = (\n name: string,\n dir: string,\n recorded: ManifestEntry | undefined,\n opts: LocalizeOptions,\n deps: Deps,\n) => OneResult;\n\nexport function localize(\n names: string[],\n opts: LocalizeOptions,\n deps: Deps,\n): number {\n return forEachName(names, opts, deps, localizeOne);\n}\n\n/**\n * The loop `localize` and `adopt` share: read the manifest once, run `one` per\n * name, write the manifest after each, then assert the links and the\n * consumer's untouched manifests.\n *\n * @param {(name: string, dir: string, recorded: object|undefined, opts: object, deps: object)\n * => {code: number, entry?: {name: string, value: object}}} one\n */\nexport function forEachName(\n names: string[],\n opts: LocalizeOptions,\n deps: Deps,\n one: OneName,\n): number {\n // Taken BEFORE anything runs: the post-condition is about what THIS run\n // changed, not about what the tree looked like at HEAD.\n const before = snapshotManifests(deps.appRoot);\n\n let manifest;\n try {\n manifest = readManifest(deps.appRoot, deps);\n } catch (e) {\n return reportError(e, deps);\n }\n\n const dir = opts.dir ?? manifest.dir ?? DEFAULT_DIR;\n const entries = {...manifest.entries};\n let code = 0;\n\n for (const name of names) {\n try {\n const result = one(name, dir, entries[name], opts, deps);\n if (result.entry) entries[result.entry.name] = result.entry.value;\n code = Math.max(code, result.code);\n // Written after EACH name, so an interruption keeps what already worked.\n writeManifest(deps.appRoot, {\n version: SCHEMA_VERSION,\n dir,\n packages: entries,\n });\n } catch (e) {\n code = Math.max(code, reportError(e, deps));\n }\n }\n\n // Over EVERY localized checkout, not just the ones named: localizing `B`\n // is what makes `A`'s registry copy of `B` redundant.\n if (shouldPrune(opts)) {\n try {\n pruneProvided(entries, opts, deps);\n } catch (e) {\n deps.warn(\n `[localize] pruning failed, the checkouts' node_modules are as npm left them: ${e.message}`,\n );\n code = Math.max(code, EXIT_WARNED);\n }\n }\n\n code = Math.max(code, assertLinked(entries, deps));\n code = Math.max(code, assertManifestsUntouched(before, deps));\n return code;\n}\n\nfunction localizeOne(\n name: string,\n dir: string,\n recorded: ManifestEntry | undefined,\n opts: LocalizeOptions,\n deps: Deps,\n): OneResult {\n // An override recorded by an earlier run is reused, so `--repo` is a\n // one-time cost rather than something to remember on every invocation.\n const override = opts.repo\n ? {repo: opts.repo, subdir: opts.subdir}\n : recorded?.repo && !looksLikeOrgSlug(recorded.repo)\n ? {repo: recorded.repo, subdir: recorded.subdir}\n : undefined;\n\n const resolved = resolveOrSuggestAdopt(name, dir, override, deps);\n let code = 0;\n\n const relClone = path.join(dir, resolved.checkoutName);\n const clone = path.join(deps.appRoot, relClone);\n // When the repository holds more than this package, the CHECKOUT is the\n // clone but the PACKAGE is a directory inside it: that is where the install\n // runs and that is what the symlink points at.\n const relPkg = resolved.subdir\n ? path.join(relClone, resolved.subdir)\n : relClone;\n const pkgDir = path.join(deps.appRoot, relPkg);\n\n guardForeignLink(resolved.npmName, dir, opts, deps);\n\n if (isGitCheckout(clone)) {\n code = Math.max(code, refresh(relClone, clone, deps));\n if (code === EXIT_WARNED) return {code}; // a non-fast-forward is reported, never forced\n } else {\n fs.mkdirSync(path.dirname(clone), {recursive: true});\n deps.log(`[localize] cloning ${resolved.repo} -> ${relClone}`);\n const r = deps.run('git', ['clone', resolved.repo, clone]);\n if (r.status !== 0) {\n throw new LocalizeError(\n `git clone ${resolved.repo} failed:\\n${(r.stderr || r.stdout).trim()}`,\n EXIT_REFUSED,\n );\n }\n }\n\n if (!fs.existsSync(path.join(pkgDir, 'package.json'))) {\n throw new LocalizeError(\n `${relPkg} has no package.json, so it is not the package \"${name}\".\\n` +\n (resolved.subdir\n ? `The registry says \"${name}\" lives in \"${resolved.subdir}\" of ${resolved.repo}, and it does not.`\n : `${resolved.repo} looks like a monorepo root. Say where the package lives:\\n` +\n ` linked localize ${name} --repo ${resolved.repo} --subdir <path-inside-the-repo>`),\n EXIT_REFUSED,\n );\n }\n\n // The checkout's own package.json is authoritative about the name: a\n // mismatch means the symlink would be written under a name nothing imports.\n const declared = readJson(path.join(pkgDir, 'package.json'))?.name;\n if (declared && declared !== resolved.npmName) {\n throw new LocalizeError(\n `${relPkg} declares itself as \"${declared}\", not \"${name}\".\\n` +\n (resolved.subdir\n ? `The registry's repository.directory for \"${name}\" points at the wrong package.`\n : `${resolved.repo} is probably a monorepo. Point at the right directory:\\n` +\n ` linked localize ${name} --repo ${resolved.repo} --subdir <path-inside-the-repo>`),\n EXIT_REFUSED,\n );\n }\n\n return installLinkAndRecord(\n {\n npmName: resolved.npmName,\n clone,\n relPkg,\n pkgDir,\n repo: resolved.repo,\n subdir: resolved.subdir,\n },\n opts,\n deps,\n code,\n );\n}\n\n/**\n * Everything after the checkout exists, shared by `localize` and `adopt`:\n * install inside it, run the configured build, link it, and describe the\n * manifest entry. Nothing here knows how the checkout got there.\n *\n * `repo` may be absent -- an adopted checkout with no remote is recorded\n * without one.\n */\nexport function installLinkAndRecord(\n {\n npmName,\n clone,\n relPkg,\n pkgDir,\n repo,\n subdir,\n }: {\n npmName: string;\n clone: string;\n relPkg: string;\n pkgDir: string;\n repo?: string;\n subdir?: string;\n },\n opts: LocalizeOptions,\n deps: Deps,\n code = 0,\n): {code: number; entry: {name: string; value: ManifestEntry}} {\n // THE constraint. Read the module header before changing this. `ensure`\n // installs inside the checkout and prunes it as one step (ensure.ts).\n try {\n code = Math.max(code, ensure({path: relPkg, subdir}, deps, opts));\n } catch (e) {\n if (e instanceof LocalizeError && e.code === EXIT_INSTALL_FAILED)\n e.message += `\\nThe checkout is left on disk. Nothing was linked and nothing was recorded.`;\n throw e;\n }\n\n // The build is the one thing localize does not know how to do, so it is\n // configuration rather than behaviour. A failure is a WARNING: a package\n // whose build is broken is exactly what you are about to fix, and refusing\n // to link it would be perverse.\n if (runBuild(relPkg, pkgDir, opts, deps) === 'failed')\n code = Math.max(code, EXIT_WARNED);\n\n writeLink(deps.appRoot, npmName, pkgDir);\n const branch = currentBranch(clone, deps);\n deps.log(`[localize] linked ${npmName} -> ${relPkg} (branch ${branch})`);\n\n const range = declaredRange(npmName, deps);\n return {\n code,\n entry: {\n name: npmName,\n value: {\n ...(repo ? {repo} : {}),\n path: relPkg,\n branch,\n ...(subdir ? {subdir} : {}),\n ...(range ? {range} : {}),\n // `--no-prune` is remembered, so the run-time check and `--relink` honour it too.\n ...(shouldPrune(opts) ? {} : {prune: false as const}),\n },\n },\n };\n}\n\n/**\n * A registry lookup that fails while a git checkout already sits where the\n * clone would go is almost always a package that was never published -- one\n * made locally. Say how to link it as it is rather than leave the developer\n * guessing at a `--repo`.\n */\nfunction resolveOrSuggestAdopt(name, dir, override, deps) {\n try {\n return resolvePackage(name, deps, override);\n } catch (e) {\n const relClone = path.join(dir, checkoutNameFor(name));\n if (\n e instanceof LocalizeError &&\n e.code === EXIT_NOT_FOUND &&\n isGitCheckout(path.join(deps.appRoot, relClone))\n ) {\n e.message +=\n `\\n${relClone} is already a git checkout. To link it as it is, with no registry lookup:\\n` +\n ` linked localize ${name} --adopt`;\n }\n throw e;\n }\n}\n\n/** Older manifests recorded `owner/repo`; those are re-resolved rather than cloned blind. */\nfunction looksLikeOrgSlug(repo) {\n return /^[\\w.-]+\\/[\\w.-]+$/.test(repo);\n}\n\n/**\n * Reuse an existing clone. A dirty tree is reused WITHOUT pulling and said so;\n * a clean one is fast-forwarded; a non-fast-forward is reported and skipped\n * rather than forced, because the developer's commits are the entire point.\n */\nfunction refresh(relPath, clone, deps) {\n const status = deps.run('git', ['status', '--porcelain'], {cwd: clone});\n const modified = status.stdout.split('\\n').filter((l) => l.trim()).length;\n if (modified > 0) {\n deps.log(\n `[localize] ${relPath}: ${modified} modified file${modified === 1 ? '' : 's'} — not pulling`,\n );\n return 0;\n }\n const pull = deps.run('git', ['pull', '--ff-only'], {cwd: clone});\n if (pull.status !== 0) {\n deps.warn(\n `[localize] ${relPath}: \\`git pull --ff-only\\` failed (not a fast-forward) — skipped, not ` +\n `forced. Reconcile it by hand:\\n${(pull.stderr || pull.stdout).trim()}`,\n );\n return EXIT_WARNED;\n }\n return 0;\n}\n\n/**\n * Run the configured build command, if there is one.\n *\n * localize has no opinion about how a checkout is built, and does not look for\n * a builder. `--build \"<cmd>\"`, or a `build` field in the manifest, or\n * `{build}` in the programmatic options. Absent -- the common case, and the\n * case for anything whose dev loop reads source directly -- nothing runs and\n * nothing is said.\n */\nfunction runBuild(relPath, pkgDir, opts, deps) {\n const cmd = opts.build;\n if (!cmd) return 'skipped';\n deps.log(`[localize] ${relPath}: ${cmd}`);\n const r = deps.run(cmd, [], {cwd: pkgDir, shell: true});\n if (r.status !== 0) {\n deps.warn(\n `[localize] ${relPath}: \\`${cmd}\\` failed. The package is linked and recorded anyway — ` +\n `a package whose build is broken is exactly what you are about to fix.\\n` +\n `${(r.stderr || r.stdout).trim()}`,\n );\n return 'failed';\n }\n return 'ok';\n}\n\n/** Refuse when `node_modules/<name>` is already a symlink pointing outside `<dir>`. */\nexport function guardForeignLink(\n npmName: string,\n dir: string,\n opts: {force?: boolean},\n deps: Deps,\n): void {\n const link = path.join(deps.appRoot, 'node_modules', npmName);\n if (!isSymlink(link)) return;\n let target;\n try {\n target = fs.realpathSync(link);\n } catch {\n return; // a dangling link is ours to replace\n }\n if (isInside(target, path.join(deps.appRoot, dir))) return;\n if (opts.force) {\n deps.warn(\n `[localize] --force: overwriting the existing link ${npmName} -> ${target}`,\n );\n return;\n }\n throw new LocalizeError(\n `node_modules/${npmName} is already a symlink to ${target}, which is outside ${dir}.\\n` +\n `Refusing to overwrite someone else's link. Pass --force to replace it.`,\n EXIT_REFUSED,\n );\n}\n\n/** Every recorded package is actually linked where the manifest says it is. */\nfunction assertLinked(entries: Record<string, ManifestEntry>, deps: Deps) {\n let code = 0;\n for (const [name, entry] of Object.entries(entries)) {\n const link = path.join(deps.appRoot, 'node_modules', name);\n const expected = path.join(deps.appRoot, entry.path);\n if (!isSymlink(link)) {\n deps.warn(\n `[localize] ${name} is recorded but node_modules/${name} is not a symlink.`,\n );\n code = Math.max(code, EXIT_WARNED);\n continue;\n }\n if (!fs.existsSync(expected)) continue; // \"checkout missing\" is a --list state, not a failure\n if (fs.realpathSync(link) !== fs.realpathSync(expected)) {\n deps.warn(\n `[localize] ${name} links to ${fs.realpathSync(link)} but the manifest records ${entry.path}.`,\n );\n code = Math.max(code, EXIT_WARNED);\n }\n }\n return code;\n}\n\n/**\n * The property the whole design rests on: this run changed neither manifest.\n *\n * Content hashes, not `git status`. `git status` compares against HEAD, so in\n * any tree with an uncommitted `package.json` it reports a modification the\n * command did not make -- an earlier tool shipped exactly that and reported\n * correct runs as failures.\n */\nexport function assertManifestsUntouched(\n before: Record<string, string | null>,\n deps: Deps,\n): number {\n const changed = diffManifests(before, snapshotManifests(deps.appRoot));\n if (!changed.length) return 0;\n deps.error(\n `[localize] the consumer's manifests changed while this command ran:\\n` +\n changed.map((c) => ` ${c}`).join('\\n') +\n `\\nThis is the exact failure localize exists to prevent. Revert those files; nothing in ` +\n `localize is supposed to touch them.`,\n );\n return EXIT_MANIFEST_DIRTY;\n}\n\nexport function reportError(e: unknown, deps: Pick<Deps, 'error'>): number {\n if (e instanceof LocalizeError) {\n deps.error(`[localize] ${e.message}`);\n return e.code;\n }\n throw e;\n}\n\n/**\n * The checked-out branch, or `HEAD` when detached. `symbolic-ref` first,\n * because it also names the branch of a repository with no commits yet --\n * `rev-parse --abbrev-ref` fails there, and `create-package` adopts a fresh\n * `git init` before its first commit.\n */\nexport function currentBranch(clone: string, deps: Deps): string {\n const sym = deps.run('git', ['symbolic-ref', '--short', '-q', 'HEAD'], {\n cwd: clone,\n });\n if (sym.status === 0 && sym.stdout.trim()) return sym.stdout.trim();\n const r = deps.run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {\n cwd: clone,\n });\n const b = r.stdout.trim();\n return r.status === 0 && b ? b : 'HEAD';\n}\n\nexport function declaredRange(\n name: string,\n deps: Pick<Deps, 'appRoot'>,\n): string | undefined {\n const pkg = readJson(path.join(deps.appRoot, 'package.json'));\n if (!pkg) return undefined;\n return (\n pkg.dependencies?.[name] ??\n pkg.devDependencies?.[name] ??\n pkg.optionalDependencies?.[name]\n );\n}\n"]}
|
|
@@ -10,6 +10,15 @@ export interface ManifestEntry {
|
|
|
10
10
|
subdir?: string;
|
|
11
11
|
/** The range the app declared when it was localized. */
|
|
12
12
|
range?: string;
|
|
13
|
+
/**
|
|
14
|
+
* `false` when the package was localized or adopted with `--no-prune`: its
|
|
15
|
+
* checkout's `node_modules` stay as npm installed them -- no prune after
|
|
16
|
+
* `--relink` or `--reinstall`, and the run-time check (`--ensure`, before
|
|
17
|
+
* `linked start` etc.) skips it. Absent means on; localizing or adopting it
|
|
18
|
+
* again without `--no-prune` turns it back on. Optional, so schema version 1
|
|
19
|
+
* readers that do not know it simply ignore it.
|
|
20
|
+
*/
|
|
21
|
+
prune?: false;
|
|
13
22
|
}
|
|
14
23
|
export interface Manifest {
|
|
15
24
|
file: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/localize/manifest.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/localize/manifest.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,SAAS,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;CAC7C;AAED,sDAAsD;AACtD,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,iEAAiE;AACjE,eAAO,MAAM,WAAW,mBAAmB,CAAC;AAE5C,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,EAAE,GAAE;IAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAwB,GAC3D,QAAQ,CAyFV;AAiBD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC1C,GACA,MAAM,CAcR"}
|
|
@@ -95,9 +95,9 @@ export function readManifest(appRoot, io = { warn: console.warn }) {
|
|
|
95
95
|
`The other entries are unaffected. \`linked localize ${name}\` rewrites it.`);
|
|
96
96
|
continue;
|
|
97
97
|
}
|
|
98
|
-
entries[name] = Object.assign(Object.assign(Object.assign(Object.assign({}, (typeof value.repo === 'string' && value.repo
|
|
98
|
+
entries[name] = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (typeof value.repo === 'string' && value.repo
|
|
99
99
|
? { repo: value.repo }
|
|
100
|
-
: {})), { path: value.path, branch: value.branch }), (typeof value.subdir === 'string' ? { subdir: value.subdir } : {})), (typeof value.range === 'string' ? { range: value.range } : {}));
|
|
100
|
+
: {})), { path: value.path, branch: value.branch }), (typeof value.subdir === 'string' ? { subdir: value.subdir } : {})), (typeof value.range === 'string' ? { range: value.range } : {})), (value.prune === false ? { prune: false } : {}));
|
|
101
101
|
}
|
|
102
102
|
return { file, exists: true, version: SCHEMA_VERSION, dir, entries, malformed };
|
|
103
103
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/localize/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `local-packages.json` -- the record of which packages are currently localized.\n *\n * The filename and schema are deliberately the SAME as the ones `@semantu/cli`\n * already writes (schema version 1, keys are npm package names). A developer\n * with a half-localized tree must be able to switch tools without re-cloning,\n * and the consumer's `postinstall` must keep working across the switch.\n *\n * One relaxation since 0.1.0: `repo` is optional, because an adopted checkout\n * may have no remote. localize 0.1.0 skips such an entry as partial, with a\n * warning, and keeps the rest; other readers of this schema were not checked.\n *\n * Two properties are load-bearing:\n *\n * 1. **It is never repaired.** Unparseable JSON, an unknown `version` or a\n * `packages` that is not an object is a refusal (exit 3) with no write.\n * This file is the only record of what a developer intended; silently\n * resetting it is how a half-localized tree becomes invisible.\n * 2. **Writes are atomic** -- `<file>.tmp` then `rename` -- so a killed run\n * cannot leave a truncated file behind.\n *\n * A *partial entry* is different from a malformed file: it is skipped with a\n * warning and its siblings still process, because one bad entry must not cost\n * a developer the other nine.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {EXIT_BAD_FILE, LocalizeError} from './errors.js';\n\nexport const MANIFEST_FILENAME = 'local-packages.json';\n\n/** One recorded package: where its checkout is, and where it came from. */\nexport interface ManifestEntry {\n /** Absent for an adopted checkout with no remote. */\n repo?: string;\n /** The package directory, relative to the app root. */\n path: string;\n branch: string;\n /** The package's directory inside the clone, for a monorepo. */\n subdir?: string;\n /** The range the app declared when it was localized. */\n range?: string;\n}\n\nexport interface Manifest {\n file: string;\n exists: boolean;\n version: number;\n dir: string;\n entries: Record<string, ManifestEntry>;\n malformed: {name: string; reason: string}[];\n}\n\n/** The only schema version this build understands. */\nexport const SCHEMA_VERSION = 1;\n\n/** Default checkout directory, relative to the consumer root. */\nexport const DEFAULT_DIR = 'packages-local';\n\nexport function manifestPath(appRoot: string): string {\n return path.join(appRoot, MANIFEST_FILENAME);\n}\n\n/**\n * Read and validate the manifest.\n *\n * A missing file is NOT an error: it is the CI case and the fresh-clone case,\n * and reads as an empty set. That is also why no `if (CI)` branch exists\n * anywhere in this package -- the file is gitignored, so CI is a natural no-op.\n *\n * @throws {LocalizeError} code 3. Nothing is written in any failure case.\n */\nexport function readManifest(\n appRoot: string,\n io: {warn: (message: string) => void} = {warn: console.warn},\n): Manifest {\n const file = manifestPath(appRoot);\n\n if (!fs.existsSync(file)) {\n return {\n file,\n exists: false,\n version: SCHEMA_VERSION,\n dir: DEFAULT_DIR,\n entries: {},\n malformed: [],\n };\n }\n\n const raw = fs.readFileSync(file, 'utf8');\n let parsed;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n throw new LocalizeError(\n `${file} is not valid JSON: ${e.message}\\n` +\n `Refusing to read or rewrite it -- it is the only record of what was localized. ` +\n `Fix it by hand, or delete it to start over.`,\n EXIT_BAD_FILE,\n );\n }\n\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new LocalizeError(\n `${file} does not contain a JSON object.\\n` +\n `Refusing to read or rewrite it. Expected {\"version\":${SCHEMA_VERSION},\"packages\":{…}}.`,\n EXIT_BAD_FILE,\n );\n }\n\n if (parsed.version !== SCHEMA_VERSION) {\n throw new LocalizeError(\n `${file} has schema version ${JSON.stringify(parsed.version)}; this version of localize understands ` +\n `only version ${SCHEMA_VERSION}.\\n` +\n `Refusing to read or rewrite it -- guessing at a schema it did not write is how intent ` +\n `gets lost. Upgrade localize, or delete the file and re-localize.`,\n EXIT_BAD_FILE,\n );\n }\n\n if (\n parsed.packages === null ||\n typeof parsed.packages !== 'object' ||\n Array.isArray(parsed.packages)\n ) {\n throw new LocalizeError(\n `${file} has a \"packages\" field that is not an object (found ` +\n `${Array.isArray(parsed.packages) ? 'an array' : typeof parsed.packages}).\\n` +\n `Refusing to read or rewrite it.`,\n EXIT_BAD_FILE,\n );\n }\n\n const dir =\n typeof parsed.dir === 'string' && parsed.dir.length > 0\n ? parsed.dir\n : DEFAULT_DIR;\n\n const entries: Record<string, ManifestEntry> = {};\n const malformed: Manifest['malformed'] = [];\n\n for (const [name, value] of Object.entries<any>(parsed.packages)) {\n const reason = validateEntry(value);\n if (reason) {\n malformed.push({name, reason});\n io.warn(\n `[localize] ${name}: malformed entry in ${MANIFEST_FILENAME} (${reason}) -- skipped. ` +\n `The other entries are unaffected. \\`linked localize ${name}\\` rewrites it.`,\n );\n continue;\n }\n entries[name] = {\n ...(typeof value.repo === 'string' && value.repo\n ? {repo: value.repo}\n : {}),\n path: value.path,\n branch: value.branch,\n ...(typeof value.subdir === 'string' ? {subdir: value.subdir} : {}),\n ...(typeof value.range === 'string' ? {range: value.range} : {}),\n };\n }\n\n return {file, exists: true, version: SCHEMA_VERSION, dir, entries, malformed};\n}\n\n/**\n * @returns {string|null} a reason the entry is unusable, else null.\n *\n * `repo` is optional: an adopted checkout may have no remote at all -- a\n * package created locally that has not been pushed anywhere yet.\n */\nfunction validateEntry(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return 'not an object';\n const missing = ['path', 'branch'].filter(\n (k) => typeof value[k] !== 'string' || value[k].length === 0,\n );\n return missing.length ? `missing ${missing.join(', ')}` : null;\n}\n\n/**\n * Write the manifest atomically: a `.tmp` in the SAME directory, so `rename`\n * is atomic on one filesystem, then `rename` over the original.\n *\n * An empty `packages` object is written rather than the file being deleted, so\n * a non-default `dir` survives delocalizing the last entry.\n */\nexport function writeManifest(\n appRoot: string,\n data: {\n version?: number;\n dir?: string;\n packages?: Record<string, ManifestEntry>;\n },\n): string {\n const target = manifestPath(appRoot);\n const tmp = `${target}.tmp`;\n\n const out = {\n version: SCHEMA_VERSION,\n ...(data.dir && data.dir !== DEFAULT_DIR ? {dir: data.dir} : {}),\n packages: data.packages ?? {},\n };\n\n fs.mkdirSync(path.dirname(target), {recursive: true});\n fs.writeFileSync(tmp, JSON.stringify(out, null, 2) + '\\n', 'utf8');\n fs.renameSync(tmp, target);\n return target;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/localize/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `local-packages.json` -- the record of which packages are currently localized.\n *\n * The filename and schema are deliberately the SAME as the ones `@semantu/cli`\n * already writes (schema version 1, keys are npm package names). A developer\n * with a half-localized tree must be able to switch tools without re-cloning,\n * and the consumer's `postinstall` must keep working across the switch.\n *\n * One relaxation since 0.1.0: `repo` is optional, because an adopted checkout\n * may have no remote. localize 0.1.0 skips such an entry as partial, with a\n * warning, and keeps the rest; other readers of this schema were not checked.\n *\n * Two properties are load-bearing:\n *\n * 1. **It is never repaired.** Unparseable JSON, an unknown `version` or a\n * `packages` that is not an object is a refusal (exit 3) with no write.\n * This file is the only record of what a developer intended; silently\n * resetting it is how a half-localized tree becomes invisible.\n * 2. **Writes are atomic** -- `<file>.tmp` then `rename` -- so a killed run\n * cannot leave a truncated file behind.\n *\n * A *partial entry* is different from a malformed file: it is skipped with a\n * warning and its siblings still process, because one bad entry must not cost\n * a developer the other nine.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {EXIT_BAD_FILE, LocalizeError} from './errors.js';\n\nexport const MANIFEST_FILENAME = 'local-packages.json';\n\n/** One recorded package: where its checkout is, and where it came from. */\nexport interface ManifestEntry {\n /** Absent for an adopted checkout with no remote. */\n repo?: string;\n /** The package directory, relative to the app root. */\n path: string;\n branch: string;\n /** The package's directory inside the clone, for a monorepo. */\n subdir?: string;\n /** The range the app declared when it was localized. */\n range?: string;\n /**\n * `false` when the package was localized or adopted with `--no-prune`: its\n * checkout's `node_modules` stay as npm installed them -- no prune after\n * `--relink` or `--reinstall`, and the run-time check (`--ensure`, before\n * `linked start` etc.) skips it. Absent means on; localizing or adopting it\n * again without `--no-prune` turns it back on. Optional, so schema version 1\n * readers that do not know it simply ignore it.\n */\n prune?: false;\n}\n\nexport interface Manifest {\n file: string;\n exists: boolean;\n version: number;\n dir: string;\n entries: Record<string, ManifestEntry>;\n malformed: {name: string; reason: string}[];\n}\n\n/** The only schema version this build understands. */\nexport const SCHEMA_VERSION = 1;\n\n/** Default checkout directory, relative to the consumer root. */\nexport const DEFAULT_DIR = 'packages-local';\n\nexport function manifestPath(appRoot: string): string {\n return path.join(appRoot, MANIFEST_FILENAME);\n}\n\n/**\n * Read and validate the manifest.\n *\n * A missing file is NOT an error: it is the CI case and the fresh-clone case,\n * and reads as an empty set. That is also why no `if (CI)` branch exists\n * anywhere in this package -- the file is gitignored, so CI is a natural no-op.\n *\n * @throws {LocalizeError} code 3. Nothing is written in any failure case.\n */\nexport function readManifest(\n appRoot: string,\n io: {warn: (message: string) => void} = {warn: console.warn},\n): Manifest {\n const file = manifestPath(appRoot);\n\n if (!fs.existsSync(file)) {\n return {\n file,\n exists: false,\n version: SCHEMA_VERSION,\n dir: DEFAULT_DIR,\n entries: {},\n malformed: [],\n };\n }\n\n const raw = fs.readFileSync(file, 'utf8');\n let parsed;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n throw new LocalizeError(\n `${file} is not valid JSON: ${e.message}\\n` +\n `Refusing to read or rewrite it -- it is the only record of what was localized. ` +\n `Fix it by hand, or delete it to start over.`,\n EXIT_BAD_FILE,\n );\n }\n\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new LocalizeError(\n `${file} does not contain a JSON object.\\n` +\n `Refusing to read or rewrite it. Expected {\"version\":${SCHEMA_VERSION},\"packages\":{…}}.`,\n EXIT_BAD_FILE,\n );\n }\n\n if (parsed.version !== SCHEMA_VERSION) {\n throw new LocalizeError(\n `${file} has schema version ${JSON.stringify(parsed.version)}; this version of localize understands ` +\n `only version ${SCHEMA_VERSION}.\\n` +\n `Refusing to read or rewrite it -- guessing at a schema it did not write is how intent ` +\n `gets lost. Upgrade localize, or delete the file and re-localize.`,\n EXIT_BAD_FILE,\n );\n }\n\n if (\n parsed.packages === null ||\n typeof parsed.packages !== 'object' ||\n Array.isArray(parsed.packages)\n ) {\n throw new LocalizeError(\n `${file} has a \"packages\" field that is not an object (found ` +\n `${Array.isArray(parsed.packages) ? 'an array' : typeof parsed.packages}).\\n` +\n `Refusing to read or rewrite it.`,\n EXIT_BAD_FILE,\n );\n }\n\n const dir =\n typeof parsed.dir === 'string' && parsed.dir.length > 0\n ? parsed.dir\n : DEFAULT_DIR;\n\n const entries: Record<string, ManifestEntry> = {};\n const malformed: Manifest['malformed'] = [];\n\n for (const [name, value] of Object.entries<any>(parsed.packages)) {\n const reason = validateEntry(value);\n if (reason) {\n malformed.push({name, reason});\n io.warn(\n `[localize] ${name}: malformed entry in ${MANIFEST_FILENAME} (${reason}) -- skipped. ` +\n `The other entries are unaffected. \\`linked localize ${name}\\` rewrites it.`,\n );\n continue;\n }\n entries[name] = {\n ...(typeof value.repo === 'string' && value.repo\n ? {repo: value.repo}\n : {}),\n path: value.path,\n branch: value.branch,\n ...(typeof value.subdir === 'string' ? {subdir: value.subdir} : {}),\n ...(typeof value.range === 'string' ? {range: value.range} : {}),\n ...(value.prune === false ? {prune: false as const} : {}),\n };\n }\n\n return {file, exists: true, version: SCHEMA_VERSION, dir, entries, malformed};\n}\n\n/**\n * @returns {string|null} a reason the entry is unusable, else null.\n *\n * `repo` is optional: an adopted checkout may have no remote at all -- a\n * package created locally that has not been pushed anywhere yet.\n */\nfunction validateEntry(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return 'not an object';\n const missing = ['path', 'branch'].filter(\n (k) => typeof value[k] !== 'string' || value[k].length === 0,\n );\n return missing.length ? `missing ${missing.join(', ')}` : null;\n}\n\n/**\n * Write the manifest atomically: a `.tmp` in the SAME directory, so `rename`\n * is atomic on one filesystem, then `rename` over the original.\n *\n * An empty `packages` object is written rather than the file being deleted, so\n * a non-default `dir` survives delocalizing the last entry.\n */\nexport function writeManifest(\n appRoot: string,\n data: {\n version?: number;\n dir?: string;\n packages?: Record<string, ManifestEntry>;\n },\n): string {\n const target = manifestPath(appRoot);\n const tmp = `${target}.tmp`;\n\n const out = {\n version: SCHEMA_VERSION,\n ...(data.dir && data.dir !== DEFAULT_DIR ? {dir: data.dir} : {}),\n packages: data.packages ?? {},\n };\n\n fs.mkdirSync(path.dirname(target), {recursive: true});\n fs.writeFileSync(tmp, JSON.stringify(out, null, 2) + '\\n', 'utf8');\n fs.renameSync(tmp, target);\n return target;\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which `linked` commands run the one-copy check (`checkOneCopy`, ensure.ts)
|
|
3
|
+
* first: the ones that run the app's code. Kept apart from `cli.ts`, which
|
|
4
|
+
* builds and parses the real program on import, so a test can install the
|
|
5
|
+
* hook on a program of its own and see exactly which commands trigger it.
|
|
6
|
+
*/
|
|
7
|
+
import type { Command } from 'commander';
|
|
8
|
+
/** `linked start`, `script`, `call` and `build-all`, and nothing else. */
|
|
9
|
+
export declare const ONE_COPY_COMMANDS: ReadonlySet<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Before one of `ONE_COPY_COMMANDS`, remove any localized checkout's own copy
|
|
12
|
+
* of what the app provides. Never runs npm, silent when there is nothing to
|
|
13
|
+
* remove, a no-op with no local-packages.json, and it never throws.
|
|
14
|
+
*/
|
|
15
|
+
export declare function installOneCopyHook(program: Command, check?: (appRoot: string) => unknown): void;
|
|
16
|
+
//# sourceMappingURL=one-copy-hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"one-copy-hook.d.ts","sourceRoot":"","sources":["../../../src/localize/one-copy-hook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAIvC,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAKhD,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,KAAK,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAsB,GACjD,IAAI,CAIN"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { checkOneCopy } from './ensure.js';
|
|
2
|
+
/** `linked start`, `script`, `call` and `build-all`, and nothing else. */
|
|
3
|
+
export const ONE_COPY_COMMANDS = new Set([
|
|
4
|
+
'start',
|
|
5
|
+
'script',
|
|
6
|
+
'call',
|
|
7
|
+
'build-all',
|
|
8
|
+
]);
|
|
9
|
+
/**
|
|
10
|
+
* Before one of `ONE_COPY_COMMANDS`, remove any localized checkout's own copy
|
|
11
|
+
* of what the app provides. Never runs npm, silent when there is nothing to
|
|
12
|
+
* remove, a no-op with no local-packages.json, and it never throws.
|
|
13
|
+
*/
|
|
14
|
+
export function installOneCopyHook(program, check = checkOneCopy) {
|
|
15
|
+
program.hook('preAction', (_program, actionCommand) => {
|
|
16
|
+
if (ONE_COPY_COMMANDS.has(actionCommand.name()))
|
|
17
|
+
check(process.cwd());
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=one-copy-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"one-copy-hook.js","sourceRoot":"","sources":["../../../src/localize/one-copy-hook.ts"],"names":[],"mappings":"AAQA,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAEzC,0EAA0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC;IAC5D,OAAO;IACP,QAAQ;IACR,MAAM;IACN,WAAW;CACZ,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAgB,EAChB,QAAsC,YAAY;IAElD,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE;QACpD,IAAI,iBAAiB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;YAAE,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Which `linked` commands run the one-copy check (`checkOneCopy`, ensure.ts)\n * first: the ones that run the app's code. Kept apart from `cli.ts`, which\n * builds and parses the real program on import, so a test can install the\n * hook on a program of its own and see exactly which commands trigger it.\n */\nimport type {Command} from 'commander';\n\nimport {checkOneCopy} from './ensure.js';\n\n/** `linked start`, `script`, `call` and `build-all`, and nothing else. */\nexport const ONE_COPY_COMMANDS: ReadonlySet<string> = new Set([\n 'start',\n 'script',\n 'call',\n 'build-all',\n]);\n\n/**\n * Before one of `ONE_COPY_COMMANDS`, remove any localized checkout's own copy\n * of what the app provides. Never runs npm, silent when there is nothing to\n * remove, a no-op with no local-packages.json, and it never throws.\n */\nexport function installOneCopyHook(\n program: Command,\n check: (appRoot: string) => unknown = checkOneCopy,\n): void {\n program.hook('preAction', (_program, actionCommand) => {\n if (ONE_COPY_COMMANDS.has(actionCommand.name())) check(process.cwd());\n });\n}\n"]}
|