importAssets
uses node:path
Import the files under root that aren't code (Markdown, CSS, images), as files of the codebase: their hashes,
by name, or undefined if they don't import. Following a mirror, one it hasn't changed stays as the codebase
has it, and one gone from the files goes from the codebase.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { fileDefinition } from "#codebase/tcmts/cli/files"; import { apply, classifyPaths } from "#codebase/tcmts/cli/main"; import { assetFiles, assetFormat, assetName, joinName } from "#codebase/tcmts/cli/mirror"; import type { Mirror } from "#codebase/tcmts/cli/mirror"; import { bold, dim, red, yellow } from "#codebase/tcmts/cli/style"; import type { DefRecord } from "#codebase/tcmts/core/types"; import fs from "node:fs"; import path_1 from "node:path"; export function importAssets( cb: Codebase, root: string, dir: string, mode: "add" | "update", into: string, verbose: boolean, exclude: string[], following?: Mirror, ): Map<string, string> | undefined { let failed = false; // a file that can't be named in the codebase (a dot in its name) is a problem with it, said, not a stop const named = assetFiles(root, new Set(exclude.map((e) => path_1.resolve(root, e)))).flatMap( (f) => { try { return [{ f, name: assetName(root, into, f) }]; } catch (e) { console.log(red(`${path_1.relative(root, f)}: ${(e as Error).message}`)); failed = true; return []; } }, ); const names = new Set(named.map((n) => n.name)); const planned: { def: DefRecord; path: string; warnings: string[] }[] = []; for (const { f, name } of named) { const { def, problems, warnings } = fileDefinition( cb, name, assetFormat(f), fs.readFileSync(f), names, ); for (const p of problems) console.log(red(`${path_1.relative(root, f)}: ${p}`)); failed ||= problems.length > 0; planned.push({ def, path: name, warnings }); } if (failed) return undefined; const held = new Map(planned.map((p) => [p.path, p.def.hash])); const was = new Map<string, string>(); // by what the codebase has for them: a removed file's mark (.tcm-files) may be gone with it const isFile = (f: Mirror["files"][string]) => Object.values(f.names).some((h) => cb.store.getDef(h)?.kind === "file"); if (following) for (const f of Object.values(following.files)) if (isFile(f)) 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); // what's wrong with the files that changed (the others said so when they did) for (const p of changed) for (const w of p.warnings) console.log(yellow(`warning: ${w}`)); if (changed.length && !apply(cb, classifyPaths(cb, changed), mode, `import ${dir}`, !verbose)) return undefined; for (const [p, h] of was) { if (held.has(p) || !cb.store.hashesAt(p).includes(h)) continue; cb.store.removeName(p, h, `import ${dir}`); console.log(`${red(" - removed ")} ${bold(p)} ${dim("(gone from the files)")}`); } return held; }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.files.fileDefinition
- tcmts.cli.main.apply
- tcmts.cli.main.classifyPaths
- tcmts.cli.mirror.Mirror
- tcmts.cli.mirror.assetFiles
- tcmts.cli.mirror.assetFormat
- tcmts.cli.mirror.assetName
- tcmts.cli.mirror.joinName
- tcmts.cli.style.bold
- tcmts.cli.style.dim
- tcmts.cli.style.red
- tcmts.cli.style.yellow
- tcmts.core.types.DefRecord