---
module: parser
version: 1
status: stable
files:
- src/parser.rs
db_tables: []
depends_on:
- specs/types/types.spec.md
---
# Parser
## Purpose
Parses spec markdown files — extracts YAML frontmatter into structured data, extracts backtick-quoted symbol names from Public API tables, and checks for required markdown sections. Uses zero-dependency YAML parsing (regex-based, no YAML library).
## Public API
### Exported Structs
| `ParsedSpec` | Parsed spec file containing `frontmatter: Frontmatter` and `body: String` |
### Exported Functions
| `parse_frontmatter` | `content: &str` | `Option<ParsedSpec>` | Parse YAML frontmatter delimited by `---` from a spec file |
| `get_spec_symbols` | `body: &str` | `Vec<String>` | Extract backtick-quoted symbol names from the `## Public API` section tables |
| `get_missing_sections` | `body: &str, required_sections: &[String]` | `Vec<String>` | Check which required `##` sections are missing from the spec body |
## Invariants
1. `parse_frontmatter` returns `None` if the content does not start with `---\n...\n---\n`
2. `get_spec_symbols` only extracts the first backtick-quoted word per table row (`` `symbol` ``)
3. `get_spec_symbols` only extracts from `### Exported ...` subsections (allowlist) and top-level tables; skips non-export subsections (e.g., `### API Endpoints`, `### Route Handlers`, `### Configuration`) and `####` method/constructor/properties sub-tables
4. Symbols are deduplicated while preserving order
5. `get_missing_sections` uses regex matching for `## SectionName` headings — case-sensitive
6. Frontmatter parsing handles both scalar fields (module, version, status) and list fields (files, db_tables, depends_on)
7. Empty list syntax `[]` is handled correctly, producing an empty Vec
## Behavioral Examples
### Scenario: Parse valid frontmatter
- **Given** a spec file with `---\nmodule: auth\nversion: 1\nstatus: stable\nfiles:\n - src/auth.ts\n---\n`
- **When** `parse_frontmatter(content)` is called
- **Then** returns `Some(ParsedSpec)` with module="auth", version="1", files=["src/auth.ts"]
### Scenario: No frontmatter delimiters
- **Given** a plain markdown file without `---` delimiters
- **When** `parse_frontmatter(content)` is called
- **Then** returns `None`
### Scenario: Extract symbols from Public API
| No frontmatter delimiters | `parse_frontmatter` returns `None` |
| Malformed YAML in frontmatter | Unknown keys silently ignored, missing fields remain as `None` |
| No `## Public API` section | `get_spec_symbols` returns empty vector |
| Empty body | `get_missing_sections` reports all required sections as missing |
## Dependencies
### Consumes
| types | `Frontmatter` struct |
| regex | `Regex`, `LazyLock` for compiled patterns |
### Consumed By
| validator | `parse_frontmatter`, `get_spec_symbols`, `get_missing_sections` |
| scoring | `parse_frontmatter`, `get_spec_symbols`, `get_missing_sections` |
| mcp | `parse_frontmatter` (for listing specs) |
## Change Log
| 2026-03-25 | Initial spec |