dxn's commands are dxn <command> <file> ..., each working on a file
written in dxn, the language of design and dimensions;
language/guide.md teaches it and lists every
diagnostic code. The usage block below is the same text that
dxn help <command> and dxn <command> --help print, and a test keeps it
in sync.
--dry-runmakesattach,reviewandrenameprint the files they would write, without writing them.-h,--helpprint the overview, or a command's usage when they come after a command.-V,--versionprint{"version": "<version>"}.
check, fmt, states, tree, cases, validate, attach, status, review, rename
Usage: dxn <command> <file> [options]
dxn, the language of design and dimensions, which grows one concept at a
time: see docs/language/guide.md. A .dxn file declares enums, each a named
set of values; dimensions, each listing the values the environment varies
by; types with the dimensions they need, their states, rules for when a
state's value exists, a when for a state the world decides, and the
children they have; environments, each a product of dimensions; profiles,
each an instance of an environment; modifiers, accessories that change
some profiles; records, each a named group of typed fields; and
expectations, rules checked against the tree in place. A # starts a
comment, to the end of the line:
# The wordmark's hover only exists with a mouse.
enum Hover = rest | hovered
dimension Pointer = mouse | touch
type Wordmark needs Pointer {
state hover: Hover
hover = hovered only when Pointer = mouse
}
environment Device = Pointer
profile Laptop: Device { Pointer = mouse }
Commands:
check <file> [--expect <title>] Parse and check a file; say what it declares,
or report every problem it has. Warnings
are printed, but do not fail. With
--expect, run only the expectation with
that title, and say whether it holds
fmt <file>... [--check] Write each file the one way a .dxn file is
written, and name the files changed; with
--check, write nothing, name the files not
written that way, and fail if there are any
states <file> <type> Evaluate a type: the states it has in each
profile, or without profiles under each
combination of the dimensions it needs,
as a Markdown table; or a child in place,
given its path from a type, such as
Toolbar.menu.toggle: where it is inside its
parents, with the states they give it
tree <file> [<type>] Print the declared has tree of a type, or all
containment roots when no type is named.
Keep conditions and lists without evaluating
state combinations; use --json for structure
Use --identifiers to show child names too
cases <file> <type> List the cases a type, or a child in place,
[--combinations] has: those that can be told apart, each
with what it covers where it covers more
than one combination; with --combinations,
every combination, as if nothing were
alike
validate <file> Check the stored records: each record's data is
every JSON file in a folder named after it in
kebab-case, next to the file, each a list of
records with every field given, each of its
type, and no others. Print what it checked, or
every problem with its line, column and path
attach <file> <path> --actor <name> --data <json> <key>=<value>...
Record, as the actor, the record it records,
for each combination the context's keys give
(a|b lists several) that exists in place:
--data gives its fields as JSON, and each
PenNode's fingerprint is taken now, of its
node or else its frame; a stored record for
the same combination, actor and data is
replaced; with --dry-run, say what it would
write
status <file> [--missing] Count, for each record an actor records, the
combinations of every element in the file's
trees, in place, and those a stored record is
about; with --missing, list the others
review <file> [<type>] [--stale] Write, for each tree and each record with a
PenNode, a Markdown page of its combinations,
each with its status and the picture of what
was recorded, pictures/<node>.png beside the
page; pages go in dxn's cache, outside the
repository, and are named as they are
written; with a type, only the trees it is
in; with --stale, only what is stale or
gone, on a page of its own
rename <file> <name> <new> Rename a declaration where the file uses it
and where stored records name it, once both
check: <name> as dxn writes it (Hover,
Hover.rest, Toolbar.layout, Phone, ...;
<kind>:<name> where one name names two), or
<file>:<line>:<column> <new> by its place; a
record's stored records move to the folder of
its new name; with --dry-run, say what it
would write
Options:
--json Print one JSON document, for tools: the result
and any warnings as "problems"; on a failure,
the file and its problems; on a refusal or
a usage error, {"error": "<message>"}, with
any problems found before a refusal
Each command prints a readable answer by default, and one JSON document with --json. Every command prints the usage above with --help.
Says what a file declares, in one line, or prints each problem as <file>:<line>:<column>: <severity>: <code>: <message> and exits 1.
dxn check wordmark.dxn
dxn check wordmark.dxn --jsonWith --expect, it runs only the expectation with that title, written with or
without its quotes, and says it holds, or reports why it fails. The rest of the
file is still checked: an expectation cannot hold in a file with problems.
dxn check toolbar.dxn --expect "Escape closes the menu and returns focus to its button"Writes each file the one way a .dxn file is written, as gofmt does for Go,
and names the files it changed. There are no options: every file reads the
same, and a diff shows a change to the model, not to its spacing.
- Two spaces of indentation for each
{; a line starting with}steps back, and one that goes on with|,andororsteps in one more. - One space between words and around
=,->and|; none before:or,and one after; none around.or+; none inside( … ); one inside{ … }on a line. - Comments kept as written; one after code, two spaces after it.
- At most one blank line in a row, and none at the start of the file, after a
{or before a}; line feeds, and one at the end. - Nothing reordered, joined or split. A file that does not parse is left alone, and its problems are reported.
dxn fmt toolbar.dxn
dxn fmt --check spec/*.dxnWith --check, it writes nothing, names the files that are not written that
way, and exits 1 if there are any: for CI. The editor extensions format a file
the same way when it is saved.
Prints a type's states in each profile or combination as a Markdown table; given a path from a type, a child's states in place.
dxn states wordmark.dxn WordmarkPrints the declared has tree of a type. With no type argument, prints all
containment roots: types not placed by any other type. A shared type expands at
each placement, showing only the type name by default. Use --identifiers to show
identifier: Type labels. Nested types can be selected by
their qualified names, such as Container.Inner; a nested declaration alone is
not a has placement.
Conditions remain visible as only when expressions, and lists as [Type].
JSON retains placement names and paths, including tagged list members. This shows declared structure
without filtering children by state combinations. The source must still pass
normal language checks, including containment-cycle and expectation checks.
dxn tree docs/architecture/dxn-codebase.dxn ModifyDxnGrammar
dxn tree docs/architecture/dxn-codebase.dxn
dxn tree docs/architecture/dxn-codebase.dxn --identifiers
dxn tree docs/architecture/dxn-codebase.dxn ModifyDxnGrammar --jsonWith --json, returns file, trees, and problems. Each tree node has name,
type, path, and children, with list and when when applicable. Text output
separates roots with a blank line; a file with no types prints No types declared.
and has an empty trees array in JSON.
Lists the cases a type or a child in place has, those that can be told apart, with what each covers; with --combinations, every combination.
dxn cases button.dxn ButtonChecks every stored record, the JSON files in a kebab-case folder named after each record, next to the file; a problem in stored data also has its JSON path.
dxn validate evidence.dxnRecords evidence for an element, by its path, in each combination the context's keys give, as an actor: the record that actor records, with the fields --data gives as JSON. Each PenNode field gets its fingerprint now, of its node, or of its frame when it has none; dxn status later tells, by it, whether the design still shows what was recorded.
dxn attach gazette.dxn Button --actor DesignAgent \
--data '{"source": {"file": "gazette.pen", "frame": "IeCCz", "node": "uqEAm"}}' \
style=primary interaction=pressedCounts, for each record an actor records, the combinations of every element in the file's trees and those a stored record is about; --missing lists the others.
Stored records with errors are reported first, then set apart and said after the count, which counts every other stored record, as an editor's hints do; it then fails. A record none of whose stored records can be counted is said instead of a count. --json gives the problems and the counts together.
dxn status toolbar.dxnWrites, for each tree and each record with a PenNode, a Markdown page to review its evidence by: a row for each combination, with its status as dxn status judges it, recorded, stale, gone or missing, and the picture of what was recorded. A stale row shows its drawing as it was when it was recorded, so it can be compared with the design as it is now. The pages go in dxn's cache, outside the repository: ~/Library/Caches/dxn/review/ on macOS, ~/.cache/dxn/review/ elsewhere, then the repository and the path of the record's folder in it. Each picture is pictures/<node>.png beside its page, or pictures/<frame>.png for a PenNode without a node; whoever attaches the evidence exports it there.
With a type, it writes only the pages of the trees the type is in: the one it is the root of, or those a type contains it in. With --stale, each page holds only what is stale or gone, the combinations whose evidence needs a decision, and is written beside the full one as <tree>.stale.md. A record made before its element gained a state or a dimension is outdated: each page lists it apart, with its picture and what it needs, and the --stale page includes it. A tree with nothing stale, gone or outdated gets no such page, and any from before is removed; dxn says so instead: Button: nothing is stale, gone or outdated.
dxn review gazette.dxn
dxn review gazette.dxn Button --staleWrote ~/Library/Caches/dxn/review/task-tree-1a2b3c4d/examples/gazette/pen-evidence/button.md
Renames a declaration everywhere the file uses it, and everywhere stored records name it: in their contexts' paths, profiles, dimensions, parents and states, and in their fields. Renaming a record moves its stored records to the folder named after its new name.
A declaration is named as dxn writes it: an enum, a type, a dimension, a
record, an environment, a profile or a modifier by its name, one declared
inside a type by its full name (Menu.State), a value with its enum or
dimension (Hover.rest, Breakpoint.sm), and a state, an action, an event or
a child with its type (Toolbar.layout). Where one name names two, such as an
event and an action, a kind before it says which (event:Menu.close). A name
can also be given by its place in the file, as an editor does.
dxn rename evidence.dxn Hover.hovered over
dxn rename toolbar.dxn Toolbar.layout arrangement
dxn rename toolbar.dxn:96:9 arrangement
dxn rename toolbar.dxn Evidence ProofA state that is provided is renamed with every state that receives it. The rename is refused, and nothing is written, when the file or the stored records do not check, before the rename or after it. An editor's rename, through the language server, refuses the same.