UX-DSL
XS0px

CLI

What the uxdsl command prints — captured, not transcribed.
Every panel is the real stdout, stderr and exit status of the CLI in this repository, run against the small project below.

The project these commands run in

A build config made with defineConfig from postcss-uxdsl/config, a theme file that points $schema at the packaged postcss-uxdsl/schema/theme.schema.json (so an editor validates and completes it) and overrides only palette.primary.main, and three sources. scripts/capture-capabilities.js runs each command below and stores what it printed; npm test runs it again with --check, so this page cannot keep showing output the CLI no longer produces. Absolute paths are shown as <project>.

uxdsl.config.cjs
// The build config of the small project whose real CLI output the playground's /docs/cli
// page shows (captured by scripts/capture-capabilities.js). `defineConfig` is the typed
// helper from `postcss-uxdsl/config`. The theme is not named here: `uxdsl build` discovers
// `uxdsl.theme.json` next to this file.
const path = require('path');
const { defineConfig } = require('postcss-uxdsl/config');

module.exports = defineConfig({
  entry: path.join(__dirname, 'src/main.uxdsl'),
  outFile: path.join(__dirname, 'dist/app.css'),
});
uxdsl.theme.json
{
  "$schema": "../../node_modules/postcss-uxdsl/schema/theme.schema.json",
  "breakpoints": { "xs": 0, "sm": 480, "md": 768, "lg": 1024, "xl": 1280 },
  "palette": {
    "primary": { "main": "#0f766e" }
  }
}
src/card.uxdsl
.card {
  @ds-surface(contained);
  display: flex;
  flex-direction: xs(column) md(row);
  gap: density(4);
}
src/button.uxdsl
.save {
  @ds-button(contained primary 2);
}
src/legacy.uxdsl
/* Left out of the entry with --exclude: an old stylesheet nothing imports any more. */
.old-banner {
  color: palette(primary-main);
}

uxdsl generate-entry: --src, --out, --exclude

Rewrites the entry's @import list from every .uxdsl file under --src; --exclude leaves files out by name.

Write the entry from what is in src/, leaving one file out exit 0
$ uxdsl generate-entry --src src --out src/main.uxdsl --exclude legacy.uxdsl
[uxdsl] Scanning src for .uxdsl files...
[uxdsl] Generated entry file at src/main.uxdsl with 2 imports.

It wrote src/main.uxdsl:

/* AUTO-GENERATED FILE - DO NOT EDIT MANUALLY */
/* Generated by uxdsl generate-entry */

/* --- Application & Component Imports --- */
@import './button.uxdsl';
@import './card.uxdsl';

uxdsl build: discovery, --config, --entry

With no flags, uxdsl build finds uxdsl.config.cjs in the current directory and the theme file next to it. --config names the config file; --entry with --out compiles one file to one output instead of the config's entry.

Build with the discovered config (uxdsl.config.cjs + uxdsl.theme.json) exit 0
$ uxdsl build
[uxdsl] Theme config detected
[uxdsl] built dist/app.css (52381 bytes)
bytes
52381
rootBlocks
17
mediaQueries
9
The same build with the config named explicitly exit 0
$ uxdsl build --config uxdsl.config.cjs
[uxdsl] Theme config detected
[uxdsl] unchanged dist/app.css (compiled output identical to the file on disk; not rewritten)
Compile one file to one output, bypassing the config's entry exit 0
$ uxdsl build --entry src/card.uxdsl --out dist/card.css
[uxdsl] Theme config detected
[uxdsl] built dist/card.css (51359 bytes)
bytes
51359
rootBlocks
17

--include-theme and --no-include-theme

--include-theme is the default: the entry also defines every token in :root, once. A second entry — a component or CSS-Module stylesheet — passes --no-include-theme to emit only its rules, consuming the tokens the first entry already defined. The same card.uxdsl, both ways:

With --include-theme (the default): the entry also defines every token in :root exit 0
$ uxdsl build --entry src/card.uxdsl --out dist/card-with-theme.css --include-theme
[uxdsl] Theme config detected
[uxdsl] built dist/card-with-theme.css (51359 bytes)
bytes
51359
rootBlocks
17
With --no-include-theme: only the component rules, consuming tokens another entry defines exit 0
$ uxdsl build --entry src/card.uxdsl --out dist/card-only.css --no-include-theme
[uxdsl] built dist/card-only.css (466 bytes)

It wrote dist/card-only.css:

.card {
  padding: var(--uxdsl__surface__contained-padding);
  border-radius: var(--uxdsl__surface__contained-radius);
  background: var(--uxdsl__surface__contained-bg);
  color: var(--uxdsl__surface__contained-color);
  border: var(--uxdsl__surface__contained-border);
  box-shadow: var(--uxdsl__surface__contained-shadow);
  display: flex;
  flex-direction: column;
  gap: var(--uxdsl__density__4);
}@media (min-width: 768px) {.card {
    flex-direction: row;
}
}
bytes
466
rootBlocks
0

--sourcemap

Writes <outFile>.map next to the CSS and a sourceMappingURL comment, so devtools point at the .uxdsl line that produced a rule. --sourcemap=inline embeds the map instead.

With --sourcemap: a .map next to the CSS, pointing devtools at the .uxdsl source exit 0
$ uxdsl build --entry src/card.uxdsl --out dist/card-mapped.css --no-include-theme --sourcemap
[uxdsl] built dist/card-mapped.css (510 bytes) + card-mapped.css.map (408 bytes)

It wrote dist/card-mapped.css:

.card {
  padding: var(--uxdsl__surface__contained-padding);
  border-radius: var(--uxdsl__surface__contained-radius);
  background: var(--uxdsl__surface__contained-bg);
  color: var(--uxdsl__surface__contained-color);
  border: var(--uxdsl__surface__contained-border);
  box-shadow: var(--uxdsl__surface__contained-shadow);
  display: flex;
  flex-direction: column;
  gap: var(--uxdsl__density__4);
}@media (min-width: 768px) {.card {
    flex-direction: row;
}
}

/*# sourceMappingURL=card-mapped.css.map */
mapSources
["../src/card.uxdsl","<no source>"]
mapFile
card-mapped.css
sourceMappingURL
card-mapped.css.map

--strict-theme

Fails the build, before writing anything, when a family you declared was partly filled from the base theme. This project overrides only palette.primary.main, so the bare flag fails; scoped to the families that must be complete (--strict-theme=breakpoints) it passes.

With --strict-theme: fail when a family you declared was partly filled from the base exit 1
$ uxdsl build --strict-theme
[uxdsl] Error: --strict-theme: the following theme families you declared are partially filled from defaults: palette. Provide every key of these families explicitly, or drop --strict-theme/strictTheme if inheriting some of them is intentional.
--strict-theme scoped to the families that must be complete exit 0
$ uxdsl build --strict-theme=breakpoints
[uxdsl] Theme config detected
[uxdsl] unchanged dist/app.css (compiled output identical to the file on disk; not rewritten)

uxdsl theme: --diff, --strict, --contrast

uxdsl theme prints the effective theme — the same discovery and resolution as build, no CSS written. --diff prints only what your theme file mentions, one row per leaf labeled project or default, and says on stderr where a family mixes the two. --strict exits non-zero when a declared family was partly inherited. --contrast runs the WCAG gate and prints its full JSON report; the Contrast page runs the same function in your browser.

Print the effective theme: the base with this project's override merged over it exit 0
$ uxdsl theme

stdout is a JSON document of 13233 bytes; an excerpt:

{
  "palette": {
    "primary": {
      "main": "#0f766e",
      "light": "#a855f7",
      "dark": "#581c87",
      "contrast": "#ffffff"
    }
  }
}
Only what this project mentions, each leaf labeled project or default exit 0
$ uxdsl theme --diff
[uxdsl] palette.primary mixes your values (main) with base values (light, dark, contrast)

stdout is a JSON document; an excerpt:

[
  {
    "path": "palette.primary.main",
    "value": "#0f766e",
    "source": "project"
  },
  {
    "path": "palette.primary.light",
    "value": "#a855f7",
    "source": "default"
  },
  {
    "path": "palette.primary.dark",
    "value": "#581c87",
    "source": "default"
  },
  {
    "path": "palette.primary.contrast",
    "value": "#ffffff",
    "source": "default"
  }
]
Fail when a declared family is partly inherited exit 1
$ uxdsl theme --strict
[uxdsl] Error: --strict: the following theme families you declared are partially filled from defaults: palette. Provide every key of these families explicitly, or drop --strict if inheriting some of them is intentional.
stdoutIsTheJson
true
--strict scoped to breakpoints, which this project declares completely exit 0
$ uxdsl theme --strict=breakpoints
Check every text and border pair of the effective theme against WCAG exit 1
$ uxdsl theme --contrast
[uxdsl] Error: --contrast: 123 contrast pairs fail WCAG for this theme. The JSON report on stdout lists each one with its mode, component, state, breakpoint and resolved colors.

stdout is a JSON document of 289550 bytes; an excerpt:

[
  {
    "mode": "light",
    "family": "surface",
    "component": "outlined",
    "tone": "surface",
    "state": "base",
    "pair": "text",
    "background": "own-bg-or-ambient",
    "breakpoint": 0,
    "required": 4.5,
    "ratio": 1,
    "reason": "1.00:1 < 4.5:1"
  },
  {
    "mode": "light",
    "family": "surface",
    "component": "outlined",
    "tone": "surface",
    "state": "base",
    "pair": "border",
    "background": "ambient",
    "breakpoint": 0,
    "required": 3,
    "ratio": 1,
    "reason": "1.00:1 < 3:1"
  }
]

uxdsl watch

uxdsl watch builds, then rebuilds when a source changes. A broken edit is reported and the last good CSS stays on disk; the next valid save recovers. A session, recorded by the capture script as it edited the file:

  1. start: uxdsl watch

    [uxdsl] Theme config detected
    [uxdsl] built dist/app.css (52381 bytes)
    [uxdsl] watching for changes...
    
  2. edit src/card.uxdsl: add border-radius: rounded(3);

    [uxdsl] change src/card.uxdsl
    [uxdsl] Theme config detected
    [uxdsl] built dist/app.css (52423 bytes)
    
  3. edit src/card.uxdsl: add xxl(2rem), a breakpoint that is not configured

    [uxdsl] change src/card.uxdsl
    [uxdsl] Theme config detected
    [uxdsl] build failed: postcss-uxdsl: src/card.uxdsl:5:3: UXD_BREAKPOINT_UNKNOWN: xxl(...) is not a configured breakpoint or a known CSS function; configured breakpoints: xs, sm, md, lg, xl.
    
  4. undo the edit

    [uxdsl] change src/card.uxdsl
    [uxdsl] Theme config detected
    [uxdsl] built dist/app.css (52381 bytes)