Skip to content

CLI

The mirror CLI, its commands, and their arguments.

View source View as Markdown

The CLI is the tool behind the other three deliverables: it scaffolds the config, compiles the token set, generates the utility stylesheet, writes the Figma export, and describes the result in one document. It reads one config file, writes everything into one directory, and keeps no other state.

Terminal
pnpm mirror <command>
CommandDescription
initWrites a starting mirror.config.ts into the current directory, and a token tree beside it if you ask for one.
tokensFetches the token source and compiles it into .maas/tokens/, and copies the typography file in beside it for the Figma export.
cssGenerates the utility stylesheet from the compiled tokens.
figmaWrites one DTCG file per collection mode and a styles payload into .maas/figma/, read from the compiled tokens alone.
dsdsWrites one YAML document describing the system, its themes and breakpoints, and its components into mirror.dsds.yaml.

Nothing here prompts and nothing here writes state of its own. Both build commands read mirror.config.ts from the directory they run in, and stop with an error naming that directory if there is none.

mirror init

Terminal
pnpm mirror init

This writes a mirror.config.ts that extends ours, which is the smallest config that runs.

import { extendMirrorConfig } from '@maas/mirror'

export default extendMirrorConfig({
  source: { type: 'git', repo: 'magicasaservice/mirror-tokens' },
})

The file is yours from there on, so a second run leaves an existing one alone and says so. Pass --force to overwrite it.

Starting from your own tokens

The config above downloads the token repository on every build. To edit the tokens, run mirror init --tokens: it copies the token tree into ./tokens and writes a mirror.config.ts whose source reads that directory.

Terminal
pnpm mirror init --tokens
import { extendMirrorConfig } from '@maas/mirror'

export default extendMirrorConfig({
  source: { type: 'local', path: './tokens' },
})

Check ./tokens in with the rest of the project. Every machine and every CI runner then resolves the same relative path, and mirror tokens compiles the files on disk rather than fetching a ref somebody else can move.

ArgumentType
--tokens
boolean
--from
string
--dir
string
--force
boolean

Pass --from to copy a repository of your own rather than ours, and --dir to land the tree somewhere other than ./tokens.

Terminal
pnpm mirror init --tokens \
  --from github:acme/design-tokens/packages/tokens#v3 \
  --dir ./design/tokens

That copies packages/tokens out of acme/design-tokens at v3 into design/tokens, and the config it writes reads ./design/tokens. Nothing records where the tree came from; from here on it lives in your own repository.

Both writes refuse without --force, and both are checked before the download starts, so a run that cannot finish downloads nothing. An empty token directory counts as absent; a directory holding anything at all is yours and is left alone.

mirror tokens

Terminal
pnpm mirror tokens

This compiles the token source into .maas/tokens/, one directory per platform. A Git source is downloaded into <dist>/.temp first and removed again once the build is through, and a local source is read where it lies.

If the token source holds a typography file (figma/type.json, unless figma.typography names another path), the run copies it verbatim into <dist>/tokens/figma/type.json, so mirror figma can resolve text styles from dist alone.

Which platforms build and where the tokens come from are both mirror.config.ts decisions. See Configuration.

mirror css

Terminal
pnpm mirror css

This reads the compiled tokens and writes .maas/tailwind.preset.css, steered by two keys under utilities.

utilities.variables decides which compiled tree is read, and defaults to true. Left on, the generator reads application.variables.js, whose leaves are var(--app-*) strings, so the emitted utilities point at custom properties. Turned off, it reads application.js, whose leaves are resolved colors, and the utilities end up with literals.

We recommend leaving it on, since utilities that point at custom properties are what makes cascade theming work at all. A literal cannot be overridden by loading another file, so a preset built with it off ignores every theme override, dark mode included, and the generator prints a warning to that effect on every run.

utilities.targets names the compiled targets the generator reads, in precedence order, and defaults to ['application'].

utilities: {
  variables: true,
  targets: ['application'],
}

mirror figma

Terminal
pnpm mirror figma

This reads the compiled json tree and writes the Figma export into .maas/figma/: one DTCG file per collection mode, ready for Figma’s own variable import, plus a styles.json payload carrying the text and effect styles. The collections and their modes are the ones figma.collections in mirror.config.ts declares. Our stock config carries that key, so a config built with extendMirrorConfig has it already. Without it the command stops, and the error prints a roster read off your targets, ready to paste.

The command reads dist and nothing else, so the export regenerates without refetching the token source. It needs the json platform in options.platforms, and stops with an error naming the key without it.

mirror dsds

Terminal
pnpm mirror dsds --content apps/docs/content

This writes one YAML document describing the system, in the Design System Documentation Specification (DSDS) format, so a tool or a model that reads DSDS reads Mirror without a parser of its own. The document holds the system itself, read from the root package.json; one theme per configured target and one breakpoint per breakpoint/ target, read from mirror.config.ts; and one component per docs page whose frontmatter carries component.

A component entry is read from its page and nothing else: the title and description, the anatomy, the data attributes, the CSS variables, the errors and the usage guidelines. Without --content the document carries the system, theme and breakpoint entries only, which is what a project with its own targets and no component pages gets.

ArgumentType
--content
string
--components
string
--out
string

Every path in the document is relative to the directory it is written to, so the file validates where it lies. The command prints the file it wrote and a warning for a page that carries component but no title or description, for an alternative or a partOf naming a page that does not exist, and for a checks path that does not exist. A warning never stops the write.

The docs site regenerates the document on every build and serves it at /mirror.dsds.yaml.

Arguments

The build commands take the same two.

ArgumentType
--cwd
string
--source
string

A Git source is written as a provider prefix and a repository, optionally followed by a directory inside it and by # and a ref.

ValueReads as
github:magicasaservice/mirror-tokensThe main branch, tokens in tokens/
gitlab:acme/tokens#nextThe next branch on GitLab
github:acme/design/packages/tokens#v2The v2 ref, tokens in packages/tokens/
./tokens, ../design-tokens/tokensA local directory

Anything starting with one of github, gitlab, bitbucket or sourcehut followed by a colon is a repository, anything else is a path, and an unrecognized prefix is an error rather than a path, so a typo is reported instead of being treated as a directory name.

Only the source is overridable from outside. Targets, platforms, dist and utilities describe what your project builds rather than which checkout builds it, so they stay in the file where they can be reviewed.

Further reading