mv
uses tcmts.cli.files.followMove, which uses Buffer
import { IDENT_PATH } from "#codebase/tcmts/cli/codebase"; import type { Codebase } from "#codebase/tcmts/cli/codebase"; import { FILE_PATH, followMove } from "#codebase/tcmts/cli/files"; import { loadMirror } from "#codebase/tcmts/cli/mirror"; import { dim } from "#codebase/tcmts/cli/style"; import { UsageError } from "#codebase/tcmts/cli/ui"; export function mv(cb: Codebase, from: string, to: string) { const exact = cb.store.names(undefined, true).filter((n) => n.path === from); const moves = exact.length ? exact.map((n) => ({ ...n, dest: to })) : cb.store .names(undefined, true) .filter((n) => n.path.startsWith(from + ".")) .map((n) => ({ ...n, dest: to + n.path.slice(from.length) })); if (!moves.length) throw new UsageError(`'${from}' not found`); // (a file's own name, like `getting-started`, may have dashes) for (const m of moves) if (!(m.kind === "file" ? FILE_PATH : IDENT_PATH).test(m.dest)) throw new UsageError(`'${m.dest}' is not a valid name`); for (const m of moves) if (cb.store.hashesAt(m.dest).length) throw new UsageError(`'${m.dest}' already exists`); cb.store.transaction(() => { for (const m of moves) { cb.store.removeName(m.path, m.hash, `mv ${from} ${to}`); cb.store.addName(m.dest, m.hash, m.kind, `mv ${from} ${to}`); } }); // pages linking to a file that moved link to where it is now (and one that moved links from there) for (const m of moves.filter((x) => x.kind === "file")) { const relinked = followMove(cb, m.path, m.dest); cb.putDefs([...relinked.values()]); const replaced = new Map<string, string>(); cb.store.transaction(() => { for (const [page, rec] of relinked) for (const old of cb.store.hashesAt(page)) { cb.store.replaceName(page, old, rec.hash, "file", `mv ${from} ${to} (links)`); replaced.set(old, rec.hash); } }); if (relinked.size) console.log(dim(` links to it changed in ${[...relinked.keys()].join(", ")}`)); // (and what uses those pages, the docs site's list of them say, follows them, as it follows an update) for (const [old, now] of replaced) cb.store.addPatch(old, now); if (replaced.size) cb.propagate(replaced); } cb.refreshShim(); console.log(`moved ${moves.length} name${moves.length > 1 ? "s" : ""}`); const mirror = loadMirror(cb); for (const m of moves) { // a mirror renames the code itself, so the runtime name follows if (mirror && m.dest.startsWith(mirror.into ? `${mirror.into}.` : "")) continue; const rec = cb.store.getDef(m.hash)!; const runtime = rec.nameHint; if (rec.nominal && runtime !== m.dest.slice(m.dest.lastIndexOf(".") + 1)) { console.log( dim( ` note: ${m.dest} is still named \`${runtime}\` at runtime (\`.name\` is part of its hash); changing that means editing it`, ), ); } } }
uses
- tcmts.cli.codebase.Codebase
- tcmts.cli.codebase.IDENT_PATH
- tcmts.cli.files.FILE_PATH
- tcmts.cli.files.followMove
- tcmts.cli.mirror.loadMirror
- tcmts.cli.style.dim
- tcmts.cli.ui.UsageError