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:

  1. Extract sections from the parsed design system (state.sections)
  2. Normalize headings using resolveAlias to convert aliases to canonical names
  3. Filter to known sections by checking membership in ORDER_MAP (creating knownSections)
  4. Walk pair-wise through adjacent sections in knownSections
  5. 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:

Summary

  • Section order validation enforces canonical heading sequences defined in spec-config.yaml across 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 resolveAlias ensures 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.ts and integrated into the linter through the rule descriptor system in rules/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →