chore: added hugo support through frontmatter parsing c8300a54
Steve · 2026-01-29 07:40 1 file(s) · +34 −15
packages/cli/src/lib/markdown.ts +34 −15
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 {