How to Automatically Fix Section Ordering Issues with the Fixer Command
The Fixer API automatically reorders DESIGN.md sections to match the canonical specification by parsing the document into discrete sections, separating known and unknown headings, sorting them against the CANONICAL_ORDER array, and reassembling the document with the prelude preserved at the top.
The google-labs-code/design.md project provides a robust toolchain for maintaining consistent documentation structure. When sections appear out of order, the fixer command offers a deterministic way to automatically fix section ordering issues with the fixer command without manual editing. This API wraps the same logic used by the section-order linter rule, ensuring your documentation always matches the canonical specification defined in spec-config.yaml.
How the Fixer API Reorders Sections
The core implementation resides in packages/cli/src/linter/fixer/handler.ts, specifically within the fixSectionOrder function. This handler processes the input through a five-stage pipeline that preserves content while enforcing structural rules.
Input Validation with FixerInputSchema
All requests must conform to the FixerInputSchema defined in packages/cli/src/linter/fixer/spec.ts. The schema requires two properties: content (the original document string) and sections (an array of objects containing heading and content fields). Each section represents a discrete portion of the DESIGN.md file, typically generated by a parser that splits the document at heading boundaries.
Preserving the Prelude
The fixer identifies introductory content by checking for a section with an empty string heading. According to handler.ts at line 21, this "prelude" section is always retained at the very top of the output document. This ensures that frontmatter, free-form text, or introductory paragraphs remain untouched regardless of the reordering logic applied to subsequent sections.
Separating Known and Unknown Sections
The algorithm distinguishes between sections defined in the specification and custom additions. In packages/cli/src/linter/spec-config.ts at line 60, the resolveAlias helper maps section headings to their canonical forms before checking against CANONICAL_ORDER.
Known sections—those appearing in the canonical order list—are queued for sorting. Unknown sections are preserved but appended after all known sections, as implemented in handler.ts lines 28-32. This approach guarantees that proprietary or experimental sections are not deleted during the fixing process.
Sorting and Document Reassembly
The sorter uses the index position within CANONICAL_ORDER to determine the correct sequence, as shown in handler.ts lines 33-36. After sorting, the reassembler concatenates three groups: the prelude (if present), the sorted known sections, and the unsorted unknown sections, each separated by a single newline.
The function returns an object containing fixedContent (the reordered document) and optional details showing the before and after ordering for debugging purposes, implemented in handler.ts lines 51-60.
Practical Implementation Examples
You can invoke the fixer programmatically via the TypeScript API or through the bundled CLI command.
Basic TypeScript Usage
Import fixSectionOrder from packages/cli/src/linter/fixer/handler.ts and provide a valid FixerInput object:
import { fixSectionOrder } from '@design-md/cli/src/linter/fixer/handler.js';
import type { FixerInput } from '@design-md/cli/src/linter/fixer/spec.js';
// Assuming parseDesignMd splits the file into sections
const { sections, rawContent } = parseDesignMd('my-design.md');
const input: FixerInput = {
content: rawContent,
sections,
};
const result = fixSectionOrder(input);
if (result.success) {
console.log('Fixed document:', result.fixedContent);
console.log('Order changed from:', result.details?.beforeOrder);
console.log('Order changed to:', result.details?.afterOrder);
} else {
console.error('Fix failed:', result.error);
}
Using the CLI Command
For command-line workflows, use the design-md fix command:
design-md fix path/to/DESIGN.md --output fixed.md
This command internally parses the file, calls fixSectionOrder, and writes the fixedContent to the specified output path.
Integrating into a Web Service
Expose the functionality via an HTTP endpoint:
import express from 'express';
import { fixSectionOrder } from '@design-md/cli/src/linter/fixer/handler.js';
import type { FixerInput } from '@design-md/cli/src/linter/fixer/spec.js';
const app = express();
app.use(express.json());
app.post('/api/fix-section-order', (req, res) => {
const input: FixerInput = req.body;
const result = fixSectionOrder(input);
res.json(result);
});
app.listen(3000);
Key Source Files
Understanding the fixer requires familiarity with these specific files:
packages/cli/src/linter/fixer/spec.ts– Defines the Zod schemas forFixerInputand result typespackages/cli/src/linter/fixer/handler.ts– Contains thefixSectionOrderimplementation and reordering logicpackages/cli/src/linter/spec-config.ts– DeclaresCANONICAL_ORDERand theresolveAliashelper for canonical heading resolutionpackages/cli/src/linter/linter/rules/section-order.ts– The linter rule that detects violations using the same ordering logic
Summary
- The Fixer API automatically reorders DESIGN.md sections by comparing parsed headings against the
CANONICAL_ORDERarray defined in the specification. - Prelude sections (empty heading) are always preserved at the top of the document.
- Unknown sections are appended after known sections, ensuring no content loss during automated fixing.
- The implementation in
packages/cli/src/linter/fixer/handler.tsprovides deterministic sorting viafixSectionOrder. - You can invoke the fixer via TypeScript API, CLI command, or HTTP service.
Frequently Asked Questions
What happens to sections not defined in the canonical order?
Unknown sections are preserved and appended after all known sections. The fixer does not delete or modify their internal content; it only relocates them to the end of the document to maintain the integrity of custom sections while enforcing the standard structure.
How does the fixer handle section aliases?
The resolveAlias function in packages/cli/src/linter/spec-config.ts expands alternative headings to their canonical forms before checking against CANONICAL_ORDER. This ensures that documents using legacy or alternative section names are correctly sorted according to the current specification.
Can I use the fixer without parsing the document first?
No, the FixerInput requires a pre-parsed sections array. You must split the document into sections with their respective headings and content before calling fixSectionOrder. The CLI command design-md fix handles this parsing automatically.
Does the fixer modify the original file?
When using the API directly, fixSectionOrder returns a new fixedContent string without modifying the input. The CLI command writes to the specified output file (or stdout if no output is specified), leaving the original document unchanged unless you overwrite it with the --output flag pointing to the same path.
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 →