A CLI for publishing standard.site documents to ATProto

chore: added hugo support through frontmatter parsing

+34 -15
+34 -15
packages/cli/src/lib/markdown.ts
··· 6 6 frontmatter: PostFrontmatter; 7 7 body: string; 8 8 } { 9 - const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/; 9 + // Support multiple frontmatter delimiters: 10 + // --- (YAML) - Jekyll, Astro, most SSGs 11 + // +++ (TOML) - Hugo 12 + // *** - Alternative format 13 + const frontmatterRegex = /^(---|\+\+\+|\*\*\*)\n([\s\S]*?)\n\1\n([\s\S]*)$/; 10 14 const match = content.match(frontmatterRegex); 11 15 12 16 if (!match) { 13 17 throw new Error("Could not parse frontmatter"); 14 18 } 15 19 16 - const frontmatterStr = match[1] ?? ""; 17 - const body = match[2] ?? ""; 20 + const delimiter = match[1]; 21 + const frontmatterStr = match[2] ?? ""; 22 + const body = match[3] ?? ""; 23 + 24 + // Determine format based on delimiter: 25 + // +++ uses TOML (key = value) 26 + // --- and *** use YAML (key: value) 27 + const isToml = delimiter === "+++"; 28 + const separator = isToml ? "=" : ":"; 18 29 19 - // Parse YAML-like frontmatter manually 30 + // Parse frontmatter manually 20 31 const raw: Record<string, unknown> = {}; 21 32 const lines = frontmatterStr.split("\n"); 22 33 23 34 for (const line of lines) { 24 - const colonIndex = line.indexOf(":"); 25 - if (colonIndex === -1) continue; 35 + const sepIndex = line.indexOf(separator); 36 + if (sepIndex === -1) continue; 26 37 27 - const key = line.slice(0, colonIndex).trim(); 28 - let value = line.slice(colonIndex + 1).trim(); 38 + const key = line.slice(0, sepIndex).trim(); 39 + let value = line.slice(sepIndex + 1).trim(); 29 40 30 41 // Handle quoted strings 31 42 if ( ··· 155 166 } 156 167 157 168 export function updateFrontmatterWithAtUri(rawContent: string, atUri: string): string { 158 - // Check if atUri already exists in frontmatter 159 - if (rawContent.includes("atUri:")) { 160 - // Replace existing atUri 161 - return rawContent.replace(/atUri:\s*["']?[^"'\n]+["']?\n?/, `atUri: "${atUri}"\n`); 169 + // Detect which delimiter is used (---, +++, or ***) 170 + const delimiterMatch = rawContent.match(/^(---|\+\+\+|\*\*\*)/); 171 + const delimiter = delimiterMatch?.[1] ?? "---"; 172 + const isToml = delimiter === "+++"; 173 + 174 + // Format the atUri entry based on frontmatter type 175 + const atUriEntry = isToml ? `atUri = "${atUri}"` : `atUri: "${atUri}"`; 176 + 177 + // Check if atUri already exists in frontmatter (handle both formats) 178 + if (rawContent.includes("atUri:") || rawContent.includes("atUri =")) { 179 + // Replace existing atUri (match both YAML and TOML formats) 180 + return rawContent.replace(/atUri\s*[=:]\s*["']?[^"'\n]+["']?\n?/, `${atUriEntry}\n`); 162 181 } 163 182 164 - // Insert atUri before the closing --- 165 - const frontmatterEndIndex = rawContent.indexOf("---", 4); 183 + // Insert atUri before the closing delimiter 184 + const frontmatterEndIndex = rawContent.indexOf(delimiter, 4); 166 185 if (frontmatterEndIndex === -1) { 167 186 throw new Error("Could not find frontmatter end"); 168 187 } ··· 170 189 const beforeEnd = rawContent.slice(0, frontmatterEndIndex); 171 190 const afterEnd = rawContent.slice(frontmatterEndIndex); 172 191 173 - return `${beforeEnd}atUri: "${atUri}"\n${afterEnd}`; 192 + return `${beforeEnd}${atUriEntry}\n${afterEnd}`; 174 193 } 175 194 176 195 export function stripMarkdownForText(markdown: string): string {