feat: frontmatter parse/resolve/serialize
Co-Authored-By: Claude
This commit is contained in:
52
src/frontmatter.ts
Normal file
52
src/frontmatter.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import yaml from "js-yaml";
|
||||
|
||||
export interface Pair {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export function parseNote(text: string): { frontmatter: Record<string, unknown>; body: string } {
|
||||
const stripped = text.replace(/^/, "");
|
||||
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(stripped);
|
||||
if (!m) return { frontmatter: {}, body: stripped };
|
||||
const loaded = yaml.load(m[1]);
|
||||
const frontmatter = loaded && typeof loaded === "object" ? (loaded as Record<string, unknown>) : {};
|
||||
return { frontmatter, body: stripped.slice(m[0].length) };
|
||||
}
|
||||
|
||||
export function resolveFrontmatter(
|
||||
presets: Pair[],
|
||||
docFrontmatter: Record<string, unknown>,
|
||||
custom: Pair[],
|
||||
mergeDoc: boolean
|
||||
): Pair[] {
|
||||
const out: Pair[] = [];
|
||||
const idx = new Map<string, number>();
|
||||
const put = (key: string, value: string) => {
|
||||
const at = idx.get(key);
|
||||
if (at !== undefined) out[at] = { key, value };
|
||||
else { idx.set(key, out.length); out.push({ key, value }); }
|
||||
};
|
||||
for (const p of presets) put(p.key, p.value);
|
||||
if (mergeDoc) for (const [k, v] of Object.entries(docFrontmatter)) put(k, stringifyScalar(v));
|
||||
for (const c of custom) put(c.key, c.value);
|
||||
return out;
|
||||
}
|
||||
|
||||
function stringifyScalar(v: unknown): string {
|
||||
if (v == null) return "";
|
||||
if (v instanceof Date) return v.toISOString().slice(0, 10);
|
||||
if (typeof v === "object") return yaml.dump(v).trim();
|
||||
return String(v);
|
||||
}
|
||||
|
||||
export function serializeFrontmatter(pairs: Pair[]): string {
|
||||
const lines = pairs.map((p) => `${p.key}: ${formatValue(p.value)}`);
|
||||
return `---\n${lines.join("\n")}\n---\n`;
|
||||
}
|
||||
|
||||
function formatValue(v: string): string {
|
||||
if (v === "") return '""';
|
||||
const bareSafe = /^[A-Za-z0-9_./-][A-Za-z0-9_./ -]*$/.test(v) && !/^\s|\s$/.test(v);
|
||||
return bareSafe ? v : JSON.stringify(v);
|
||||
}
|
||||
Reference in New Issue
Block a user