6. Working in scratch files

Your code lives in the codebase; scratch files are where you write it. This page is the everyday loop: writing, saving, changing, fixing, renaming and undoing.

6.1 Scratch files

Any .ts file at the top of your codebase directory is a scratch file (ucm init makes scratch.ts). It's ordinary TypeScript: your editor checks it, and node scratch.ts runs it.

Once code is saved, you can empty or delete the file. Many people keep one scratch file and reuse it.

6.2 Check, add, update

ucm check (or ucm, which checks every time you save) reports each definition in the file:

statusmeaningto save it
newnot in the codebase yetucm add
identicalalready saved, exactly thisnothing to do
updatethe name exists, with different codeucm update
docsame code, a new doc commentucm add or ucm update
aliasthis exact code is already saved under another nameucm add gives it a second name
conflictthe name has several definitions (after a merge)ucm resolve, see merging

ucm add saves new things and never replaces anything: a name that's already taken is skipped with a note. ucm update also replaces, and that's where the codebase does its work.

6.3 When an update breaks something

ucm update re-checks everything that uses what you changed. What still typechecks is updated along with it. What doesn't keeps its old version, so the codebase is never half-changed, and goes on the todo list:

$ ucm update
  ~ update    geo.distance : (a: Point, b: Point, unit: "m" | "km") => number  (was #vwvxl53m)

  1 dependent definition(s) no longer typecheck; see `ucm todo`

$ ucm todo
needs fixing geo.pathLength: Expected 3 arguments, but got 2.

fix with `ucm edit <name>`, change the scratch file, then `ucm update`

ucm edit writes a definition back into a scratch file, already pointing at the new versions of what it uses:

$ ucm edit geo.pathLength
wrote geo.pathLength to scratch.ts
// ucm: namespace geo
import { distance } from "#codebase/geo";
import type { Point } from "#codebase/geo";

/**
 * How far you travel visiting the points in order.
 */
export const pathLength = (ps: Point[]): number => ps.slice(1).reduce((n, p, i) => n + distance(ps[i]!, p), 0)

Fix it (here, pass the unit: distance(ps[i]!, p, "m")) and update:

$ ucm update
  ~ update    geo.pathLength : (ps: Point[]) => number  (was #3ah7ke6j)

$ ucm todo
nothing to do

6.4 Editing what's saved

ucm edit <name>... is also how you change anything: it writes definitions into scratch.ts (refusing to overwrite a file with something in it; --file other.ts picks another, --force overwrites). Edit, then ucm update. You can edit several at once, from different namespaces: each gets a // ucm: path a.b.c comment when its path isn't the file's namespace plus its name, so update puts it back where it came from.

6.5 Names

Names are labels; changing them never touches code.

6.6 Undo

ucm history lists every change to names on this branch, newest first, and ucm reset <id> goes back to just after an entry. Code is never deleted, so a reset can always be reset again. ucm diff shows what the last command changed, or what changed since an entry: ucm diff 12.

6.7 Browsing

In VS Code, all of this is in the sidebar and in hovers (editors).

built from 5890e54f