( markdown: string, sourcePath?: string, )
| 128 | * @returns Object containing parsed frontmatter and content without frontmatter |
| 129 | */ |
| 130 | export function parseFrontmatter( |
| 131 | markdown: string, |
| 132 | sourcePath?: string, |
| 133 | ): ParsedMarkdown { |
| 134 | const match = markdown.match(FRONTMATTER_REGEX) |
| 135 | |
| 136 | if (!match) { |
| 137 | // No frontmatter found |
| 138 | return { |
| 139 | frontmatter: {}, |
| 140 | content: markdown, |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | const frontmatterText = match[1] || '' |
| 145 | const content = markdown.slice(match[0].length) |
| 146 | |
| 147 | let frontmatter: FrontmatterData = {} |
| 148 | try { |
| 149 | const parsed = parseYaml(frontmatterText) as FrontmatterData | null |
| 150 | if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { |
| 151 | frontmatter = parsed |
| 152 | } |
| 153 | } catch { |
| 154 | // YAML parsing failed - try again after quoting problematic values |
| 155 | try { |
| 156 | const quotedText = quoteProblematicValues(frontmatterText) |
| 157 | const parsed = parseYaml(quotedText) as FrontmatterData | null |
| 158 | if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { |
| 159 | frontmatter = parsed |
| 160 | } |
| 161 | } catch (retryError) { |
| 162 | // Still failed - log for debugging so users can diagnose broken frontmatter |
| 163 | const location = sourcePath ? ` in ${sourcePath}` : '' |
| 164 | logForDebugging( |
| 165 | `Failed to parse YAML frontmatter${location}: ${retryError instanceof Error ? retryError.message : retryError}`, |
| 166 | { level: 'warn' }, |
| 167 | ) |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | return { |
| 172 | frontmatter, |
| 173 | content, |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * Splits a comma-separated string and expands brace patterns. |
no test coverage detected