@_linked/cli 1.41.1 → 1.43.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 +29 -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/commands/setup-publish.d.ts +26 -1
- package/lib/esm/commands/setup-publish.d.ts.map +1 -1
- package/lib/esm/commands/setup-publish.js +107 -9
- package/lib/esm/commands/setup-publish.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 @@
|
|
|
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"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export declare const MANIFEST_FILENAME = "local-packages.json";
|
|
2
|
+
/** One recorded package: where its checkout is, and where it came from. */
|
|
3
|
+
export interface ManifestEntry {
|
|
4
|
+
/** Absent for an adopted checkout with no remote. */
|
|
5
|
+
repo?: string;
|
|
6
|
+
/** The package directory, relative to the app root. */
|
|
7
|
+
path: string;
|
|
8
|
+
branch: string;
|
|
9
|
+
/** The package's directory inside the clone, for a monorepo. */
|
|
10
|
+
subdir?: string;
|
|
11
|
+
/** The range the app declared when it was localized. */
|
|
12
|
+
range?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Manifest {
|
|
15
|
+
file: string;
|
|
16
|
+
exists: boolean;
|
|
17
|
+
version: number;
|
|
18
|
+
dir: string;
|
|
19
|
+
entries: Record<string, ManifestEntry>;
|
|
20
|
+
malformed: {
|
|
21
|
+
name: string;
|
|
22
|
+
reason: string;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
/** The only schema version this build understands. */
|
|
26
|
+
export declare const SCHEMA_VERSION = 1;
|
|
27
|
+
/** Default checkout directory, relative to the consumer root. */
|
|
28
|
+
export declare const DEFAULT_DIR = "packages-local";
|
|
29
|
+
export declare function manifestPath(appRoot: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Read and validate the manifest.
|
|
32
|
+
*
|
|
33
|
+
* A missing file is NOT an error: it is the CI case and the fresh-clone case,
|
|
34
|
+
* and reads as an empty set. That is also why no `if (CI)` branch exists
|
|
35
|
+
* anywhere in this package -- the file is gitignored, so CI is a natural no-op.
|
|
36
|
+
*
|
|
37
|
+
* @throws {LocalizeError} code 3. Nothing is written in any failure case.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readManifest(appRoot: string, io?: {
|
|
40
|
+
warn: (message: string) => void;
|
|
41
|
+
}): Manifest;
|
|
42
|
+
/**
|
|
43
|
+
* Write the manifest atomically: a `.tmp` in the SAME directory, so `rename`
|
|
44
|
+
* is atomic on one filesystem, then `rename` over the original.
|
|
45
|
+
*
|
|
46
|
+
* An empty `packages` object is written rather than the file being deleted, so
|
|
47
|
+
* a non-default `dir` survives delocalizing the last entry.
|
|
48
|
+
*/
|
|
49
|
+
export declare function writeManifest(appRoot: string, data: {
|
|
50
|
+
version?: number;
|
|
51
|
+
dir?: string;
|
|
52
|
+
packages?: Record<string, ManifestEntry>;
|
|
53
|
+
}): string;
|
|
54
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +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;CAChB;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,CAwFV;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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `local-packages.json` -- the record of which packages are currently localized.
|
|
3
|
+
*
|
|
4
|
+
* The filename and schema are deliberately the SAME as the ones `@semantu/cli`
|
|
5
|
+
* already writes (schema version 1, keys are npm package names). A developer
|
|
6
|
+
* with a half-localized tree must be able to switch tools without re-cloning,
|
|
7
|
+
* and the consumer's `postinstall` must keep working across the switch.
|
|
8
|
+
*
|
|
9
|
+
* One relaxation since 0.1.0: `repo` is optional, because an adopted checkout
|
|
10
|
+
* may have no remote. localize 0.1.0 skips such an entry as partial, with a
|
|
11
|
+
* warning, and keeps the rest; other readers of this schema were not checked.
|
|
12
|
+
*
|
|
13
|
+
* Two properties are load-bearing:
|
|
14
|
+
*
|
|
15
|
+
* 1. **It is never repaired.** Unparseable JSON, an unknown `version` or a
|
|
16
|
+
* `packages` that is not an object is a refusal (exit 3) with no write.
|
|
17
|
+
* This file is the only record of what a developer intended; silently
|
|
18
|
+
* resetting it is how a half-localized tree becomes invisible.
|
|
19
|
+
* 2. **Writes are atomic** -- `<file>.tmp` then `rename` -- so a killed run
|
|
20
|
+
* cannot leave a truncated file behind.
|
|
21
|
+
*
|
|
22
|
+
* A *partial entry* is different from a malformed file: it is skipped with a
|
|
23
|
+
* warning and its siblings still process, because one bad entry must not cost
|
|
24
|
+
* a developer the other nine.
|
|
25
|
+
*/
|
|
26
|
+
import fs from 'node:fs';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import { EXIT_BAD_FILE, LocalizeError } from './errors.js';
|
|
29
|
+
export const MANIFEST_FILENAME = 'local-packages.json';
|
|
30
|
+
/** The only schema version this build understands. */
|
|
31
|
+
export const SCHEMA_VERSION = 1;
|
|
32
|
+
/** Default checkout directory, relative to the consumer root. */
|
|
33
|
+
export const DEFAULT_DIR = 'packages-local';
|
|
34
|
+
export function manifestPath(appRoot) {
|
|
35
|
+
return path.join(appRoot, MANIFEST_FILENAME);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read and validate the manifest.
|
|
39
|
+
*
|
|
40
|
+
* A missing file is NOT an error: it is the CI case and the fresh-clone case,
|
|
41
|
+
* and reads as an empty set. That is also why no `if (CI)` branch exists
|
|
42
|
+
* anywhere in this package -- the file is gitignored, so CI is a natural no-op.
|
|
43
|
+
*
|
|
44
|
+
* @throws {LocalizeError} code 3. Nothing is written in any failure case.
|
|
45
|
+
*/
|
|
46
|
+
export function readManifest(appRoot, io = { warn: console.warn }) {
|
|
47
|
+
const file = manifestPath(appRoot);
|
|
48
|
+
if (!fs.existsSync(file)) {
|
|
49
|
+
return {
|
|
50
|
+
file,
|
|
51
|
+
exists: false,
|
|
52
|
+
version: SCHEMA_VERSION,
|
|
53
|
+
dir: DEFAULT_DIR,
|
|
54
|
+
entries: {},
|
|
55
|
+
malformed: [],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const raw = fs.readFileSync(file, 'utf8');
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(raw);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
throw new LocalizeError(`${file} is not valid JSON: ${e.message}\n` +
|
|
65
|
+
`Refusing to read or rewrite it -- it is the only record of what was localized. ` +
|
|
66
|
+
`Fix it by hand, or delete it to start over.`, EXIT_BAD_FILE);
|
|
67
|
+
}
|
|
68
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
69
|
+
throw new LocalizeError(`${file} does not contain a JSON object.\n` +
|
|
70
|
+
`Refusing to read or rewrite it. Expected {"version":${SCHEMA_VERSION},"packages":{…}}.`, EXIT_BAD_FILE);
|
|
71
|
+
}
|
|
72
|
+
if (parsed.version !== SCHEMA_VERSION) {
|
|
73
|
+
throw new LocalizeError(`${file} has schema version ${JSON.stringify(parsed.version)}; this version of localize understands ` +
|
|
74
|
+
`only version ${SCHEMA_VERSION}.\n` +
|
|
75
|
+
`Refusing to read or rewrite it -- guessing at a schema it did not write is how intent ` +
|
|
76
|
+
`gets lost. Upgrade localize, or delete the file and re-localize.`, EXIT_BAD_FILE);
|
|
77
|
+
}
|
|
78
|
+
if (parsed.packages === null ||
|
|
79
|
+
typeof parsed.packages !== 'object' ||
|
|
80
|
+
Array.isArray(parsed.packages)) {
|
|
81
|
+
throw new LocalizeError(`${file} has a "packages" field that is not an object (found ` +
|
|
82
|
+
`${Array.isArray(parsed.packages) ? 'an array' : typeof parsed.packages}).\n` +
|
|
83
|
+
`Refusing to read or rewrite it.`, EXIT_BAD_FILE);
|
|
84
|
+
}
|
|
85
|
+
const dir = typeof parsed.dir === 'string' && parsed.dir.length > 0
|
|
86
|
+
? parsed.dir
|
|
87
|
+
: DEFAULT_DIR;
|
|
88
|
+
const entries = {};
|
|
89
|
+
const malformed = [];
|
|
90
|
+
for (const [name, value] of Object.entries(parsed.packages)) {
|
|
91
|
+
const reason = validateEntry(value);
|
|
92
|
+
if (reason) {
|
|
93
|
+
malformed.push({ name, reason });
|
|
94
|
+
io.warn(`[localize] ${name}: malformed entry in ${MANIFEST_FILENAME} (${reason}) -- skipped. ` +
|
|
95
|
+
`The other entries are unaffected. \`linked localize ${name}\` rewrites it.`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
entries[name] = Object.assign(Object.assign(Object.assign(Object.assign({}, (typeof value.repo === 'string' && value.repo
|
|
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 } : {}));
|
|
101
|
+
}
|
|
102
|
+
return { file, exists: true, version: SCHEMA_VERSION, dir, entries, malformed };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* @returns {string|null} a reason the entry is unusable, else null.
|
|
106
|
+
*
|
|
107
|
+
* `repo` is optional: an adopted checkout may have no remote at all -- a
|
|
108
|
+
* package created locally that has not been pushed anywhere yet.
|
|
109
|
+
*/
|
|
110
|
+
function validateEntry(value) {
|
|
111
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
112
|
+
return 'not an object';
|
|
113
|
+
const missing = ['path', 'branch'].filter((k) => typeof value[k] !== 'string' || value[k].length === 0);
|
|
114
|
+
return missing.length ? `missing ${missing.join(', ')}` : null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write the manifest atomically: a `.tmp` in the SAME directory, so `rename`
|
|
118
|
+
* is atomic on one filesystem, then `rename` over the original.
|
|
119
|
+
*
|
|
120
|
+
* An empty `packages` object is written rather than the file being deleted, so
|
|
121
|
+
* a non-default `dir` survives delocalizing the last entry.
|
|
122
|
+
*/
|
|
123
|
+
export function writeManifest(appRoot, data) {
|
|
124
|
+
var _a;
|
|
125
|
+
const target = manifestPath(appRoot);
|
|
126
|
+
const tmp = `${target}.tmp`;
|
|
127
|
+
const out = Object.assign(Object.assign({ version: SCHEMA_VERSION }, (data.dir && data.dir !== DEFAULT_DIR ? { dir: data.dir } : {})), { packages: (_a = data.packages) !== null && _a !== void 0 ? _a : {} });
|
|
128
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
129
|
+
fs.writeFileSync(tmp, JSON.stringify(out, null, 2) + '\n', 'utf8');
|
|
130
|
+
fs.renameSync(tmp, target);
|
|
131
|
+
return target;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** A dependency the app has, left out because some localized checkout asks a range it misses. */
|
|
2
|
+
export interface ProvidedSkip {
|
|
3
|
+
name: string;
|
|
4
|
+
reason: 'range';
|
|
5
|
+
/** The localized checkouts whose range the app's version does not satisfy. */
|
|
6
|
+
asks: {
|
|
7
|
+
from: string;
|
|
8
|
+
range: string;
|
|
9
|
+
}[];
|
|
10
|
+
appVersion: string;
|
|
11
|
+
}
|
|
12
|
+
export interface Provided {
|
|
13
|
+
/** Sorted: the localized packages, the dependencies the app provides, react/react-dom. */
|
|
14
|
+
names: string[];
|
|
15
|
+
skipped: ProvidedSkip[];
|
|
16
|
+
/** The localized packages among `names` (installed at the app root). */
|
|
17
|
+
localized: string[];
|
|
18
|
+
/** The names in `names` that are there as a localized checkout's dependency. */
|
|
19
|
+
dependencies: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @param appRoot the app root (where `local-packages.json` and `node_modules` are)
|
|
23
|
+
* @param localizedNames the localized package names; defaults to the
|
|
24
|
+
* manifest's. Pruning passes the entries it is working on, so a checkout
|
|
25
|
+
* being localized right now counts before the manifest records it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function providedPackages(appRoot: string, localizedNames?: string[]): Provided;
|
|
28
|
+
//# sourceMappingURL=provided.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provided.d.ts","sourceRoot":"","sources":["../../../src/localize/provided.ts"],"names":[],"mappings":"AAsCA,iGAAiG;AACjG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,8EAA8E;IAC9E,IAAI,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,0FAA0F;IAC1F,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,wEAAwE;IACxE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gFAAgF;IAChF,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAA2B,GAChD,QAAQ,CAuCV"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE rule for what an app provides to its localized checkouts -- the one list
|
|
3
|
+
* that pruning (prune.ts), the run-time one-copy check (ensure.ts) and Vite's
|
|
4
|
+
* `resolve.dedupe` (`../localized-dedupe.ts`) all start from.
|
|
5
|
+
*
|
|
6
|
+
* - every localized package the app has installed -- always, whatever a range
|
|
7
|
+
* says: the live checkout is the point of localizing it, for every importer;
|
|
8
|
+
* - every runtime dependency a localized checkout declares (`dependencies`,
|
|
9
|
+
* `peerDependencies`, `optionalDependencies` -- what its source imports) that
|
|
10
|
+
* the app has at a version satisfying EVERY localized checkout's range for
|
|
11
|
+
* it. A range the app's version does not satisfy (or that cannot be read)
|
|
12
|
+
* leaves the name out, as `skipped`, with who asks what;
|
|
13
|
+
* - `react` and `react-dom` when the app has them.
|
|
14
|
+
*
|
|
15
|
+
* Scoped to what is localized on purpose: a duplicate comes from a checkout's
|
|
16
|
+
* own `npm install`, so the checkouts' declarations are what can produce one.
|
|
17
|
+
* The server's "installed N times" warning stays as the cross-check for
|
|
18
|
+
* anything this misses (a linked package hoisted into a checkout only
|
|
19
|
+
* transitively).
|
|
20
|
+
*
|
|
21
|
+
* Synchronous and cheap -- the manifest, one `package.json` per localized
|
|
22
|
+
* package and one per dependency it names -- because the run-time check calls
|
|
23
|
+
* it before every `linked start`.
|
|
24
|
+
*/
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
import path from 'node:path';
|
|
27
|
+
import { readInstalledPkgSync } from '../installed-packages.js';
|
|
28
|
+
import { readManifest } from './manifest.js';
|
|
29
|
+
import { readJson } from './fsops.js';
|
|
30
|
+
import { satisfies } from './prune.js';
|
|
31
|
+
const RUNTIME_FIELDS = [
|
|
32
|
+
'dependencies',
|
|
33
|
+
'peerDependencies',
|
|
34
|
+
'optionalDependencies',
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* @param appRoot the app root (where `local-packages.json` and `node_modules` are)
|
|
38
|
+
* @param localizedNames the localized package names; defaults to the
|
|
39
|
+
* manifest's. Pruning passes the entries it is working on, so a checkout
|
|
40
|
+
* being localized right now counts before the manifest records it.
|
|
41
|
+
*/
|
|
42
|
+
export function providedPackages(appRoot, localizedNames = manifestNames(appRoot)) {
|
|
43
|
+
var _a, _b, _c, _d, _e;
|
|
44
|
+
const localized = localizedNames.filter((name) => fs.existsSync(path.join(appRoot, 'node_modules', name, 'package.json')));
|
|
45
|
+
const names = new Set(localized);
|
|
46
|
+
const skipped = [];
|
|
47
|
+
const dependencies = [];
|
|
48
|
+
// name -> every localized checkout's runtime range for it
|
|
49
|
+
const asks = new Map();
|
|
50
|
+
for (const from of localized) {
|
|
51
|
+
const pkg = (_a = readJson(path.join(appRoot, 'node_modules', from, 'package.json'))) !== null && _a !== void 0 ? _a : {};
|
|
52
|
+
for (const field of RUNTIME_FIELDS) {
|
|
53
|
+
for (const [dep, range] of Object.entries((_b = pkg[field]) !== null && _b !== void 0 ? _b : {})) {
|
|
54
|
+
if (names.has(dep))
|
|
55
|
+
continue;
|
|
56
|
+
const list = (_c = asks.get(dep)) !== null && _c !== void 0 ? _c : [];
|
|
57
|
+
if (!list.some((a) => a.from === from))
|
|
58
|
+
list.push({ from, range });
|
|
59
|
+
asks.set(dep, list);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const [name, ranges] of asks) {
|
|
64
|
+
const appVersion = (_e = (_d = readInstalledPkgSync(name, appRoot)) === null || _d === void 0 ? void 0 : _d.json) === null || _e === void 0 ? void 0 : _e.version;
|
|
65
|
+
if (!appVersion)
|
|
66
|
+
continue; // the app does not provide it
|
|
67
|
+
const unmet = ranges.filter((a) => satisfies(appVersion, a.range) !== true);
|
|
68
|
+
if (unmet.length)
|
|
69
|
+
skipped.push({ name, reason: 'range', asks: unmet, appVersion });
|
|
70
|
+
else {
|
|
71
|
+
names.add(name);
|
|
72
|
+
dependencies.push(name);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const name of ['react', 'react-dom']) {
|
|
76
|
+
if (readInstalledPkgSync(name, appRoot))
|
|
77
|
+
names.add(name);
|
|
78
|
+
}
|
|
79
|
+
return { names: [...names].sort(), skipped, localized, dependencies };
|
|
80
|
+
}
|
|
81
|
+
function manifestNames(appRoot) {
|
|
82
|
+
try {
|
|
83
|
+
return Object.keys(readManifest(appRoot, { warn: () => { } }).entries);
|
|
84
|
+
}
|
|
85
|
+
catch (_a) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=provided.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provided.js","sourceRoot":"","sources":["../../../src/localize/provided.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * THE rule for what an app provides to its localized checkouts -- the one list\n * that pruning (prune.ts), the run-time one-copy check (ensure.ts) and Vite's\n * `resolve.dedupe` (`../localized-dedupe.ts`) all start from.\n *\n * - every localized package the app has installed -- always, whatever a range\n * says: the live checkout is the point of localizing it, for every importer;\n * - every runtime dependency a localized checkout declares (`dependencies`,\n * `peerDependencies`, `optionalDependencies` -- what its source imports) that\n * the app has at a version satisfying EVERY localized checkout's range for\n * it. A range the app's version does not satisfy (or that cannot be read)\n * leaves the name out, as `skipped`, with who asks what;\n * - `react` and `react-dom` when the app has them.\n *\n * Scoped to what is localized on purpose: a duplicate comes from a checkout's\n * own `npm install`, so the checkouts' declarations are what can produce one.\n * The server's \"installed N times\" warning stays as the cross-check for\n * anything this misses (a linked package hoisted into a checkout only\n * transitively).\n *\n * Synchronous and cheap -- the manifest, one `package.json` per localized\n * package and one per dependency it names -- because the run-time check calls\n * it before every `linked start`.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {readInstalledPkgSync} from '../installed-packages.js';\nimport {readManifest} from './manifest.js';\nimport {readJson} from './fsops.js';\nimport {satisfies} from './prune.js';\n\nconst RUNTIME_FIELDS = [\n 'dependencies',\n 'peerDependencies',\n 'optionalDependencies',\n];\n\n/** A dependency the app has, left out because some localized checkout asks a range it misses. */\nexport interface ProvidedSkip {\n name: string;\n reason: 'range';\n /** The localized checkouts whose range the app's version does not satisfy. */\n asks: {from: string; range: string}[];\n appVersion: string;\n}\n\nexport interface Provided {\n /** Sorted: the localized packages, the dependencies the app provides, react/react-dom. */\n names: string[];\n skipped: ProvidedSkip[];\n /** The localized packages among `names` (installed at the app root). */\n localized: string[];\n /** The names in `names` that are there as a localized checkout's dependency. */\n dependencies: string[];\n}\n\n/**\n * @param appRoot the app root (where `local-packages.json` and `node_modules` are)\n * @param localizedNames the localized package names; defaults to the\n * manifest's. Pruning passes the entries it is working on, so a checkout\n * being localized right now counts before the manifest records it.\n */\nexport function providedPackages(\n appRoot: string,\n localizedNames: string[] = manifestNames(appRoot),\n): Provided {\n const localized = localizedNames.filter((name) =>\n fs.existsSync(path.join(appRoot, 'node_modules', name, 'package.json')),\n );\n const names = new Set<string>(localized);\n const skipped: ProvidedSkip[] = [];\n const dependencies: string[] = [];\n\n // name -> every localized checkout's runtime range for it\n const asks = new Map<string, {from: string; range: string}[]>();\n for (const from of localized) {\n const pkg =\n readJson(path.join(appRoot, 'node_modules', from, 'package.json')) ?? {};\n for (const field of RUNTIME_FIELDS) {\n for (const [dep, range] of Object.entries<string>(pkg[field] ?? {})) {\n if (names.has(dep)) continue;\n const list = asks.get(dep) ?? [];\n if (!list.some((a) => a.from === from)) list.push({from, range});\n asks.set(dep, list);\n }\n }\n }\n\n for (const [name, ranges] of asks) {\n const appVersion = readInstalledPkgSync(name, appRoot)?.json?.version;\n if (!appVersion) continue; // the app does not provide it\n const unmet = ranges.filter((a) => satisfies(appVersion, a.range) !== true);\n if (unmet.length)\n skipped.push({name, reason: 'range', asks: unmet, appVersion});\n else {\n names.add(name);\n dependencies.push(name);\n }\n }\n\n for (const name of ['react', 'react-dom']) {\n if (readInstalledPkgSync(name, appRoot)) names.add(name);\n }\n return {names: [...names].sort(), skipped, localized, dependencies};\n}\n\nfunction manifestNames(appRoot: string): string[] {\n try {\n return Object.keys(readManifest(appRoot, {warn: () => {}}).entries);\n } catch {\n return [];\n }\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ProvidedSkip } from './provided.js';
|
|
2
|
+
import type { ManifestEntry } from './manifest.js';
|
|
3
|
+
import type { Deps } from './run.js';
|
|
4
|
+
/** What pruning reads from a command's options. */
|
|
5
|
+
export interface PruneOptions {
|
|
6
|
+
/** On unless explicitly false. */
|
|
7
|
+
prune?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Limit a prune to some checkouts and/or some dependency names. */
|
|
10
|
+
export interface PruneScope {
|
|
11
|
+
/** Only these localized packages' checkouts. */
|
|
12
|
+
owners?: string[];
|
|
13
|
+
/** Only these dependency names. */
|
|
14
|
+
deps?: string[];
|
|
15
|
+
}
|
|
16
|
+
/** What pruning may remove: the rule's names plus every localized sibling, and what the rule skipped. */
|
|
17
|
+
export interface Candidates {
|
|
18
|
+
names: Set<string>;
|
|
19
|
+
skipped: Map<string, ProvidedSkip>;
|
|
20
|
+
}
|
|
21
|
+
/** The candidates for `entries`, by `providedPackages` (provided.ts). */
|
|
22
|
+
export declare function candidatesFor(entries: Record<string, ManifestEntry>, deps: Pick<Deps, 'appRoot'>): Candidates;
|
|
23
|
+
/**
|
|
24
|
+
* Does the app's installed `version` satisfy `range`? `null` means "cannot
|
|
25
|
+
* tell" -- a dist-tag, `file:`, `npm:`, `workspace:`, a git URL, or a version
|
|
26
|
+
* that is not one -- and every caller then keeps the copy. The failure mode is
|
|
27
|
+
* therefore always the safe one: a copy kept that could have gone, never a
|
|
28
|
+
* copy removed that was needed.
|
|
29
|
+
*
|
|
30
|
+
* npm's own `semver` decides, so prereleases follow npm's rule: `1.3.0-beta.1`
|
|
31
|
+
* satisfies a range only when one of its comparators names a prerelease on
|
|
32
|
+
* the same `major.minor.patch`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function satisfies(version: string, range: string): boolean | null;
|
|
35
|
+
/** Pruning is on unless a caller says `{prune: false}`. */
|
|
36
|
+
export declare function shouldPrune(opts?: PruneOptions): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* @param entries the localized packages: every one counts as a sibling
|
|
39
|
+
* @param opts unused beyond `prune`, which callers check with `shouldPrune`
|
|
40
|
+
* @param deps `{appRoot, log, warn}`
|
|
41
|
+
* @param scope prune only some checkouts / names (the run-time check)
|
|
42
|
+
*/
|
|
43
|
+
export declare function pruneProvided(entries: Record<string, ManifestEntry>, opts: PruneOptions, deps: Pick<Deps, 'appRoot' | 'log' | 'warn'>, scope?: PruneScope): {
|
|
44
|
+
removed: any[];
|
|
45
|
+
kept: any[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Is `dep` -- declared by a checkout at `range` -- something the app provides,
|
|
49
|
+
* so that its absence from the checkout's own `node_modules` is not a
|
|
50
|
+
* dependency gone missing? `--relink` asks this before reinstalling a
|
|
51
|
+
* checkout, so a copy pruned on purpose does not trigger a reinstall on every
|
|
52
|
+
* postinstall.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isProvidedByApp(dep: string, range: string | undefined, entries: Record<string, ManifestEntry>, candidates: Candidates, deps: Pick<Deps, 'appRoot'>): boolean;
|
|
55
|
+
/** The package dir's `node_modules`, and the clone root's when the package is a monorepo subdir. */
|
|
56
|
+
export declare function nodeModulesRoots(pkgDir: any, entry: any): string[];
|
|
57
|
+
export declare function realOrSelf(p: string): string;
|
|
58
|
+
//# sourceMappingURL=prune.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prune.d.ts","sourceRoot":"","sources":["../../../src/localize/prune.ts"],"names":[],"mappings":"AAoEA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,UAAU,CAAC;AAEnC,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,yGAAyG;AACzG,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACpC;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACtC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAC1B,UAAU,CAMZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAKxE;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAE5D;AAcD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACtC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC,EAC5C,KAAK,GAAE,UAAe,GACrB;IAAC,OAAO,EAAE,GAAG,EAAE,CAAC;IAAC,IAAI,EAAE,GAAG,EAAE,CAAA;CAAC,CAqC/B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACtC,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAC1B,OAAO,CAMT;AAwJD,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,MAAM,KAAA,EAAE,KAAK,KAAA,YAQ7C;AAwDD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM5C"}
|