diff --git a/src/core/parsers/markdown-parser.ts b/src/core/parsers/markdown-parser.ts index abad78df2..770cc0518 100644 --- a/src/core/parsers/markdown-parser.ts +++ b/src/core/parsers/markdown-parser.ts @@ -216,10 +216,12 @@ export class MarkdownParser { contentBeforeChildren.push(line); } - // Find first non-empty line + // Find first non-empty requirement text line, skipping optional metadata. const directContent = contentBeforeChildren.join('\n').trim(); if (directContent) { - const firstLine = directContent.split('\n').find(l => l.trim()); + const firstLine = directContent + .split('\n') + .find(l => l.trim() && !this.isRequirementMetadataLine(l)); if (firstLine) { text = firstLine.trim(); } @@ -237,6 +239,10 @@ export class MarkdownParser { return requirements; } + private isRequirementMetadataLine(line: string): boolean { + return /^\*\*[^*]+\*\*:/.test(line.trim()); + } + protected parseScenarios(requirementSection: Section): Scenario[] { const scenarios: Scenario[] = []; diff --git a/test/core/parsers/markdown-parser.test.ts b/test/core/parsers/markdown-parser.test.ts index 751ab98db..ee857cc94 100644 --- a/test/core/parsers/markdown-parser.test.ts +++ b/test/core/parsers/markdown-parser.test.ts @@ -77,6 +77,33 @@ Then they are authenticated expect(scenario.rawText).toContain('and see a maintenance warning'); }); + it('should skip requirement metadata before description text', () => { + const content = `# File Serving Spec + +## Purpose +This specification defines file serving requirements. + +## Requirements + +### Requirement: File Serving +**ID**: REQ-FILE-001 +**Priority**: P1 + +The system MUST serve static files from the root directory. + +#### Scenario: Static file request +- **WHEN** a client requests a static file +- **THEN** the file is returned`; + + const parser = new MarkdownParser(content); + const spec = parser.parseSpec('file-serving'); + + expect(spec.requirements).toHaveLength(1); + expect(spec.requirements[0].text).toBe( + 'The system MUST serve static files from the root directory.' + ); + }); + it('should throw error for missing overview', () => { const content = `# Test Spec