* Extract the frontmatter block: the content between the opening `---` * fence (first non-blank line of the file) and the closing `---` fence. * An unclosed fence is treated as "no frontmatter" rather than swallowing * the whole template as TypeScript. * * Returns the content plus its
()
| 121 | * Returns the content plus its 0-indexed start line, or null. |
| 122 | */ |
| 123 | private extractFrontmatter(): { content: string; startLine: number; endLine: number } | null { |
| 124 | const lines = this.source.split('\n'); |
| 125 | |
| 126 | // Opening fence must be the first non-blank line |
| 127 | let openIdx = -1; |
| 128 | for (let i = 0; i < lines.length; i++) { |
| 129 | const trimmed = lines[i]!.trim(); |
| 130 | if (trimmed === '') continue; |
| 131 | if (trimmed === '---') openIdx = i; |
| 132 | break; |
| 133 | } |
| 134 | if (openIdx === -1) return null; |
| 135 | |
| 136 | // Closing fence |
| 137 | let closeIdx = -1; |
| 138 | for (let i = openIdx + 1; i < lines.length; i++) { |
| 139 | if (lines[i]!.trim() === '---') { |
| 140 | closeIdx = i; |
| 141 | break; |
| 142 | } |
| 143 | } |
| 144 | if (closeIdx === -1) return null; |
| 145 | |
| 146 | return { |
| 147 | content: lines.slice(openIdx + 1, closeIdx).join('\n'), |
| 148 | startLine: openIdx + 1, // 0-indexed line where content starts |
| 149 | endLine: closeIdx, // 0-indexed line of the closing fence |
| 150 | }; |
| 151 | } |
| 152 | |
| 153 | /** |
| 154 | * Extract <script> blocks from the template portion |