How to Use the Programmatic API to Lint DESIGN.md Files
The @google/design.md package exports a lint function that parses DESIGN.md content, resolves design tokens into a typed model, runs configurable validation rules, and returns a structured LintReport containing findings, severity counts, and a Tailwind-compatible configuration.
The google-labs-code/design.md repository provides a self-contained linting engine for design system documentation. While the CLI handles file system operations, the programmatic API allows you to integrate DESIGN.md validation directly into CI pipelines, custom tooling, or editor extensions. This guide covers the core lint function and its supporting handlers as implemented in the TypeScript source.
Importing the Linter Entry Point
The public API surface is exposed through the package's linter entry point. Import the lint function and associated types from @google/design.md/linter to begin processing DESIGN.md content programmatically.
import { lint, type LintReport, type LintOptions } from '@google/design.md/linter';
import { readFileSync } from 'node:fs';
The main entry file at packages/cli/src/linter/index.ts re-exports the core implementation from packages/cli/src/linter/lint.ts along with type definitions and rule helpers.
Understanding the Linting Pipeline
When you invoke lint(content, options?), the function executes a five-stage pipeline defined in packages/cli/src/linter/lint.ts:
- Parsing –
ParserHandlerreads the raw Markdown, extracts YAML front-matter (if present), and constructs aParsedDesignSystemstructure. - Model resolution –
ModelHandlerresolves token references, normalizes colors, dimensions, and typography into a fully typedDesignSystemState. - Rule execution –
runLinterapplies theDEFAULT_RULESset or any customLintRules supplied in options, aggregating findings and severity counts. - Tailwind emission –
TailwindEmitterHandlergenerates a Tailwind-compatible theme configuration from the resolved design system. - Report assembly – Results are packaged into a
LintReportcontaining findings, the model, Tailwind config, and a section map.
The function gracefully handles documents missing YAML front-matter by falling back to a simple heading scan (extractSectionsFromContent) and returning a warning-level finding rather than throwing an exception.
Basic Linting Example
Load your DESIGN.md content and call lint to receive a complete validation report.
// Load raw markdown content
const designMd = readFileSync('examples/totality-festival/DESIGN.md', 'utf8');
// Run the linter with default options
const report: LintReport = lint(designMd);
// Inspect results
console.log('Resolved tokens:', report.designSystem.tokens?.length ?? 0);
console.log('Findings:', report.findings.length);
report.findings.forEach(f => {
console.log(`[${f.severity.toUpperCase()}] ${f.message}`);
});
// Access generated Tailwind configuration
console.log('Tailwind config:', JSON.stringify(report.tailwindConfig, null, 2));
Customizing Validation Rules
Pass a LintOptions object to override the default rule set. Import DEFAULT_RULES and individual rules like brokenRef from packages/cli/src/linter/rules/index.ts to compose custom validation logic.
import { DEFAULT_RULES, brokenRef } from '@google/design.md/linter';
const customOptions: LintOptions = {
rules: [
...DEFAULT_RULES,
// Add custom validation for broken references
brokenRef,
],
};
const report = lint(designMd, customOptions);
Advanced Programmatic Workflows
Beyond basic linting, the API exposes handlers for additional processing.
- Programmatic fixing – Import
fixSectionOrderfrompackages/cli/src/fixer/handler.tsto reorder sections after linting. - DTCG export – Use
DtcgEmitterHandler(defined inpackages/cli/src/dtcg/handler.ts) to serialize the resolved design system to a token file format compatible with downstream tooling.
Key Types and Source Files
Reference these core types when building integrations.
| Type | Description | Source Location |
|---|---|---|
LintReport |
Complete result including findings, design system, and Tailwind config | packages/cli/src/linter/lint.ts |
LintOptions |
Configuration interface accepting custom rule arrays | packages/cli/src/linter/lint.ts |
Finding |
Individual issue with severity level and message | packages/cli/src/linter/spec.ts |
DesignSystemState |
Fully resolved design tokens model | packages/cli/src/model/spec.ts |
The rule execution logic resides in packages/cli/src/linter/runner.ts, while the Tailwind configuration emitter is implemented in packages/cli/src/tailwind/handler.ts.
Summary
- Import the
lintfunction from@google/design.md/linterto validate DESIGN.md content programmatically. - The pipeline parses Markdown, resolves tokens via
ModelHandler, executes rules viarunLinter, and generates Tailwind config viaTailwindEmitterHandler. - The function handles missing YAML front-matter gracefully by falling back to heading extraction with a warning.
- Customize validation by passing custom rules through the
LintOptionsinterface. - Access auxiliary handlers like
fixSectionOrderandDtcgEmitterHandlerfor fixing and exporting operations.
Frequently Asked Questions
What happens if my DESIGN.md file lacks YAML front matter?
The lint function detects missing front-matter and automatically falls back to extractSectionsFromContent for basic heading analysis. It returns a warning-level finding in the report rather than throwing an error, allowing the linting process to continue with reduced metadata extraction.
How do I add custom lint rules to the programmatic API?
Construct a LintOptions object with a rules array containing your custom LintRule implementations. Import the DEFAULT_RULES array from packages/cli/src/linter/rules/index.ts and spread it into your custom array alongside additional rules like brokenRef to extend or replace the default validation behavior.
Can I export the linted design system to other formats?
Yes. After linting, use the DtcgEmitterHandler (located in packages/cli/src/dtcg/handler.ts) to serialize the DesignSystemState into a DTCG (Design Tokens Community Group) compatible token file format for integration with other design tools and pipelines.
Where is the lint function defined in the source code?
The lint function is implemented in packages/cli/src/linter/lint.ts and re-exported as the public API entry point in packages/cli/src/linter/index.ts. The function orchestrates the parsing, modeling, and rule execution phases while delegating specific tasks to specialized handlers like ParserHandler and ModelHandler.
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 →