Skip to content

Commit 7db432c

Browse files
corvid-agentclaude
andcommitted
docs: add 12 self-specs bootstrapping Specl with its own format
Write specs for every module in the project: models, template, parser, validator, DB service, store service, editor page, and all 6 components. Each spec follows the standard frontmatter + 7 required sections format and passes validation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3081cb8 commit 7db432c

12 files changed

+1241
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
module: frontmatter-editor
3+
version: 1
4+
status: active
5+
files:
6+
- src/app/components/frontmatter-editor/frontmatter-editor.ts
7+
- src/app/components/frontmatter-editor/frontmatter-editor.html
8+
- src/app/components/frontmatter-editor/frontmatter-editor.scss
9+
depends_on:
10+
- spec-models
11+
---
12+
13+
# Frontmatter Editor
14+
15+
## Purpose
16+
17+
Provides a structured form UI for editing spec YAML frontmatter fields. Renders text inputs for module and version, a select dropdown for status, and dynamic add/remove lists for files, db_tables, and depends_on. All changes emit the complete updated frontmatter object to the parent.
18+
19+
## Public API
20+
21+
### Exported Classes
22+
23+
| Class | Description |
24+
|-------|-------------|
25+
| `FrontmatterEditorComponent` | Angular standalone component for editing SpecFrontmatter |
26+
27+
### Component Inputs
28+
29+
| Input | Type | Required | Description |
30+
|-------|------|----------|-------------|
31+
| `frontmatter` | `SpecFrontmatter` | Yes | The current frontmatter to edit |
32+
33+
### Component Outputs
34+
35+
| Output | Type | Description |
36+
|--------|------|-------------|
37+
| `frontmatterChange` | `SpecFrontmatter` | Emitted with the complete updated frontmatter on any field change |
38+
39+
## Invariants
40+
41+
1. Every change emits the full `SpecFrontmatter` object — not partial updates
42+
2. Array items (files, db_tables, depends_on) are added via temporary input fields that clear after add
43+
3. Empty strings are not added to arrays — `trim()` is checked before adding
44+
4. Removing an array item splices by index and emits the updated frontmatter
45+
5. The frontmatter input is never mutated — spread copies are always created
46+
47+
## Behavioral Examples
48+
49+
### Scenario: Change module name
50+
51+
- **Given** frontmatter with `module: 'auth'`
52+
- **When** user changes the module input to `'auth-middleware'`
53+
- **Then** `frontmatterChange` emits with `{...frontmatter, module: 'auth-middleware'}`
54+
55+
### Scenario: Add a file path
56+
57+
- **Given** frontmatter with `files: ['server/auth.ts']`
58+
- **When** user types `'server/middleware.ts'` in the new file input and clicks add
59+
- **Then** `frontmatterChange` emits with `files: ['server/auth.ts', 'server/middleware.ts']`
60+
- **And** the new file input is cleared
61+
62+
### Scenario: Remove a file path
63+
64+
- **Given** frontmatter with `files: ['a.ts', 'b.ts', 'c.ts']`
65+
- **When** user clicks remove on index 1
66+
- **Then** `frontmatterChange` emits with `files: ['a.ts', 'c.ts']`
67+
68+
### Scenario: Add empty string blocked
69+
70+
- **Given** the new file input is empty or whitespace
71+
- **When** user clicks add
72+
- **Then** nothing happens — no emit, no change
73+
74+
### Scenario: Change status
75+
76+
- **Given** frontmatter with `status: 'draft'`
77+
- **When** user selects `'active'` from the dropdown
78+
- **Then** `frontmatterChange` emits with `status: 'active'`
79+
80+
## Error Cases
81+
82+
| Condition | Behavior |
83+
|-----------|----------|
84+
| Empty string in add input | Blocked — `trim()` check prevents adding |
85+
| Remove at invalid index | `splice` is safe — no error, but array may not change |
86+
87+
## Dependencies
88+
89+
### Consumes
90+
91+
| Module | What is used |
92+
|--------|-------------|
93+
| `spec-models` | `SpecFrontmatter`, `SpecStatus` types |
94+
| `@angular/forms` | `FormsModule` for two-way binding |
95+
96+
### Consumed By
97+
98+
| Module | What is used |
99+
|--------|-------------|
100+
| `editor-page` | Child component for editing frontmatter when `activeSectionIndex === -1` |
101+
102+
## Change Log
103+
104+
| Date | Author | Change |
105+
|------|--------|--------|
106+
| 2026-02-24 | CorvidAgent | Initial spec |
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
module: section-editor
3+
version: 1
4+
status: active
5+
files:
6+
- src/app/components/section-editor/section-editor.ts
7+
- src/app/components/section-editor/section-editor.html
8+
- src/app/components/section-editor/section-editor.scss
9+
depends_on:
10+
- spec-models
11+
---
12+
13+
# Section Editor
14+
15+
## Purpose
16+
17+
Provides a focused editing interface for a single spec section. Renders an editable heading input and a CodeMirror 6 editor scoped to just that section's content. Supports prev/next navigation between sections. Manages CodeMirror instance lifecycle — creating and destroying editors as the active section changes.
18+
19+
## Public API
20+
21+
### Exported Classes
22+
23+
| Class | Description |
24+
|-------|-------------|
25+
| `SectionEditorComponent` | Angular standalone component for editing a single section |
26+
27+
### Component Inputs
28+
29+
| Input | Type | Required | Description |
30+
|-------|------|----------|-------------|
31+
| `section` | `SpecSection` | Yes | The section to edit |
32+
| `sectionIndex` | `number` | Yes | Current section index in the editable sections array |
33+
| `totalSections` | `number` | Yes | Total number of editable sections |
34+
35+
### Component Outputs
36+
37+
| Output | Type | Description |
38+
|--------|------|-------------|
39+
| `contentChange` | `string` | Emitted when the section content changes in the editor |
40+
| `headingChange` | `string` | Emitted when the section heading input changes |
41+
| `navigate` | `number` | Emitted with target index when prev/next is clicked (-1 for frontmatter) |
42+
43+
## Invariants
44+
45+
1. A new CodeMirror EditorView is created when the section index changes
46+
2. The old EditorView is destroyed before creating a new one to prevent memory leaks
47+
3. `suppressUpdate` flag prevents feedback loops — when user types, the update listener emits contentChange which would trigger an external state update, which would try to update the editor again
48+
4. Prev button navigates to `index - 1`, or `-1` (frontmatter) if already at index 0
49+
5. Next button is disabled at the last section (`sectionIndex >= totalSections - 1`)
50+
6. The editor uses One Dark theme, markdown syntax highlighting, line numbers, history, and active line highlighting
51+
52+
## Behavioral Examples
53+
54+
### Scenario: Section changes trigger editor recreation
55+
56+
- **Given** the editor is showing section at index 2
57+
- **When** the parent sets `sectionIndex` to 3
58+
- **Then** the current EditorView is destroyed and a new one is created with section 3's content
59+
60+
### Scenario: Content editing emits change
61+
62+
- **Given** the Purpose section is loaded in the editor
63+
- **When** user types additional text
64+
- **Then** `contentChange` emits with the full updated document text
65+
66+
### Scenario: Navigate to previous section
67+
68+
- **Given** current section index is 2
69+
- **When** user clicks the "Prev" button
70+
- **Then** `navigate` emits with value `1`
71+
72+
### Scenario: Navigate from first section to frontmatter
73+
74+
- **Given** current section index is 0
75+
- **When** user clicks the "Prev" button
76+
- **Then** `navigate` emits with value `-1`
77+
78+
### Scenario: Heading change
79+
80+
- **Given** section heading is "Purpose"
81+
- **When** user changes the heading input to "Overview"
82+
- **Then** `headingChange` emits with value `"Overview"`
83+
84+
## Error Cases
85+
86+
| Condition | Behavior |
87+
|-----------|----------|
88+
| No editor host element | Effect exits early, no editor created |
89+
| Component destroyed | `ngOnDestroy` calls `destroyEditor` to clean up the EditorView |
90+
| External content matches editor content | No dispatch — avoids unnecessary updates |
91+
92+
## Dependencies
93+
94+
### Consumes
95+
96+
| Module | What is used |
97+
|--------|-------------|
98+
| `spec-models` | `SpecSection` type |
99+
| `@codemirror/state` | `EditorState` |
100+
| `@codemirror/view` | `EditorView`, `keymap`, `lineNumbers`, `highlightActiveLine` |
101+
| `@codemirror/commands` | `defaultKeymap`, `history`, `historyKeymap` |
102+
| `@codemirror/lang-markdown` | `markdown` language support |
103+
| `@codemirror/theme-one-dark` | `oneDark` theme |
104+
| `@codemirror/language` | `syntaxHighlighting`, `defaultHighlightStyle` |
105+
106+
### Consumed By
107+
108+
| Module | What is used |
109+
|--------|-------------|
110+
| `editor-page` | Child component displaying the active section |
111+
112+
## Change Log
113+
114+
| Date | Author | Change |
115+
|------|--------|--------|
116+
| 2026-02-24 | CorvidAgent | Initial spec |
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
module: section-nav
3+
version: 1
4+
status: active
5+
files:
6+
- src/app/components/section-nav/section-nav.ts
7+
- src/app/components/section-nav/section-nav.html
8+
- src/app/components/section-nav/section-nav.scss
9+
depends_on:
10+
- spec-models
11+
---
12+
13+
# Section Nav
14+
15+
## Purpose
16+
17+
Renders a sidebar navigation listing all sections of a spec. Includes a "Frontmatter" entry at the top (index -1) followed by all parsed sections. Highlights the currently active section and supports visual indentation for subsections based on heading level.
18+
19+
## Public API
20+
21+
### Exported Classes
22+
23+
| Class | Description |
24+
|-------|-------------|
25+
| `SectionNavComponent` | Angular standalone component for section navigation |
26+
27+
### Exported Types
28+
29+
| Type | Description |
30+
|------|-------------|
31+
| `NavItem` | Discriminated union: `{type: 'frontmatter', label: string}` or `{type: 'section', index: number, label: string, level: number}` |
32+
33+
### Component Inputs
34+
35+
| Input | Type | Required | Description |
36+
|-------|------|----------|-------------|
37+
| `sections` | `SpecSection[]` | Yes | Array of editable sections to display |
38+
| `activeIndex` | `number` | Yes | Currently active section index (-1 for frontmatter) |
39+
40+
### Component Outputs
41+
42+
| Output | Type | Description |
43+
|--------|------|-------------|
44+
| `selectIndex` | `number` | Emitted when a nav item is clicked, with the section index (-1 for frontmatter) |
45+
46+
## Invariants
47+
48+
1. The first nav item is always "Frontmatter" with type `'frontmatter'`
49+
2. Section nav items preserve the order from the input `sections` array
50+
3. `isActive` returns true for frontmatter when `activeIndex === -1` and for sections when `activeIndex === item.index`
51+
4. Each section nav item carries its heading `level` for visual indentation in the template
52+
53+
## Behavioral Examples
54+
55+
### Scenario: Render nav for a standard spec
56+
57+
- **Given** sections `[{heading: 'Purpose', level: 2}, {heading: 'Exported Functions', level: 3}, {heading: 'Public API', level: 2}]`
58+
- **When** the component renders
59+
- **Then** nav items are: Frontmatter, Purpose (level 2), Exported Functions (level 3, indented), Public API (level 2)
60+
61+
### Scenario: Select a section
62+
63+
- **Given** frontmatter is active (index -1)
64+
- **When** user clicks on "Purpose" (index 0)
65+
- **Then** `selectIndex` emits `0`
66+
67+
### Scenario: Select frontmatter
68+
69+
- **Given** section index 2 is active
70+
- **When** user clicks on "Frontmatter"
71+
- **Then** `selectIndex` emits `-1`
72+
73+
## Error Cases
74+
75+
| Condition | Behavior |
76+
|-----------|----------|
77+
| Empty sections array | Only "Frontmatter" nav item is shown |
78+
| activeIndex out of bounds | No item is highlighted as active |
79+
80+
## Dependencies
81+
82+
### Consumes
83+
84+
| Module | What is used |
85+
|--------|-------------|
86+
| `spec-models` | `SpecSection` type |
87+
88+
### Consumed By
89+
90+
| Module | What is used |
91+
|--------|-------------|
92+
| `editor-page` | Child component for section navigation sidebar |
93+
94+
## Change Log
95+
96+
| Date | Author | Change |
97+
|------|--------|--------|
98+
| 2026-02-24 | CorvidAgent | Initial spec |

0 commit comments

Comments
 (0)