importFiles
uses node:path
Import the files under root: the hash of each definition's code in them, by path, or undefined if they don't
import. Following a mirror's files, a definition they haven't changed since tcm last saw them stays as the
codebase has it (it may have changed it while write-back waited), and one gone from the files goes from the
codebase.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { apply, checkDistinct, classifyPaths, importAssets } from "#codebase/tcmts/cli/main"; import { joinName, namespaceForFile, sourceFiles } from "#codebase/tcmts/cli/mirror"; import type { Mirror } from "#codebase/tcmts/cli/mirror"; import { bold, dim, red, yellow } from "#codebase/tcmts/cli/style"; import { UsageError } from "#codebase/tcmts/cli/ui"; import path_1 from "node:path"; export function importFiles( cb: Codebase, root: string, dir: string, mode: "add" | "update", into: string, verbose: boolean, exclude: string[], tests: boolean, following?: Mirror, ): Map<string, string> | undefined { const files = sourceFiles(root, new Set(exclude.map((e) => path_1.resolve(root, e))), tests); if (!files.length) throw new UsageError(`no .ts files under ${dir}`); // (files that aren't code come after it: a page's links to code need the code) const done = (held: Map<string, string> | undefined) => { const assets = held && importAssets(cb, root, dir, mode, into, verbose, exclude, following); return held && assets && new Map([...held, ...assets]); }; console.log(dim(`analyzing ${files.length} files under ${dir}…`)); cb.refreshShim(); const a = cb.analyzeProject( files, (file, name) => cb.lineageSalt(joinName(into, namespaceForFile(root, file), name)), [], // (the augmentations these files hold new versions of are left out) cb.compilerOptions(root, "import", (p) => !into || p.startsWith(`${into}.`)), ); for (const w of a.warnings) console.log(yellow(`warning: ${w}`)); if (a.diagnostics.length || a.errors.length) { for (const d of a.diagnostics) process.stdout.write(d.formatted); for (const e of a.errors) console.log(red(e)); console.log( red(`\n${a.errors.length + a.diagnostics.length} problem(s); nothing was imported.`), ); return undefined; } const planned = a.defs.map((def) => ({ def, path: joinName(into, namespaceForFile(root, def.file), def.nameHint), })); checkDistinct( planned, (p) => `${p.path} is defined in more than one file (one of them is ${p.def.file})`, ); cb.lockPackages(a.packages); const held = new Map(planned.map((p) => [p.path, p.def.hash])); if (!following) return done( apply(cb, classifyPaths(cb, planned), mode, `import ${dir}`, !verbose) ? held : undefined, ); const was = new Map<string, string>(); for (const f of Object.values(following.files)) for (const [leaf, h] of Object.entries(f.names)) was.set(joinName(f.ns, leaf), h); const changed = planned.filter((p) => was.get(p.path) !== p.def.hash); for (const p of changed) { const w = was.get(p.path); if (w && !cb.store.hashesAt(p.path, p.def.kind).includes(w)) console.log( yellow(` ! ${p.path} changed in the files and in the codebase; the files' change is kept`), ); } const gone = [...was].filter( ([p, h]) => !held.has(p) && cb.store.getDef(h)?.kind !== "file" && cb.store.hashesAt(p).includes(h), ); if (!changed.length && !gone.length) console.log(dim("nothing to do")); const ok = !changed.length || apply(cb, classifyPaths(cb, changed), mode, `import ${dir}`, !verbose); for (const [p, h] of gone) { cb.store.removeName(p, h, `import ${dir}`); console.log(`${red(" - removed ")} ${bold(p)} ${dim("(gone from the files)")}`); } return done(ok ? held : undefined); }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.main.apply
- tcmts.cli.main.checkDistinct
- tcmts.cli.main.classifyPaths
- tcmts.cli.main.importAssets
- tcmts.cli.mirror.Mirror
- tcmts.cli.mirror.joinName
- tcmts.cli.mirror.namespaceForFile
- tcmts.cli.mirror.sourceFiles
- tcmts.cli.style.bold
- tcmts.cli.style.dim
- tcmts.cli.style.red
- tcmts.cli.style.yellow
- tcmts.cli.ui.UsageError