The web UI a `tcm serve` server shows (`/forge/`): a codebase's front page, namespaces and definitions, search, contributions and their review, history, branches, releases and people. Each page renders on the server from the codebase it serves (`TCM_SHARE_CODEBASE`, or this app's own, under `tcm dev`); links between them are followed in the app. `tcm dev tcmts.share.App` serves tcm's own codebase while you work on it.
A row of a diff as a page shows it: a line (added, removed or unchanged; its numbers before and after; its HTML), or a run of `gap` lines left out (`cut`: the end of one cut short).
A codebase's history entries' names, read as the trees they're stored as. A namespace node's hash is its content's, so two entries' names differ only under nodes whose hashes differ, and comparing them reads only those; one name is a walk down its path. What's read is kept (a node never changes), and so are the last few entries' names, each made from the names asked for before it and what changed between them: walking a branch's history back reads each step's changes, not every name of every entry.
What a page shows if it doesn't load (the server failed or refused it, or is unreachable): what went wrong and a way to try again, not a blank page. Going to another page tries that one.
What a server keeps between page requests: what depends only on the branch's head (its names, placement, what each definition is for), made once for each head and dropped when it moves; and what never changes (an entry's changes, a release's definitions, the history's namespaces).
A contribution's page: the conversation (its description, comments and events, the merge box), or the changes read along a review path (what's new before what uses it, then tests; what only re-hashed last, folded).
ContributionsPage({ state }: { state: string; }) => Promise<Element>
The contributions: open ones, or merged, closed or all of them.
DefRow({ row, full }: { row: NameRow; full?: boolean | undefined; }) => Element
A definition in a list: where it runs, its name, its type, the first line of its doc.
A definition: its doc and code (references linked, their types shown on hover), what uses it; beside them what only a codebase knows: what it uses, the tests that reach it, its history, its other names, the releases it's in.
EntryChangeGroup({ hash, from, to, }: { hash: string; from: number; to: number; }) => Promise<Element | null>
Some of a history entry's changes (`from` to `to`, in review order), as its page shows them (MoreChanges).
One history entry: what it's for (its message, if it has one), when and how it was made, and what it changed, each definition with its lines (as a contribution's changes show), what only re-hashed folded away.
Every page's frame: the project's name, the finder, who's signed in, and the tabs with their counts. On a private server, with no token, it's the sign-in page instead. An app showing these pages as its own sets pageFrame.
The front page: what the project is and how to get it, what you can use (its packages, apps and docs), a map of its namespaces with where their code runs, and its README.
The history: a branch's entries by day, each with what it changed by name and count (an entry that re-hashed hundreds of definitions but edited four reads as small), `under` one namespace if asked.
MergeBox({ c, m, tests }: { c: Contribution; m: Mergeable | null; tests: number; }) => Element
Whether it merges, and what the viewer may do about it: merge (the maintainer), close or reopen (theirs too).
A namespace: where it is, the namespaces in it, its definitions by what they're for, its README.
PackageBox({ pkg }: { pkg: PackageInfo; }) => Element
A package, on its manifest's page: what it is and its releases, the commands it runs, what it exports, and the apps, files and end-to-end tests it ships, each a link to what it names.
Who the request is from: the token its cookie holds (the server's, its maintainer's; a contributor's), or none, a reader (on a public server). Undefined when the server is private and there's no token. With no server token at all (`tcm dev` on a codebase of your own), everyone is its maintainer.
A definition's code as lines, as a diff compares it, its references read with `nameOf`; `text` reads one of its text versions (its comments, layout and doc), `undefined` the one it was first stored with.
What a history entry changed, definition by definition (reviewItems, in review order), and what only re-hashed; undefined for the first entry. Names come as `entryDiff`'s do.
A definition's lines (definitionLines) as highlighted HTML, one for each: code coloured as its page colours it; a file by its format (TypeScript, JavaScript and JSON coloured, other text as it is). Not `exact`, JSX is read by the scanner alone, which is quick (text between tags may be coloured as code).
Run `steps` in turn, letting other work run every `slice` milliseconds, so what a page or the warm-up makes in bulk doesn't hold up the pages asked for meanwhile; in the `background`, it waits while a page is making something. It stops when `go` says to; whether it finished.
Markdown as HTML for a page: `tcm-page:<hash>` links (a doc's links to code, a page's to other pages) open that definition's page, images kept in the codebase (`tcm-page:<hash>` too) are shown, each a link to its page, and TypeScript code blocks are highlighted. Other links are kept only to http(s), mailto and relative addresses (`safeHref`): a README, a comment or a contribution's description can't make a `javascript:` link.
The changed definitions a namespace diff holds, each with its lines, coloured (highlightedLines): what's added or removed, whole; what's edited or reworded, as a line diff; what's renamed or conflicted, by name. `oldNames` and `newNames` name what the code refers to, before and after.
roleNow(s: Pick<Share, "cache" | "cb">, r: NameRow) => Role
What a named definition is for (roleOf), told once for each head.
Make what the pages read of the branch's head before they're asked for it, as they'd make it: what each definition is for (and where it runs), the front page's map, how many history entries there are, and the history's first ten pages, in the background (inSlices); it stops if the head moves.
A definition's or file's code in a box: a head, the line count, then its lines, numbered (`CodeLines`). A file with a view of its own (Markdown rendered, an image) shows that first, with a switch to its code; an address naming lines shows the code.
CodeLines({ lines }: { lines: string[]; }) => Element
Code as numbered lines. A line's number links to it (`#L12`); shift-clicking another makes a range (`#L12-L20`). The lines the address names are marked and scrolled to.
A button that copies some text (a name, a command), saying so (or that the browser wouldn't); pointing at it shows what it copies.
DiffLines({ rows, more }: { rows: DiffRow[]; more?: string | undefined; }) => Element | null
A diff's rows (foldDiff's), coloured as code: what's added and removed marked, each line numbered before and after, ⋮ for the lines left out. One line after another, or side by side as DiffMode chooses (on a screen wide enough). `more` is where the rest of a diff cut short is (its definition's page).
The switch between diffs' two layouts, one line after another (unified) and side by side (split): for every diff on the page, and remembered by the browser.
The history's filter: which branch (a select), and under which namespace (a search field).
MoreChanges({ hash, from, total }: { hash: string; from: number; total: number; }) => Element
A history entry's changes from `from` on, loaded as they're scrolled to: ten at a time, each ten asked for when the page comes within a screen of them, and the next ten's turn only once those are in. A merge of hundreds sends what's read.
The finder in the header (React Aria's Autocomplete: a search field over a list of results): names, words in docs, or a type (`:(xs: T[]) => T`), with results as you type. ⌘K or / goes to it, arrows choose, Enter opens the result chosen (or, with none chosen, the search page). On the search page it holds what was searched for.
SignInForm({ then }: { then: string; }) => Element
The sign-in form: a token (a contributor's, or the server's), then the page asked for.
Put some text on the clipboard: by the Clipboard API, or, where a page may not use it (an embedded browser, a page without the permission), by copying a selection of it, as browsers always have. Fails if neither is allowed.
Shared
Avatar({ name, large }: { name: string; large?: boolean | undefined; }) => Element
Someone's avatar: a placeholder, the same for everyone until people have pictures, named for who it is.
"Get it": a button that opens how to (React Aria's dialog, in a popover): the command that makes a codebase and pulls this one, to copy, and what comes after.
A row of tabs that are links (the project's, a contribution's, a list's states): React Aria's Tabs, with the page's own selected (none, on a page of none of them). Arrow keys move between them; Enter or a click goes. (Its tabs are elements, not a function of the list: it renders on the server too, and a function can't go to the browser.)
What a history entry changed, from the entry before it (its first parent: a merge's, what it brought); undefined for the first entry. Its names, and its parent's, are made from the names read last (NameTrees).
A change's lines as the rows a page sends (DiffRow): each change and two lines of context around it, the rest as gaps, each line once (its HTML, or its text made HTML); past `most` rows, the rest one gap. Done before the page goes to the browser, so a one-line edit to a long definition sends a few lines, not two copies of it.
Lines already coloured (highlightedLines), by their text and how it was read: a diff's sides come again and again (an entry's page, a contribution's, the next entry's). The newest few thousand are kept.
Highlighted code's HTML as lines: an element a line break falls inside is closed at the end of its line and opened again on the next, so each line is whole. A final line break ends the last line; it doesn't start another.
Highlighted code (`highlight`'s) with its references made links: to the page of the definition or namespace they name, with the definition's name and type to show on hover.
A package manifest's fields as its source writes them: the object it declares, read, never run (a page runs no code). Strings, and arrays and objects of them, come through (`as const` and the like after one are fine); anything computed doesn't.
The history entries that changed what a name is: when it was added, each change to its code (or what it uses), and its removal, newest first; looking back `scan` entries along the branch's first parents, at most `limit`.
The name a package's manifest means by one of its `files`: a name in its namespace, or a path from the codebase's root (`../README.md`), read as the file kept under the namespace it would be written from.
The frame every page is drawn in, if an app showing the forge's pages has its own (the hub: its header, not a project's): set once, as that app's pages start.
The project a codebase is: named for the package at its top namespace (or the namespace), described by that package's doc or the first sentence of its README. Manifests are read from their source, not evaluated.
The order to review changes in: what's new before what uses it, so each definition is read after what it depends on; then tests; removed and renamed last. `usesOf` says which hashes a hash uses.
A link's address, if it's one a page may link to: http, https or mailto, or one with no scheme (a path, `#…`). Others (`javascript:`, `data:`, `vbscript:`…) are undefined, read as a browser reads them (it skips tabs, newlines and leading spaces and control characters, so `java\tscript:` is `javascript:`).