import { describeFile, describeFolder, firstSentence } from "../describe/describe.ts"; import { filesAt, fileTouches, objectBytes, type Save, type Touches } from "../mirror/queries.ts"; import type { Release } from "../releases/releases.ts"; import { isText } from "./files.ts"; import { type Html, html } from "./html.ts"; import { formatDate, formatSize, type PublicRepo, pathUrl, plural, relativeTime, } from "./layout.ts"; import { type MarkdownBase, renderLine, renderMarkdown } from "./markdown.ts"; type AtlasFile = { name: string; path: string; size: number; lines: number | null; description: string | null; /** The saves that touched it, oldest first. */ saves: Save[]; }; type AtlasFolder = { name: string; path: string; folders: AtlasFolder[]; files: AtlasFile[]; /** The saves that touched anything under it, removed files included, oldest first. */ saves: Save[]; }; type View = { repo: string; at: string | null }; type Facts = { lines: number | null; description: string | null }; // Measured: Koh 3's vendored 9 MB sqlite3.c cost every Atlas view ~25 ms to inflate and scan. An // object never changes, so what it says about itself is kept for the life of the process, keyed by // hash and file name (the name picks the comment syntax). // ponytail: unbounded, one small entry per object viewed; an LRU if a bucket reaches millions. const known = new Map(); function factsOf(db: PublicRepo["mirror"], hash: string, name: string): Facts { const key = `${hash} ${name}`; const cached = known.get(key); if (cached) return cached; const bytes = objectBytes(db, hash); const text = bytes && isText(bytes) ? new TextDecoder().decode(bytes) : null; const facts = text === null ? { lines: null, description: null } : { lines: countLines(text), description: describeFile(name, text) }; known.set(key, facts); return facts; } /** * §21.5's Atlas at one save: the folder tree as `
`, so it opens and links without * JavaScript. Each row is followed by a `