How to Contribute to the Export Functionality in design.md
Contributing to the export functionality involves extending existing emitter handlers or adding new format support by implementing the *EmitterSpec contract in the CLI package under packages/cli.
The export feature in google-labs-code/design.md converts DESIGN.md tokens into various developer-ready formats like Tailwind JSON, CSS custom properties, and W3C Design Tokens. If you want to contribute to the export functionality, you will work primarily within the CLI package architecture that emphasizes side-effect-free, pure functions. This guide explains the exact file locations, handler patterns, and testing requirements for extending export capabilities.
Export Architecture Overview
The export command is deliberately side-effect-free apart from console I/O, making it easy to test and extend. The entry point lives in packages/cli/src/commands/export.ts, where the command uses citty (defineCommand) to declare arguments at lines 15-44. The actual transformation logic resides in dedicated emitter handlers located under packages/cli/src/linter/, each implementing a pure execute(state) method that accepts a DesignSystemState object and returns either {success:true, data:...} or an error object.
The Export Command Flow
Understanding the execution flow helps you identify where to inject new functionality.
Argument Parsing and Validation
When a user runs design export <file> --format=<fmt> [--prefix=<pfx>], the CLI first validates inputs against a closed enum (FORMATS) at lines 49-57 in export.ts. If the supplied --format is not in the allowed list, the command prints a JSON error to stderr and exits with code 1.
Input Processing and Linting
The command calls readInput (lines 59-68) to load the DESIGN.md source or stdin, propagating any FileReadError with exit code 2. The raw content then passes through the lint function (lines 70-71) to produce a DesignSystemState object representing the design tokens.
Handler Dispatch and Output
Depending on the selected format, the command constructs an emitter handler:
TailwindV4EmitterHandler→ CSS@themefor Tailwind v4 (css-tailwind) at lines 72-82TailwindEmitterHandler→ JSON theme extension for Tailwind v3 (json-tailwind/tailwind) at lines 83-94DtcgEmitterHandler→ W3C Design Tokens JSON (dtcg) at lines 94-104CssVarsEmitterHandler→ CSS custom properties (css-vars) with optional prefix at lines 105-115
Each handler's execute method returns data that the command writes to stdout using process.stdout.write for CSS or console.log for JSON. Errors print to stderr as JSON and trigger non-zero exit codes.
Adding a New Export Format
To contribute a new export format, follow these three steps:
-
Register the format – Add your format string to the
FORMATStuple at line 20 inexport.ts. -
Implement the handler – Create a new handler class in
packages/cli/src/linter/<your-format>/handler.tsthat follows the*EmitterSpeccontract. The class must expose anexecute(state)method returning{success:true, data:string}or an error object. -
Wire up dispatch – Add a branch in the
runmethod (around line 72-115) that constructs your handler and writes the result to stdout. -
Write tests – Add unit tests in
packages/cli/src/commands/export.test.tsverifying both successful output and error conditions.
Extending Existing Handlers
You can also contribute by improving current emitters:
-
Tailwind JSON handler (
packages/cli/src/linter/tailwind/handler.tslines 22-36) – Maps colors, font families, font sizes, and dimensions to the Tailwindtheme.extendshape. -
DTCG handler (
packages/cli/src/linter/dtcg/handler.tslines 24-46) – Builds a token file adhering to the Design Tokens 2025.10 schema, converting colors, dimensions, and typography into appropriate DTCG structures. -
CSS-vars handler (
export.tslines 115-116) – Serializes token declarations into a:root { … }block, applying the optional prefix if given.
When extending these, maintain the existing pure function pattern and update the corresponding test file.
Testing Your Changes
The test suite in packages/cli/src/commands/export.test.ts provides the verification framework. Key test patterns include:
- Format validation – Verify that invalid formats trigger JSON errors and exit code 1 (lines 58-70).
- Output verification – For handlers like
css-vars, assert that output starts with:root {and contains prefixed custom properties when the--prefixflag is used (lines 37-55).
Run the full suite with bun test to ensure no regressions before submitting your contribution.
Summary
- The export functionality lives in
packages/cliand uses citty for argument parsing atpackages/cli/src/commands/export.ts. - Four built-in handlers support
css-tailwind,json-tailwind,dtcg, andcss-varsformats, each implementing a pureexecute(state)method. - Adding a new format requires updating the
FORMATStuple, creating a handler class following the*EmitterSpeccontract, and adding dispatch logic. - Extend existing handlers by modifying the specific files under
packages/cli/src/linter/while maintaining strict typing and pure function patterns. - Verify changes using
packages/cli/src/commands/export.test.tsand runbun testbefore submitting.
Frequently Asked Questions
Where is the export command defined?
The export command is defined in packages/cli/src/commands/export.ts using citty's defineCommand function at lines 15-44. This file handles argument parsing, format validation against the FORMATS enum, and dispatch to the appropriate emitter handler.
What interface must new handlers implement?
New handlers must implement the *EmitterSpec contract by exposing an execute(state) method that accepts a DesignSystemState object and returns either {success:true, data:string} for successful exports or an error object. This pattern ensures consistency across all emitters including TailwindV4EmitterHandler, DtcgEmitterHandler, and CssVarsEmitterHandler.
How do I test a new export format locally?
Add tests to packages/cli/src/commands/export.test.ts following the existing patterns. Verify that your format accepts valid input and produces the expected output structure, and confirm that invalid inputs return JSON errors with appropriate exit codes. Run bun test from the CLI package directory to execute the suite.
Which file handles CSS custom property generation?
CSS custom property generation is handled by the CssVarsEmitterHandler in packages/cli/src/linter/css-vars/handler.ts (implementation referenced in export.ts lines 105-115). This handler serializes tokens into a :root block and respects the optional --prefix argument for namespacing variables.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →