57 lines
1.9 KiB
JavaScript
57 lines
1.9 KiB
JavaScript
import { parse } from 'smol-toml';
|
|
|
|
// Zola frontmatter is delimited by a `+++` line, then TOML, then another
|
|
// `+++` line. Only the first such block (right at the top of the file) is
|
|
// treated as frontmatter; anything else is body content.
|
|
const FRONTMATTER_RE = /^\+\+\+\r?\n([\s\S]*?)\r?\n\+\+\+\r?\n?/;
|
|
|
|
// Values that would be ambiguous or invalid as a plain (unquoted) YAML
|
|
// scalar: leading YAML indicator characters, empty strings, and strings
|
|
// that would otherwise parse as a different type (bool/null/number).
|
|
const LEADING_SPECIAL_RE = /^[-?:,[\]{}#&*!|>'"%@`]/;
|
|
const AMBIGUOUS_SCALAR_RE = /^(true|false|null|~|-?\d+(\.\d+)?)$/i;
|
|
|
|
function needsQuoting(value) {
|
|
if (value === '') return true;
|
|
if (LEADING_SPECIAL_RE.test(value)) return true;
|
|
if (value.includes(':') || value.includes('#')) return true;
|
|
if (/^\s|\s$/.test(value)) return true;
|
|
if (AMBIGUOUS_SCALAR_RE.test(value)) return true;
|
|
return false;
|
|
}
|
|
|
|
function yamlScalar(value) {
|
|
return needsQuoting(value) ? JSON.stringify(value) : value;
|
|
}
|
|
|
|
/**
|
|
* Converts a leading Zola `+++ TOML +++` frontmatter block into a Starlight
|
|
* `--- YAML ---` block, per the documented field mapping. The body (and the
|
|
* rest of the file after the frontmatter) is left byte-for-byte untouched.
|
|
* Files with no leading `+++` block are returned unchanged.
|
|
*
|
|
* @param {string} rawMarkdown
|
|
* @returns {string}
|
|
*/
|
|
export function convertFrontmatter(rawMarkdown) {
|
|
const match = rawMarkdown.match(FRONTMATTER_RE);
|
|
if (!match) return rawMarkdown;
|
|
|
|
const toml = parse(match[1]);
|
|
const body = rawMarkdown.slice(match[0].length);
|
|
|
|
const lines = ['---'];
|
|
if ('title' in toml) {
|
|
lines.push(`title: ${yamlScalar(String(toml.title))}`);
|
|
}
|
|
if ('description' in toml) {
|
|
lines.push(`description: ${yamlScalar(String(toml.description))}`);
|
|
}
|
|
if ('weight' in toml) {
|
|
lines.push('sidebar:', ` order: ${toml.weight}`);
|
|
}
|
|
lines.push('---');
|
|
|
|
return lines.join('\n') + '\n' + body;
|
|
}
|