Tests, doc comments & annotations

Implemented

test blocks that run with clay test or the Run button, /** */ comments, and @name(...) annotations that travel with a definition.

Tests

test "name" => expr at the top level defines a test: expr must be a bool. It is stored as an ordinary term named test_<slug> (lowercase, runs of other characters become _) that hashes exactly like the plain let, so a test is shared, synced and brought in like any other definition. Only the unhashed source text records that it is a test.

let double = (n: int): int => n * 2

/** Doubles a number, twice. Shown on hover and in search. */
let twice = (n: int): int => double(double(n))

test "double doubles" => double(4) == 8
test "twice quadruples" => twice(3) == 12
Verified: clay test reports both as PASS.

clay test [file|name] [--no-ucm] [--json] prints PASS, FAIL or ERROR per test and exits non-zero on any failure. Each test runs in the in-process engine and again through UCM, and a difference between the two is reported as a disagreement. In the editor, Run prints PASS or FAIL for each test in the buffer, offline too.

Doc comments

/** ... */ immediately before a definition is its documentation. It is a grammar extra kept in the definition’s unhashed source text, so it can never change a hash, and it survives rename, update, move, sync and the bucket. It shows in editor hover, in the tooltip of the definition’s chip in the This-file panel, in Browser search results (searchable) and in clay view.

Only /** */ counts (no ///). The doc is read from the very start of a definition’s text, after blank lines and // lines.

Annotations (experimental)

@name(expression) before a let attaches view metadata to a definition. Like a doc comment it lives in the definition’s unhashed source text and is never part of the term, so it can never change a hash, and it follows the definition through rename, update, move and sync. Unlike a doc comment its value is ordinary Clay, and a rename rewrites the names inside it. Today only Phaistos reads one, @phaistos, whose record says where the definition’s cell sits in the sheet; dragging a cell writes x and y into it.

let margin = 5

@phaistos({x: margin * 40, y: 20, title: "My table"})
let foo = [1, 2, 5]
Verified: the hash of foo is the same with or without the annotation.