@_linked/cli 1.41.1 → 1.42.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 +17 -0
- package/README.md +21 -54
- package/lib/esm/cli-methods.js +2 -2
- package/lib/esm/cli-methods.js.map +1 -1
- package/lib/esm/cli.js +13 -1
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/commands/localize.d.ts +6 -15
- package/lib/esm/commands/localize.d.ts.map +1 -1
- package/lib/esm/commands/localize.js +26 -35
- package/lib/esm/commands/localize.js.map +1 -1
- package/lib/esm/installed-packages.d.ts +12 -12
- package/lib/esm/installed-packages.d.ts.map +1 -1
- package/lib/esm/installed-packages.js +37 -27
- package/lib/esm/installed-packages.js.map +1 -1
- package/lib/esm/lifecycle.d.ts +4 -3
- package/lib/esm/lifecycle.d.ts.map +1 -1
- package/lib/esm/lifecycle.js +6 -14
- package/lib/esm/lifecycle.js.map +1 -1
- package/lib/esm/localize/adopt.d.ts +10 -0
- package/lib/esm/localize/adopt.d.ts.map +1 -0
- package/lib/esm/localize/adopt.js +76 -0
- package/lib/esm/localize/adopt.js.map +1 -0
- package/lib/esm/localize/delocalize.d.ts +6 -0
- package/lib/esm/localize/delocalize.d.ts.map +1 -0
- package/lib/esm/localize/delocalize.js +138 -0
- package/lib/esm/localize/delocalize.js.map +1 -0
- package/lib/esm/localize/ensure.d.ts +26 -0
- package/lib/esm/localize/ensure.d.ts.map +1 -0
- package/lib/esm/localize/ensure.js +152 -0
- package/lib/esm/localize/ensure.js.map +1 -0
- package/lib/esm/localize/errors.d.ts +23 -0
- package/lib/esm/localize/errors.d.ts.map +1 -0
- package/lib/esm/localize/errors.js +26 -0
- package/lib/esm/localize/errors.js.map +1 -0
- package/lib/esm/localize/fsops.d.ts +36 -0
- package/lib/esm/localize/fsops.d.ts.map +1 -0
- package/lib/esm/localize/fsops.js +155 -0
- package/lib/esm/localize/fsops.js.map +1 -0
- package/lib/esm/localize/index.d.ts +29 -0
- package/lib/esm/localize/index.d.ts.map +1 -0
- package/lib/esm/localize/index.js +22 -0
- package/lib/esm/localize/index.js.map +1 -0
- package/lib/esm/localize/list.d.ts +18 -0
- package/lib/esm/localize/list.d.ts.map +1 -0
- package/lib/esm/localize/list.js +174 -0
- package/lib/esm/localize/list.js.map +1 -0
- package/lib/esm/localize/localize.d.ts +84 -0
- package/lib/esm/localize/localize.d.ts.map +1 -0
- package/lib/esm/localize/localize.js +354 -0
- package/lib/esm/localize/localize.js.map +1 -0
- package/lib/esm/localize/manifest.d.ts +54 -0
- package/lib/esm/localize/manifest.d.ts.map +1 -0
- package/lib/esm/localize/manifest.js +133 -0
- package/lib/esm/localize/manifest.js.map +1 -0
- package/lib/esm/localize/provided.d.ts +28 -0
- package/lib/esm/localize/provided.d.ts.map +1 -0
- package/lib/esm/localize/provided.js +89 -0
- package/lib/esm/localize/provided.js.map +1 -0
- package/lib/esm/localize/prune.d.ts +58 -0
- package/lib/esm/localize/prune.d.ts.map +1 -0
- package/lib/esm/localize/prune.js +390 -0
- package/lib/esm/localize/prune.js.map +1 -0
- package/lib/esm/localize/relink.d.ts +11 -0
- package/lib/esm/localize/relink.d.ts.map +1 -0
- package/lib/esm/localize/relink.js +174 -0
- package/lib/esm/localize/relink.js.map +1 -0
- package/lib/esm/localize/resolve.d.ts +47 -0
- package/lib/esm/localize/resolve.d.ts.map +1 -0
- package/lib/esm/localize/resolve.js +153 -0
- package/lib/esm/localize/resolve.js.map +1 -0
- package/lib/esm/localize/run.d.ts +35 -0
- package/lib/esm/localize/run.d.ts.map +1 -0
- package/lib/esm/localize/run.js +30 -0
- package/lib/esm/localize/run.js.map +1 -0
- package/lib/esm/localized-dedupe.d.ts +6 -0
- package/lib/esm/localized-dedupe.d.ts.map +1 -1
- package/lib/esm/localized-dedupe.js +23 -66
- package/lib/esm/localized-dedupe.js.map +1 -1
- package/package.json +1 -2
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One copy, always: every package the app provides loads once, whichever tool
|
|
3
|
+
* runs the code -- Vite, `tsc`, plain Node, `tsx`, a test runner.
|
|
4
|
+
*
|
|
5
|
+
* Two halves:
|
|
6
|
+
*
|
|
7
|
+
* - **`ensure(entry)`** -- the ONLY way a checkout gets installed: `npm
|
|
8
|
+
* install` inside it, then prune it (prune.ts). localize's install step,
|
|
9
|
+
* `--relink`'s reinstall and `linked localize --reinstall <pkg>` all go
|
|
10
|
+
* through it, so the copies an install puts back exist only until it
|
|
11
|
+
* returns. Hand-running `npm install` in a checkout is what `--reinstall`
|
|
12
|
+
* replaces.
|
|
13
|
+
* - **`checkOneCopy(appRoot)`** -- the run-time check. Before `linked start`,
|
|
14
|
+
* `script`, `call` and `build-all` (a commander `preAction` in cli.ts), and
|
|
15
|
+
* as `linked localize --ensure` for an app's npm `pre*` scripts. Stat-only:
|
|
16
|
+
* for every recorded checkout and every name the app provides, does
|
|
17
|
+
* `<checkout>/node_modules/<name>` exist with a real path other than the
|
|
18
|
+
* app's copy? Only then does it prune -- through prune's guarded path, so a
|
|
19
|
+
* copy whose ranges the app does not satisfy stays -- and it says what it
|
|
20
|
+
* removed in one line. It never runs npm, prints nothing when there is
|
|
21
|
+
* nothing to do (or no manifest), and never throws: a run command must not
|
|
22
|
+
* fail over a developer's private checkout state.
|
|
23
|
+
*/
|
|
24
|
+
import fs from 'node:fs';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { EXIT_INSTALL_FAILED, EXIT_REFUSED, EXIT_WARNED, LocalizeError, } from './errors.js';
|
|
27
|
+
import { manifestPath, readManifest } from './manifest.js';
|
|
28
|
+
import { readJson } from './fsops.js';
|
|
29
|
+
import { nodeModulesRoots, pruneProvided, realOrSelf, shouldPrune, } from './prune.js';
|
|
30
|
+
import { providedPackages } from './provided.js';
|
|
31
|
+
import { defaultDeps } from './run.js';
|
|
32
|
+
import { reportError } from './localize.js';
|
|
33
|
+
/**
|
|
34
|
+
* `npm install` inside the checkout at `entry.path`, then prune it.
|
|
35
|
+
*
|
|
36
|
+
* The package's name is read from the checkout's own `package.json`; the
|
|
37
|
+
* other localized packages (siblings) from the manifest, so a checkout being
|
|
38
|
+
* localized right now prunes before the manifest records it.
|
|
39
|
+
*
|
|
40
|
+
* @returns 0, or `EXIT_WARNED` when the prune failed (the install stands).
|
|
41
|
+
* @throws {LocalizeError} `EXIT_INSTALL_FAILED` when `npm install` fails.
|
|
42
|
+
*/
|
|
43
|
+
export function ensure(entry, deps, opts = {}) {
|
|
44
|
+
var _a;
|
|
45
|
+
const pkgDir = path.join(deps.appRoot, entry.path);
|
|
46
|
+
deps.log(`[localize] npm install in ${entry.path}`);
|
|
47
|
+
const install = deps.run('npm', ['install', '--no-audit', '--no-fund'], {
|
|
48
|
+
cwd: pkgDir,
|
|
49
|
+
});
|
|
50
|
+
if (install.status !== 0) {
|
|
51
|
+
throw new LocalizeError(`npm install failed in ${entry.path}:\n${(install.stderr || install.stdout).trim()}`, EXIT_INSTALL_FAILED);
|
|
52
|
+
}
|
|
53
|
+
if (!shouldPrune(opts))
|
|
54
|
+
return 0;
|
|
55
|
+
const name = (_a = readJson(path.join(pkgDir, 'package.json'))) === null || _a === void 0 ? void 0 : _a.name;
|
|
56
|
+
if (typeof name !== 'string')
|
|
57
|
+
return 0;
|
|
58
|
+
try {
|
|
59
|
+
const entries = Object.assign(Object.assign({}, recordedEntries(deps)), { [name]: entry });
|
|
60
|
+
pruneProvided(entries, opts, deps, { owners: [name] });
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
deps.warn(`[localize] pruning ${entry.path} failed, its node_modules are as npm left them: ${e.message}`);
|
|
65
|
+
return EXIT_WARNED;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** `linked localize --reinstall <pkg>`: `ensure` for one recorded package. */
|
|
69
|
+
export function reinstall(name, opts, deps) {
|
|
70
|
+
try {
|
|
71
|
+
const entry = readManifest(deps.appRoot, deps).entries[name];
|
|
72
|
+
if (!entry) {
|
|
73
|
+
throw new LocalizeError(`${name} is not localized here, so there is no checkout to reinstall. ` +
|
|
74
|
+
'`linked localize --list` shows what is.', EXIT_REFUSED);
|
|
75
|
+
}
|
|
76
|
+
if (!fs.existsSync(path.join(deps.appRoot, entry.path, 'package.json'))) {
|
|
77
|
+
throw new LocalizeError(`${name} is recorded at ${entry.path}, which has no package.json.`, EXIT_REFUSED);
|
|
78
|
+
}
|
|
79
|
+
return ensure(entry, deps, opts);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
return reportError(e, deps);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The run-time check: remove every recorded checkout's own copy of what the
|
|
87
|
+
* app provides. Stat-only until there is something to remove.
|
|
88
|
+
*
|
|
89
|
+
* @returns what was removed, as `<checkout>/node_modules/<name>@<version>`.
|
|
90
|
+
*/
|
|
91
|
+
export function checkOneCopy(appRoot = process.cwd(), deps = defaultDeps(appRoot)) {
|
|
92
|
+
var _a;
|
|
93
|
+
try {
|
|
94
|
+
if (!fs.existsSync(manifestPath(appRoot)))
|
|
95
|
+
return { pruned: [] };
|
|
96
|
+
const entries = readManifest(appRoot, { warn: () => { } }).entries;
|
|
97
|
+
const owners = Object.keys(entries);
|
|
98
|
+
if (!owners.length)
|
|
99
|
+
return { pruned: [] };
|
|
100
|
+
// The app's copy of each provided name, by real path.
|
|
101
|
+
const appReal = new Map();
|
|
102
|
+
for (const name of providedPackages(appRoot, owners).names) {
|
|
103
|
+
const dir = path.join(appRoot, 'node_modules', name);
|
|
104
|
+
if (fs.existsSync(dir))
|
|
105
|
+
appReal.set(name, realOrSelf(dir));
|
|
106
|
+
}
|
|
107
|
+
const hitOwners = new Set();
|
|
108
|
+
const hitNames = new Set();
|
|
109
|
+
for (const [owner, entry] of Object.entries(entries)) {
|
|
110
|
+
const pkgDir = path.join(appRoot, entry.path);
|
|
111
|
+
for (const nm of nodeModulesRoots(pkgDir, entry)) {
|
|
112
|
+
for (const [name, real] of appReal) {
|
|
113
|
+
if (name === owner)
|
|
114
|
+
continue;
|
|
115
|
+
const copy = path.join(nm, name);
|
|
116
|
+
if (fs.existsSync(copy) && realOrSelf(copy) !== real) {
|
|
117
|
+
hitOwners.add(owner);
|
|
118
|
+
hitNames.add(name);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!hitOwners.size)
|
|
124
|
+
return { pruned: [] };
|
|
125
|
+
// Prune's own report is per checkout and also speaks of what it keeps;
|
|
126
|
+
// here only what went is worth a line, on every run command.
|
|
127
|
+
const quiet = { appRoot, log: () => { }, warn: () => { } };
|
|
128
|
+
const { removed } = pruneProvided(entries, {}, quiet, {
|
|
129
|
+
owners: [...hitOwners],
|
|
130
|
+
deps: [...hitNames],
|
|
131
|
+
});
|
|
132
|
+
const pruned = removed.map((r) => `${r.owner}/node_modules/${r.dep}@${r.version}`);
|
|
133
|
+
if (pruned.length) {
|
|
134
|
+
deps.log(`[localize] one copy: removed ${pruned.join(', ')} — the app provides ` +
|
|
135
|
+
`${pruned.length === 1 ? 'it' : 'them'}.`);
|
|
136
|
+
}
|
|
137
|
+
return { pruned };
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
deps.warn(`[localize] one-copy check failed, nothing more was removed: ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e}`);
|
|
141
|
+
return { pruned: [] };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function recordedEntries(deps) {
|
|
145
|
+
try {
|
|
146
|
+
return readManifest(deps.appRoot, { warn: () => { } }).entries;
|
|
147
|
+
}
|
|
148
|
+
catch (_a) {
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=ensure.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every refusal in localize throws a LocalizeError carrying an exit code, so
|
|
3
|
+
* callers can branch on `.code` rather than matching on a message.
|
|
4
|
+
*
|
|
5
|
+
* The codes are a public contract: scripts depend on them.
|
|
6
|
+
*/
|
|
7
|
+
/** The manifest file is unusable and localize refuses to touch it. */
|
|
8
|
+
export declare const EXIT_BAD_FILE = 3;
|
|
9
|
+
/** No git repository could be resolved for the package name. */
|
|
10
|
+
export declare const EXIT_NOT_FOUND = 4;
|
|
11
|
+
/** Something was warned about and skipped; the command otherwise worked. */
|
|
12
|
+
export declare const EXIT_WARNED = 5;
|
|
13
|
+
/** A guard refused to act. `--force` overrides. */
|
|
14
|
+
export declare const EXIT_REFUSED = 6;
|
|
15
|
+
/** The install inside the checkout failed: nothing linked, nothing recorded. */
|
|
16
|
+
export declare const EXIT_INSTALL_FAILED = 7;
|
|
17
|
+
/** package.json / package-lock.json changed -- the failure this tool exists to prevent. */
|
|
18
|
+
export declare const EXIT_MANIFEST_DIRTY = 8;
|
|
19
|
+
export declare class LocalizeError extends Error {
|
|
20
|
+
code: number;
|
|
21
|
+
constructor(message: string, code: number);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/localize/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sEAAsE;AACtE,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,gEAAgE;AAChE,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,4EAA4E;AAC5E,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,mDAAmD;AACnD,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,2FAA2F;AAC3F,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,qBAAa,aAAc,SAAQ,KAAK;IACtC,IAAI,EAAE,MAAM,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAK1C"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every refusal in localize throws a LocalizeError carrying an exit code, so
|
|
3
|
+
* callers can branch on `.code` rather than matching on a message.
|
|
4
|
+
*
|
|
5
|
+
* The codes are a public contract: scripts depend on them.
|
|
6
|
+
*/
|
|
7
|
+
/** The manifest file is unusable and localize refuses to touch it. */
|
|
8
|
+
export const EXIT_BAD_FILE = 3;
|
|
9
|
+
/** No git repository could be resolved for the package name. */
|
|
10
|
+
export const EXIT_NOT_FOUND = 4;
|
|
11
|
+
/** Something was warned about and skipped; the command otherwise worked. */
|
|
12
|
+
export const EXIT_WARNED = 5;
|
|
13
|
+
/** A guard refused to act. `--force` overrides. */
|
|
14
|
+
export const EXIT_REFUSED = 6;
|
|
15
|
+
/** The install inside the checkout failed: nothing linked, nothing recorded. */
|
|
16
|
+
export const EXIT_INSTALL_FAILED = 7;
|
|
17
|
+
/** package.json / package-lock.json changed -- the failure this tool exists to prevent. */
|
|
18
|
+
export const EXIT_MANIFEST_DIRTY = 8;
|
|
19
|
+
export class LocalizeError extends Error {
|
|
20
|
+
constructor(message, code) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'LocalizeError';
|
|
23
|
+
this.code = code;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/localize/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sEAAsE;AACtE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B,gEAAgE;AAChE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAChC,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,mDAAmD;AACnD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAC9B,gFAAgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,2FAA2F;AAC3F,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEtC,YAAY,OAAe,EAAE,IAAY;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF","sourcesContent":["/**\n * Every refusal in localize throws a LocalizeError carrying an exit code, so\n * callers can branch on `.code` rather than matching on a message.\n *\n * The codes are a public contract: scripts depend on them.\n */\n\n/** The manifest file is unusable and localize refuses to touch it. */\nexport const EXIT_BAD_FILE = 3;\n/** No git repository could be resolved for the package name. */\nexport const EXIT_NOT_FOUND = 4;\n/** Something was warned about and skipped; the command otherwise worked. */\nexport const EXIT_WARNED = 5;\n/** A guard refused to act. `--force` overrides. */\nexport const EXIT_REFUSED = 6;\n/** The install inside the checkout failed: nothing linked, nothing recorded. */\nexport const EXIT_INSTALL_FAILED = 7;\n/** package.json / package-lock.json changed -- the failure this tool exists to prevent. */\nexport const EXIT_MANIFEST_DIRTY = 8;\n\nexport class LocalizeError extends Error {\n code: number;\n constructor(message: string, code: number) {\n super(message);\n this.name = 'LocalizeError';\n this.code = code;\n }\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare function isSymlink(p: string): boolean;
|
|
2
|
+
export declare function isGitCheckout(p: string): boolean;
|
|
3
|
+
/** Is `child` at or below `parent`? Both must be absolute, real paths. */
|
|
4
|
+
export declare function isInside(child: string, parent: string): boolean;
|
|
5
|
+
export declare function readJson(file: string): any;
|
|
6
|
+
/** Where `node_modules/<name>` points, resolved, or null when it is not a link. */
|
|
7
|
+
export declare function linkTarget(appRoot: string, name: string): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Write `node_modules/<name> -> <checkout>` and nothing else.
|
|
10
|
+
*
|
|
11
|
+
* The target is stored RELATIVE so the tree survives being moved or bind-mounted
|
|
12
|
+
* into a container at a different path.
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeLink(appRoot: string, name: string, checkout: string): string;
|
|
15
|
+
/** Every symlink directly under node_modules whose target leaves node_modules. */
|
|
16
|
+
export declare function scanLinks(appRoot: string): {
|
|
17
|
+
name: string;
|
|
18
|
+
target: string;
|
|
19
|
+
}[];
|
|
20
|
+
/** The files no localize command may ever touch. */
|
|
21
|
+
export declare const MANIFEST_FILES: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Hash the consumer's manifests.
|
|
24
|
+
*
|
|
25
|
+
* Content hashes, NOT `git status`. `git status` compares against HEAD, so in
|
|
26
|
+
* any tree with an uncommitted `package.json` it reports a modification the
|
|
27
|
+
* command did not make -- an earlier version of this tool shipped that bug and
|
|
28
|
+
* reported correct runs as failures. Hashes also work in a tree with no git,
|
|
29
|
+
* and catch an edit that HEAD happens to agree with.
|
|
30
|
+
*
|
|
31
|
+
* `latin1` is a byte-exact round-trip for arbitrary bytes; `utf8` is not.
|
|
32
|
+
*/
|
|
33
|
+
export declare function snapshotManifests(appRoot: string): Record<string, string | null>;
|
|
34
|
+
/** @returns {string[]} a human description of each manifest that changed. */
|
|
35
|
+
export declare function diffManifests(before: Record<string, string | null>, after: Record<string, string | null>): string[];
|
|
36
|
+
//# sourceMappingURL=fsops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsops.d.ts","sourceRoot":"","sources":["../../../src/localize/fsops.ts"],"names":[],"mappings":"AAiBA,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAM5C;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,0EAA0E;AAC1E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAG/D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAM1C;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASvE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,MAAM,CAOR;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,EAAE,CAqC3E;AAMD,oDAAoD;AACpD,eAAO,MAAM,cAAc,UAAwC,CAAC;AAEpE;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAW/B;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GACnC,MAAM,EAAE,CAMV"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The filesystem primitives, and the guard that proves localize kept its
|
|
3
|
+
* promise.
|
|
4
|
+
*
|
|
5
|
+
* The link is written with `fs.symlink` and never by invoking npm. Two
|
|
6
|
+
* separate reasons, both measured rather than assumed:
|
|
7
|
+
*
|
|
8
|
+
* - `npm install <path> --no-save` brings npm's peer resolution along, which
|
|
9
|
+
* hard-failed an app's boot on a missing peer dependency. Module resolution
|
|
10
|
+
* happens from the symlink's REAL path, whose ancestors have no
|
|
11
|
+
* `node_modules`, so the checkout needs its own installed tree.
|
|
12
|
+
* - a `postinstall` hook that invokes an install at the consumer root recurses.
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
export function isSymlink(p) {
|
|
18
|
+
try {
|
|
19
|
+
return fs.lstatSync(p).isSymbolicLink();
|
|
20
|
+
}
|
|
21
|
+
catch (_a) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function isGitCheckout(p) {
|
|
26
|
+
return fs.existsSync(path.join(p, '.git'));
|
|
27
|
+
}
|
|
28
|
+
/** Is `child` at or below `parent`? Both must be absolute, real paths. */
|
|
29
|
+
export function isInside(child, parent) {
|
|
30
|
+
const rel = path.relative(parent, child);
|
|
31
|
+
return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
|
|
32
|
+
}
|
|
33
|
+
export function readJson(file) {
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
36
|
+
}
|
|
37
|
+
catch (_a) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Where `node_modules/<name>` points, resolved, or null when it is not a link. */
|
|
42
|
+
export function linkTarget(appRoot, name) {
|
|
43
|
+
const link = path.join(appRoot, 'node_modules', name);
|
|
44
|
+
if (!isSymlink(link))
|
|
45
|
+
return null;
|
|
46
|
+
try {
|
|
47
|
+
return fs.realpathSync(link);
|
|
48
|
+
}
|
|
49
|
+
catch (_a) {
|
|
50
|
+
// A dangling link is still linked intent; its target is simply gone.
|
|
51
|
+
return path.resolve(path.dirname(link), fs.readlinkSync(link));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write `node_modules/<name> -> <checkout>` and nothing else.
|
|
56
|
+
*
|
|
57
|
+
* The target is stored RELATIVE so the tree survives being moved or bind-mounted
|
|
58
|
+
* into a container at a different path.
|
|
59
|
+
*/
|
|
60
|
+
export function writeLink(appRoot, name, checkout) {
|
|
61
|
+
const link = path.join(appRoot, 'node_modules', name);
|
|
62
|
+
fs.mkdirSync(path.dirname(link), { recursive: true });
|
|
63
|
+
if (isSymlink(link))
|
|
64
|
+
fs.unlinkSync(link);
|
|
65
|
+
else if (fs.existsSync(link))
|
|
66
|
+
fs.rmSync(link, { recursive: true, force: true });
|
|
67
|
+
fs.symlinkSync(path.relative(path.dirname(link), checkout), link, 'dir');
|
|
68
|
+
return link;
|
|
69
|
+
}
|
|
70
|
+
/** Every symlink directly under node_modules whose target leaves node_modules. */
|
|
71
|
+
export function scanLinks(appRoot) {
|
|
72
|
+
const root = path.join(appRoot, 'node_modules');
|
|
73
|
+
const out = [];
|
|
74
|
+
let top;
|
|
75
|
+
try {
|
|
76
|
+
top = fs.readdirSync(root, { withFileTypes: true });
|
|
77
|
+
}
|
|
78
|
+
catch (_a) {
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
const collect = (name, full) => {
|
|
82
|
+
if (!isSymlink(full))
|
|
83
|
+
return;
|
|
84
|
+
let target;
|
|
85
|
+
try {
|
|
86
|
+
target = fs.realpathSync(full);
|
|
87
|
+
}
|
|
88
|
+
catch (_a) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (isInside(target, root))
|
|
92
|
+
return; // an ordinary hoisting link, not a checkout
|
|
93
|
+
out.push({ name, target });
|
|
94
|
+
};
|
|
95
|
+
for (const item of top) {
|
|
96
|
+
if (item.name === '.bin' || item.name.startsWith('.'))
|
|
97
|
+
continue;
|
|
98
|
+
const full = path.join(root, item.name);
|
|
99
|
+
if (item.name.startsWith('@')) {
|
|
100
|
+
let inner;
|
|
101
|
+
try {
|
|
102
|
+
inner = fs.readdirSync(full, { withFileTypes: true });
|
|
103
|
+
}
|
|
104
|
+
catch (_b) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
for (const sub of inner)
|
|
108
|
+
collect(`${item.name}/${sub.name}`, path.join(full, sub.name));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
collect(item.name, full);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// the post-condition
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
/** The files no localize command may ever touch. */
|
|
120
|
+
export const MANIFEST_FILES = ['package.json', 'package-lock.json'];
|
|
121
|
+
/**
|
|
122
|
+
* Hash the consumer's manifests.
|
|
123
|
+
*
|
|
124
|
+
* Content hashes, NOT `git status`. `git status` compares against HEAD, so in
|
|
125
|
+
* any tree with an uncommitted `package.json` it reports a modification the
|
|
126
|
+
* command did not make -- an earlier version of this tool shipped that bug and
|
|
127
|
+
* reported correct runs as failures. Hashes also work in a tree with no git,
|
|
128
|
+
* and catch an edit that HEAD happens to agree with.
|
|
129
|
+
*
|
|
130
|
+
* `latin1` is a byte-exact round-trip for arbitrary bytes; `utf8` is not.
|
|
131
|
+
*/
|
|
132
|
+
export function snapshotManifests(appRoot) {
|
|
133
|
+
const snap = {};
|
|
134
|
+
for (const file of MANIFEST_FILES) {
|
|
135
|
+
try {
|
|
136
|
+
const bytes = fs.readFileSync(path.join(appRoot, file), 'latin1');
|
|
137
|
+
snap[file] = createHash('sha256').update(bytes, 'latin1').digest('hex');
|
|
138
|
+
}
|
|
139
|
+
catch (_a) {
|
|
140
|
+
snap[file] = null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return snap;
|
|
144
|
+
}
|
|
145
|
+
/** @returns {string[]} a human description of each manifest that changed. */
|
|
146
|
+
export function diffManifests(before, after) {
|
|
147
|
+
return MANIFEST_FILES.filter((f) => before[f] !== after[f]).map((f) => {
|
|
148
|
+
if (before[f] === null)
|
|
149
|
+
return `${f} (created)`;
|
|
150
|
+
if (after[f] === null)
|
|
151
|
+
return `${f} (deleted)`;
|
|
152
|
+
return `${f} (modified)`;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=fsops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsops.js","sourceRoot":"","sources":["../../../src/localize/fsops.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The filesystem primitives, and the guard that proves localize kept its\n * promise.\n *\n * The link is written with `fs.symlink` and never by invoking npm. Two\n * separate reasons, both measured rather than assumed:\n *\n * - `npm install <path> --no-save` brings npm's peer resolution along, which\n * hard-failed an app's boot on a missing peer dependency. Module resolution\n * happens from the symlink's REAL path, whose ancestors have no\n * `node_modules`, so the checkout needs its own installed tree.\n * - a `postinstall` hook that invokes an install at the consumer root recurses.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {createHash} from 'node:crypto';\n\nexport function isSymlink(p: string): boolean {\n try {\n return fs.lstatSync(p).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nexport function isGitCheckout(p: string): boolean {\n return fs.existsSync(path.join(p, '.git'));\n}\n\n/** Is `child` at or below `parent`? Both must be absolute, real paths. */\nexport function isInside(child: string, parent: string): boolean {\n const rel = path.relative(parent, child);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n}\n\nexport function readJson(file: string): any {\n try {\n return JSON.parse(fs.readFileSync(file, 'utf8'));\n } catch {\n return null;\n }\n}\n\n/** Where `node_modules/<name>` points, resolved, or null when it is not a link. */\nexport function linkTarget(appRoot: string, name: string): string | null {\n const link = path.join(appRoot, 'node_modules', name);\n if (!isSymlink(link)) return null;\n try {\n return fs.realpathSync(link);\n } catch {\n // A dangling link is still linked intent; its target is simply gone.\n return path.resolve(path.dirname(link), fs.readlinkSync(link));\n }\n}\n\n/**\n * Write `node_modules/<name> -> <checkout>` and nothing else.\n *\n * The target is stored RELATIVE so the tree survives being moved or bind-mounted\n * into a container at a different path.\n */\nexport function writeLink(\n appRoot: string,\n name: string,\n checkout: string,\n): string {\n const link = path.join(appRoot, 'node_modules', name);\n fs.mkdirSync(path.dirname(link), {recursive: true});\n if (isSymlink(link)) fs.unlinkSync(link);\n else if (fs.existsSync(link)) fs.rmSync(link, {recursive: true, force: true});\n fs.symlinkSync(path.relative(path.dirname(link), checkout), link, 'dir');\n return link;\n}\n\n/** Every symlink directly under node_modules whose target leaves node_modules. */\nexport function scanLinks(appRoot: string): {name: string; target: string}[] {\n const root = path.join(appRoot, 'node_modules');\n const out: {name: string; target: string}[] = [];\n let top;\n try {\n top = fs.readdirSync(root, {withFileTypes: true});\n } catch {\n return out;\n }\n const collect = (name, full) => {\n if (!isSymlink(full)) return;\n let target;\n try {\n target = fs.realpathSync(full);\n } catch {\n return;\n }\n if (isInside(target, root)) return; // an ordinary hoisting link, not a checkout\n out.push({name, target});\n };\n for (const item of top) {\n if (item.name === '.bin' || item.name.startsWith('.')) continue;\n const full = path.join(root, item.name);\n if (item.name.startsWith('@')) {\n let inner;\n try {\n inner = fs.readdirSync(full, {withFileTypes: true});\n } catch {\n continue;\n }\n for (const sub of inner)\n collect(`${item.name}/${sub.name}`, path.join(full, sub.name));\n } else {\n collect(item.name, full);\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// the post-condition\n// ---------------------------------------------------------------------------\n\n/** The files no localize command may ever touch. */\nexport const MANIFEST_FILES = ['package.json', 'package-lock.json'];\n\n/**\n * Hash the consumer's manifests.\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 version of this tool shipped that bug and\n * reported correct runs as failures. Hashes also work in a tree with no git,\n * and catch an edit that HEAD happens to agree with.\n *\n * `latin1` is a byte-exact round-trip for arbitrary bytes; `utf8` is not.\n */\nexport function snapshotManifests(\n appRoot: string,\n): Record<string, string | null> {\n const snap: Record<string, string | null> = {};\n for (const file of MANIFEST_FILES) {\n try {\n const bytes = fs.readFileSync(path.join(appRoot, file), 'latin1');\n snap[file] = createHash('sha256').update(bytes, 'latin1').digest('hex');\n } catch {\n snap[file] = null;\n }\n }\n return snap;\n}\n\n/** @returns {string[]} a human description of each manifest that changed. */\nexport function diffManifests(\n before: Record<string, string | null>,\n after: Record<string, string | null>,\n): string[] {\n return MANIFEST_FILES.filter((f) => before[f] !== after[f]).map((f) => {\n if (before[f] === null) return `${f} (created)`;\n if (after[f] === null) return `${f} (deleted)`;\n return `${f} (modified)`;\n });\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* localize's programmatic API: `linked localize` / `linked delocalize` (see
|
|
3
|
+
* `commands/localize.ts`, the commander adapter) and `create-package`'s adopt
|
|
4
|
+
* reach it through here.
|
|
5
|
+
*
|
|
6
|
+
* Every function takes `deps` -- `{appRoot, run, log, warn, error}` -- so a
|
|
7
|
+
* caller can point it at another root or capture its output. `defaultDeps()`
|
|
8
|
+
* builds the normal one.
|
|
9
|
+
*/
|
|
10
|
+
export { localize } from './localize.js';
|
|
11
|
+
export { adopt } from './adopt.js';
|
|
12
|
+
export { delocalize } from './delocalize.js';
|
|
13
|
+
export { list, collect } from './list.js';
|
|
14
|
+
export { relink } from './relink.js';
|
|
15
|
+
export { pruneProvided, satisfies, shouldPrune } from './prune.js';
|
|
16
|
+
export type { PruneOptions, PruneScope } from './prune.js';
|
|
17
|
+
export { providedPackages } from './provided.js';
|
|
18
|
+
export type { Provided, ProvidedSkip } from './provided.js';
|
|
19
|
+
export { ensure, reinstall, checkOneCopy } from './ensure.js';
|
|
20
|
+
export type { LocalizeOptions } from './localize.js';
|
|
21
|
+
export type { ListRow } from './list.js';
|
|
22
|
+
export type { Resolved } from './resolve.js';
|
|
23
|
+
export type { Manifest, ManifestEntry } from './manifest.js';
|
|
24
|
+
export type { Deps, Run, RunOptions, RunResult } from './run.js';
|
|
25
|
+
export { resolvePackage, normalizeGitUrl, checkoutNameFor } from './resolve.js';
|
|
26
|
+
export { readManifest, writeManifest, manifestPath, MANIFEST_FILENAME, SCHEMA_VERSION, DEFAULT_DIR, } from './manifest.js';
|
|
27
|
+
export { defaultDeps, makeRun } from './run.js';
|
|
28
|
+
export { LocalizeError, EXIT_BAD_FILE, EXIT_NOT_FOUND, EXIT_WARNED, EXIT_REFUSED, EXIT_INSTALL_FAILED, EXIT_MANIFEST_DIRTY, } from './errors.js';
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/localize/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AACvC,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAC;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAC,IAAI,EAAE,OAAO,EAAC,MAAM,WAAW,CAAC;AACxC,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACnC,OAAO,EAAC,aAAa,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,YAAY,CAAC;AACjE,YAAY,EAAC,YAAY,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AACzD,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAC,QAAQ,EAAE,YAAY,EAAC,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAC,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AACnD,YAAY,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,YAAY,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAC;AAC3C,YAAY,EAAC,QAAQ,EAAE,aAAa,EAAC,MAAM,eAAe,CAAC;AAC3D,YAAY,EAAC,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAC,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,cAAc,CAAC;AAC9E,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,WAAW,EAAE,OAAO,EAAC,MAAM,UAAU,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* localize's programmatic API: `linked localize` / `linked delocalize` (see
|
|
3
|
+
* `commands/localize.ts`, the commander adapter) and `create-package`'s adopt
|
|
4
|
+
* reach it through here.
|
|
5
|
+
*
|
|
6
|
+
* Every function takes `deps` -- `{appRoot, run, log, warn, error}` -- so a
|
|
7
|
+
* caller can point it at another root or capture its output. `defaultDeps()`
|
|
8
|
+
* builds the normal one.
|
|
9
|
+
*/
|
|
10
|
+
export { localize } from './localize.js';
|
|
11
|
+
export { adopt } from './adopt.js';
|
|
12
|
+
export { delocalize } from './delocalize.js';
|
|
13
|
+
export { list, collect } from './list.js';
|
|
14
|
+
export { relink } from './relink.js';
|
|
15
|
+
export { pruneProvided, satisfies, shouldPrune } from './prune.js';
|
|
16
|
+
export { providedPackages } from './provided.js';
|
|
17
|
+
export { ensure, reinstall, checkOneCopy } from './ensure.js';
|
|
18
|
+
export { resolvePackage, normalizeGitUrl, checkoutNameFor } from './resolve.js';
|
|
19
|
+
export { readManifest, writeManifest, manifestPath, MANIFEST_FILENAME, SCHEMA_VERSION, DEFAULT_DIR, } from './manifest.js';
|
|
20
|
+
export { defaultDeps, makeRun } from './run.js';
|
|
21
|
+
export { LocalizeError, EXIT_BAD_FILE, EXIT_NOT_FOUND, EXIT_WARNED, EXIT_REFUSED, EXIT_INSTALL_FAILED, EXIT_MANIFEST_DIRTY, } from './errors.js';
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/localize/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AACvC,OAAO,EAAC,KAAK,EAAC,MAAM,YAAY,CAAC;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAC,IAAI,EAAE,OAAO,EAAC,MAAM,WAAW,CAAC;AACxC,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AACnC,OAAO,EAAC,aAAa,EAAE,SAAS,EAAE,WAAW,EAAC,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAC,MAAM,EAAE,SAAS,EAAE,YAAY,EAAC,MAAM,aAAa,CAAC;AAM5D,OAAO,EAAC,cAAc,EAAE,eAAe,EAAE,eAAe,EAAC,MAAM,cAAc,CAAC;AAC9E,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,WAAW,EAAE,OAAO,EAAC,MAAM,UAAU,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,aAAa,CAAC","sourcesContent":["/**\n * localize's programmatic API: `linked localize` / `linked delocalize` (see\n * `commands/localize.ts`, the commander adapter) and `create-package`'s adopt\n * reach it through here.\n *\n * Every function takes `deps` -- `{appRoot, run, log, warn, error}` -- so a\n * caller can point it at another root or capture its output. `defaultDeps()`\n * builds the normal one.\n */\nexport {localize} from './localize.js';\nexport {adopt} from './adopt.js';\nexport {delocalize} from './delocalize.js';\nexport {list, collect} from './list.js';\nexport {relink} from './relink.js';\nexport {pruneProvided, satisfies, shouldPrune} from './prune.js';\nexport type {PruneOptions, PruneScope} from './prune.js';\nexport {providedPackages} from './provided.js';\nexport type {Provided, ProvidedSkip} from './provided.js';\nexport {ensure, reinstall, checkOneCopy} from './ensure.js';\nexport type {LocalizeOptions} from './localize.js';\nexport type {ListRow} from './list.js';\nexport type {Resolved} from './resolve.js';\nexport type {Manifest, ManifestEntry} from './manifest.js';\nexport type {Deps, Run, RunOptions, RunResult} from './run.js';\nexport {resolvePackage, normalizeGitUrl, checkoutNameFor} from './resolve.js';\nexport {\n readManifest,\n writeManifest,\n manifestPath,\n MANIFEST_FILENAME,\n SCHEMA_VERSION,\n DEFAULT_DIR,\n} from './manifest.js';\nexport {defaultDeps, makeRun} from './run.js';\nexport {\n LocalizeError,\n EXIT_BAD_FILE,\n EXIT_NOT_FOUND,\n EXIT_WARNED,\n EXIT_REFUSED,\n EXIT_INSTALL_FAILED,\n EXIT_MANIFEST_DIRTY,\n} from './errors.js';\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Deps } from './run.js';
|
|
2
|
+
/** One row of `--list`: a recorded package, or a link the manifest does not know. */
|
|
3
|
+
export interface ListRow {
|
|
4
|
+
name: string;
|
|
5
|
+
state: 'linked' | 'checkout-missing' | 'not-linked' | 'malformed' | 'untracked' | 'unrecorded';
|
|
6
|
+
path: string;
|
|
7
|
+
branch: string;
|
|
8
|
+
note: string;
|
|
9
|
+
}
|
|
10
|
+
/** @returns {{rows: object[], notLinked: number}} */
|
|
11
|
+
export declare function collect(deps: Deps): {
|
|
12
|
+
rows: ListRow[];
|
|
13
|
+
notLinked: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function list(opts: {
|
|
16
|
+
check?: boolean;
|
|
17
|
+
}, deps: Deps): number;
|
|
18
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/localize/list.ts"],"names":[],"mappings":"AAuBA,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;CACd;AAED,qDAAqD;AACrD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG;IAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAwFxE;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CA0ChE"}
|