How the `diff` Command Detects Regressions in DESIGN.md Files
The diff command detects regressions by comparing lint summary statistics between two versions of a DESIGN.md file, flagging a regression only when the after version contains more errors or warnings than the before version.
The diff command in the google-labs-code/design.md repository serves as an automated gatekeeper for design system changes. Unlike traditional diff tools that only compare text, this command parses both files into design system maps and evaluates whether modifications introduced new validation failures. Understanding how it detects regressions requires examining its four-stage pipeline implemented across the CLI utilities.
The Regression Detection Pipeline
The command orchestrates file reading, linting, token comparison, and summary analysis to determine regression status. Each stage relies on specific utility functions defined in the source code.
Reading Input Files with readInput
The process begins in packages/cli/src/commands/diff.ts by loading both versions of the design file. The readInput function (defined in packages/cli/src/utils.ts) handles file paths or stdin (indicated by -) and returns the raw content without throwing parsing errors.
const before = await readInput(beforePath);
const after = await readInput(afterPath);
This utility ensures the command can compare local files against previous versions or piped content from version control systems.
Linting Both Versions
Both file contents pass through the lint function exported from packages/cli/src/linter/index.ts. This function parses the markdown, validates tokens, and returns a LintReport object containing two critical properties:
designSystem– Parsed token maps for colors, typography, spacing, rounded corners, and componentssummary– Counts oferrors,warnings, andinfosfound during validation
const beforeReport = lint(beforeContent);
const afterReport = lint(afterContent);
The linting step establishes the baseline and comparison metrics for regression detection.
Diffing Token Maps with diffMaps
While token changes are tracked for reporting purposes, they do not directly trigger regression flags. The diffMaps function (lines 58-84 in packages/cli/src/utils.ts) compares the designSystem maps from both reports and categorizes changes into three arrays:
added– Keys present only in the after mapremoved– Keys present only in the before mapmodified– Keys present in both but with different JSON-stringified values
The command calls diffMaps for each token category:
tokens: {
colors: diffMaps(beforeReport.designSystem.colors, afterReport.designSystem.colors),
typography: diffMaps(beforeReport.designSystem.typography, afterReport.designSystem.typography),
rounded: diffMaps(beforeReport.designSystem.rounded, afterReport.designSystem.rounded),
spacing: diffMaps(beforeReport.designSystem.spacing, afterReport.designSystem.spacing),
components: diffMaps(
serializeComponents(beforeReport.designSystem.components),
serializeComponents(afterReport.designSystem.components)
)
}
For components, serializeComponents converts the nested Map<string, ComponentDef> structure into a plain object to enable structural comparison.
Determining Regression Status
The actual regression detection occurs by comparing the summary objects from both lint reports. As implemented in packages/cli/src/commands/diff.ts (lines 68-70), a regression is defined strictly by an increase in lint findings:
regression: afterReport.summary.errors > beforeReport.summary.errors
|| afterReport.summary.warnings > beforeReport.summary.warnings,
The command calculates the delta between versions and sets the process exit code accordingly:
process.exitCode = diff.regression ? 1 : 0;
If the after file contains more errors or warnings than the before file, the command exits with status 1, signaling a regression. Otherwise, it exits with 0.
Practical Usage Examples
Command Line Interface
Invoke the diff command to compare two design files directly:
npx @google/design.md diff DESIGN.md DESIGN-v2.md
The command outputs a JSON structure showing token changes and findings:
{
"tokens": {
"colors": { "added": [], "removed": [], "modified": ["tertiary"] },
"components": { "added": [], "removed": [], "modified": [] }
},
"findings": {
"before": { "errors": 0, "warnings": 1, "infos": 1 },
"after": { "errors": 1, "warnings": 2, "infos": 1 },
"delta": { "errors": 1, "warnings": 1 }
},
"regression": true
}
Because the after state introduced additional errors and warnings, the regression flag is true and the process exits with code 1.
Programmatic Integration
You can replicate the regression logic in Node.js or TypeScript applications:
import { readInput } from '@google/design.md/cli/src/utils.js';
import { lint } from '@google/design.md/cli/src/linter/index.js';
import { diffMaps } from '@google/design.md/cli/src/utils.js';
async function diffDesigns(beforePath: string, afterPath: string) {
const before = await readInput(beforePath);
const after = await readInput(afterPath);
const beforeReport = lint(before);
const afterReport = lint(after);
const diff = {
tokens: {
colors: diffMaps(beforeReport.designSystem.colors, afterReport.designSystem.colors),
typography: diffMaps(beforeReport.designSystem.typography, afterReport.designSystem.typography),
spacing: diffMaps(beforeReport.designSystem.spacing, afterReport.designSystem.spacing),
},
regression:
afterReport.summary.errors > beforeReport.summary.errors ||
afterReport.summary.warnings > beforeReport.summary.warnings,
};
console.log(diff);
process.exitCode = diff.regression ? 1 : 0;
}
This implementation mirrors the CLI behavior, enabling custom CI/CD integrations or automated design system monitoring.
Key Source Files
Understanding the regression detection mechanism requires familiarity with these specific files in the google-labs-code/design.md repository:
packages/cli/src/commands/diff.ts– Orchestrates the entire pipeline, including the regression logic at lines 68-70 that compares error and warning counts.packages/cli/src/utils.ts– ContainsreadInputanddiffMaps(lines 58-84), which classify token changes into added, removed, or modified categories.packages/cli/src/linter/index.ts– Re-exports thelintfunction that produces theLintReportand summary statistics.packages/cli/src/linter/lint.ts– Implements the parsing and rule evaluation that populatessummary.errorsandsummary.warnings.packages/cli/src/linter/rules/*– Individual lint rules (such asbroken-refandcontrast-ratio) whose counts drive the regression detection algorithm.
Summary
- The
diffcommand detects regressions by comparing lint summary counts, not token semantic changes, between two DESIGN.md versions. - Regression definition: A regression occurs when the after version has more
errorsorwarningsthan the before version, as implemented inpackages/cli/src/commands/diff.ts. - The command uses
readInputto load files anddiffMapsto categorize token modifications, but these serve reporting rather than regression detection. - Exit codes indicate status:
1for regression detected,0for no regression. - The
lintfunction generates the summary statistics that ultimately determine whether a design change constitutes a regression.
Frequently Asked Questions
Does the diff command consider token changes as regressions?
No. The diff command does not flag semantic changes to design tokens (such as color value modifications or new component definitions) as regressions. According to the source code in packages/cli/src/commands/diff.ts, regressions are determined solely by comparing lint summary counts. Token diffs generated by diffMaps are provided for human review but do not influence the regression boolean or exit code.
What exit codes does the diff command return?
The command returns exit code 1 when a regression is detected (meaning the after file has more errors or warnings than the before file), and exit code 0 when no regression is found. This behavior, implemented via process.exitCode = diff.regression ? 1 : 0, makes the command suitable for CI/CD pipelines where non-zero exit codes fail builds automatically.
How does diffMaps determine if a token was modified?
The diffMaps function in packages/cli/src/utils.ts (lines 58-84) determines modifications by comparing JSON-stringified values of keys present in both the before and after maps. If JSON.stringify(beforeValue) !== JSON.stringify(afterValue), the key is classified as modified rather than added or removed. This approach handles complex nested objects and ensures structural equality checks.
Can the diff command compare files from stdin?
Yes. The readInput utility in packages/cli/src/utils.ts accepts - as a file path indicator, allowing the command to read from stdin. This enables piping scenarios such as git show HEAD:DESIGN.md | npx @google/design.md diff DESIGN.md - to compare the current working file against the previous Git version.
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 →