# How to Contribute to the Export Functionality in design.md

> Learn how to contribute to the export functionality in design.md by extending emitter handlers or adding new formats within the CLI package. Enhance the design.md export features today.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-07-02

---

**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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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 `@theme` for Tailwind v4 (`css-tailwind`) at lines 72-82
- **`TailwindEmitterHandler`** → JSON theme extension for Tailwind v3 (`json-tailwind`/`tailwind`) at lines 83-94
- **`DtcgEmitterHandler`** → W3C Design Tokens JSON (`dtcg`) at lines 94-104
- **`CssVarsEmitterHandler`** → 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:

1. **Register the format** – Add your format string to the `FORMATS` tuple at line 20 in [`export.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts).

2. **Implement the handler** – Create a new handler class in `packages/cli/src/linter/<your-format>/handler.ts` that follows the `*EmitterSpec` contract. The class must expose an `execute(state)` method returning `{success:true, data:string}` or an error object.

3. **Wire up dispatch** – Add a branch in the `run` method (around line 72-115) that constructs your handler and writes the result to stdout.

4. **Write tests** – Add unit tests in [`packages/cli/src/commands/export.test.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.test.ts) verifying 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.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/tailwind/handler.ts) lines 22-36) – Maps colors, font families, font sizes, and dimensions to the Tailwind `theme.extend` shape.

- **DTCG handler** ([`packages/cli/src/linter/dtcg/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/dtcg/handler.ts) lines 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.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts) lines 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`](https://github.com/google-labs-code/design.md/blob/main/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 `--prefix` flag 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/cli` and uses **citty** for argument parsing at [`packages/cli/src/commands/export.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.ts).
- Four built-in handlers support `css-tailwind`, `json-tailwind`, `dtcg`, and `css-vars` formats, each implementing a pure `execute(state)` method.
- Adding a new format requires updating the `FORMATS` tuple, creating a handler class following the `*EmitterSpec` contract, 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.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.test.ts) and run `bun test` before submitting.

## Frequently Asked Questions

### Where is the export command defined?

The export command is defined in [`packages/cli/src/commands/export.ts`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/css-vars/handler.ts) (implementation referenced in [`export.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts) lines 105-115). This handler serializes tokens into a `:root` block and respects the optional `--prefix` argument for namespacing variables.