diff --git a/src/core/validate.test.ts b/src/core/validate.test.ts index 3bff612..0268b6b 100644 --- a/src/core/validate.test.ts +++ b/src/core/validate.test.ts @@ -162,6 +162,86 @@ describe('validate-docs-code', () => { expect(result).toHaveLength(1); expect(result[0].refPath).toBe('src/example.ts'); }); + + it('コードブロック内のCODE_REFを除外すること', () => { + const content = ` +# Test Document + + + +\`\`\`html + +\`\`\` + + + `; + + const result = extractCodeRefs(content, '/docs/test.md'); + + expect(result).toHaveLength(2); + expect(result[0].refPath).toBe('src/valid.ts'); + expect(result[1].refPath).toBe('src/another-valid.ts'); + }); + + it('インラインコード内のCODE_REFを除外すること', () => { + const content = ` +# Test Document + +Use this syntax: \`\` + + + `; + + const result = extractCodeRefs(content, '/docs/test.md'); + + expect(result).toHaveLength(1); + expect(result[0].refPath).toBe('src/valid.ts'); + }); + + it('閉じていないコードブロック内のCODE_REFを除外すること', () => { + const content = ` +# Test Document + + + +\`\`\`html + + + `; + + const result = extractCodeRefs(content, '/docs/test.md'); + + expect(result).toHaveLength(1); + expect(result[0].refPath).toBe('src/valid.ts'); + }); + + it('複数のコードブロックが混在する場合にCODE_REFを正しく抽出すること', () => { + const content = ` +# Documentation + + + +\`\`\`typescript + +const x = 1; +\`\`\` + + + +\`\`\`javascript + +\`\`\` + + + `; + + const result = extractCodeRefs(content, '/docs/test.md'); + + expect(result).toHaveLength(3); + expect(result[0].refPath).toBe('src/valid1.ts'); + expect(result[1].refPath).toBe('src/valid2.ts'); + expect(result[2].refPath).toBe('src/valid3.ts'); + }); }); describe('validateCodeRef', () => { diff --git a/src/core/validate.ts b/src/core/validate.ts index 80f1644..bee5e27 100644 --- a/src/core/validate.ts +++ b/src/core/validate.ts @@ -53,15 +53,33 @@ export function findMarkdownFiles(dir: string): string[] { function getCodeBlockRanges(content: string): { start: number; end: number }[] { const ranges: { start: number; end: number }[] = []; - // Triple backtick code blocks - const codeBlockPattern = /```[\s\S]*?```/g; + // Find all triple backtick positions + const backtickPositions: number[] = []; + const backtickPattern = /```/g; let match: RegExpExecArray | null; - while ((match = codeBlockPattern.exec(content)) !== null) { - ranges.push({ - start: match.index, - end: match.index + match[0].length, - }); + while ((match = backtickPattern.exec(content)) !== null) { + backtickPositions.push(match.index); + } + + // Pair up backticks: even indices (0, 2, 4...) are opening, odd indices (1, 3, 5...) are closing + for (let i = 0; i < backtickPositions.length; i += 2) { + const start = backtickPositions[i]; + const end = backtickPositions[i + 1]; + + if (end !== undefined) { + // Closed code block + ranges.push({ + start, + end: end + 3, // +3 to include the closing ``` + }); + } else { + // Unclosed code block (odd number of backticks) + ranges.push({ + start, + end: content.length, + }); + } } // Inline code (backticks)