How Section Order Validation Works in the DESIGN.md Linter
The DESIGN.md linter validates section order by comparing parsed headings against a canonical sequence defined in spec-config.yaml, using pairwise index comparison to detect any sections that appear out of order.
The google-labs-code/design.md linter enforces structured documentation standards by ensuring DESIGN.md files follow a specific section hierarchy. Section order validation is a core rule that checks whether headings appear in the canonical sequence defined by the specification configuration, catching documentation errors before they propagate.
The Three-Stage Validation Pipeline
Section order validation operates through a precise three-step process that maps file content against the specification's canonical structure.
Loading Canonical Order and Aliases
The validation begins in packages/cli/src/linter/spec-config.ts, where the system reads spec-config.yaml and exports three critical components: CANONICAL_ORDER, SECTION_ALIASES, and the resolveAlias function. These exports define the expected sequence of sections and establish mappings for common variations or alternate spellings. The configuration parsing occurs between lines 49-61, creating a centralized source of truth for valid section names.
Building the Order Map
In packages/cli/src/linter/linter/rules/section-order.ts (lines 26-28), the rule constructs a Map called ORDER_MAP that assigns each canonical section name its expected position index. This data structure enables O(1) lookup during validation, converting the canonical order array into a queryable format where each section maps to its integer position.
Pairwise Order Validation
The core validation logic resides in the sectionOrder(state) function (lines 28-56 of section-order.ts). The process follows these steps:
- Extract sections from the parsed design system (
state.sections) - Normalize headings using
resolveAliasto convert aliases to canonical names - Filter to known sections by checking membership in
ORDER_MAP(creatingknownSections) - Walk pair-wise through adjacent sections in
knownSections - Compare indices by checking if the later section has a smaller index than the preceding one in
ORDER_MAP
If the linter detects an inversion—where a section appears before its predecessor in the canonical order—it immediately records a finding with a descriptive message listing the expected order and stops further scanning of that file.
Code Implementation Walkthrough
Running the Validation Programmatically
You can invoke the section order rule directly in TypeScript:
import { loadSpec } from '@design-md/cli';
import { sectionOrder } from '@design-md/cli/src/linter/linter/rules/section-order';
// Parse a DESIGN.md file (returns DesignSystemState)
const state = await loadSpec('path/to/DESIGN.md');
// Run the section-order check
const findings = sectionOrder(state);
if (findings.length) {
console.warn('Section order problems:');
findings.forEach(f => console.warn(f.message));
}
Expected Output Format
When the linter detects a violation, it generates a finding with a clear message:
Section 'Colors' appears before 'Tokens', which is out of order. Expected order: Tokens, Colors, Typography, Components, ...
Configuring Custom Aliases
The validation system recognizes alternate section names through the alias resolution mechanism. To treat Palette as equivalent to Colors, modify your spec-config.yaml:
# spec-config.yaml (excerpt)
sections:
- canonical: Colors
aliases: [Palette, Colour]
The resolveAlias function automatically normalizes these variations during validation, ensuring that ## Palette is evaluated as Colors when checking against the canonical order.
Key Source Files
Understanding section order validation requires familiarity with these specific files in the google-labs-code/design.md repository:
packages/cli/src/linter/spec-config.ts– Loads and validates the specification configuration; exportsCANONICAL_ORDER,SECTION_ALIASES, andresolveAliaspackages/cli/src/linter/linter/rules/section-order.ts– Implements thesectionOrderfunction andsectionOrderRuledescriptorpackages/cli/src/linter/linter/rules/index.ts– Aggregates all rule descriptors for the linter runnerpackages/cli/src/linter/linter/handler.ts– Coordinates rule execution against parsedDesignSystemStateobjectsspec-config.yaml– Source YAML defining canonical sections and their aliases
Summary
- Section order validation enforces canonical heading sequences defined in
spec-config.yamlacross all DESIGN.md files - The system uses a three-stage pipeline: loading configuration, building an order map, and performing pairwise index comparisons
- Alias resolution via
resolveAliasensures flexible heading recognition while maintaining strict ordering requirements - Validation stops at the first violation found, providing immediate feedback with the expected canonical sequence
- The rule is implemented in
section-order.tsand integrated into the linter through the rule descriptor system inrules/index.ts
Frequently Asked Questions
What happens if a section is missing from the DESIGN.md file?
The section order validator only checks the relative ordering of sections that are actually present. Missing sections do not trigger order violations because the validation logic filters headings against ORDER_MAP and only evaluates knownSections. However, other linter rules may flag missing required sections separately.
Can I customize the canonical order for my organization?
Yes. The canonical order is defined in spec-config.yaml and loaded through spec-config.ts. Modifying the sections array in that YAML file changes the expected order globally. You must rebuild or reinstall the linter package after modifying the configuration to ensure the TypeScript exports reflect your changes.
How does the linter handle unknown or custom sections?
The sectionOrder function filters the parsed sections against ORDER_MAP before validation. Any headings not defined in the canonical order or aliases are excluded from knownSections and do not participate in order validation. This allows documents to contain custom sections without triggering false positives, provided those sections do not interfere with the ordering of canonical sections.
Where is the section order rule registered in the linter?
The sectionOrderRule descriptor is exported from packages/cli/src/linter/linter/rules/section-order.ts and aggregated in packages/cli/src/linter/linter/rules/index.ts. The linter runner (handler.ts) loads all rule descriptors from this index and executes them against the parsed DesignSystemState when users run design-md lint <file>.
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 →