ttrpg-tools/src/components/doc-data.ts

86 lines
2.4 KiB
TypeScript
Raw Normal View History

import yaml from "js-yaml";
export interface DocEntry {
tag: string;
icon: string;
title: string;
description: string;
syntax: string;
props: { name: string; type: string; default?: string; desc: string }[];
/** Markdown body (everything after frontmatter ---) */
body: string;
}
/** Splits frontmatter and markdown body from a raw .md string. */
function parseFrontmatter(raw: string): Record<string, unknown> | null {
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
if (!match) return null;
try {
return yaml.load(match[1]) as Record<string, unknown>;
} catch {
return null;
}
}
function getBody(raw: string): string {
const match = raw.match(/^---\n[\s\S]*?\n---\n?([\s\S]*)$/);
return match ? match[1] : raw;
}
function parseEntry(raw: string): DocEntry | null {
const fm = parseFrontmatter(raw);
if (!fm) return null;
return {
tag: fm.tag as string,
icon: fm.icon as string,
title: fm.title as string,
description: fm.description as string,
syntax: fm.syntax as string,
props: (fm.props as DocEntry["props"]) ?? [],
body: getBody(raw),
};
}
// Static imports each .md file is asset/source so imports are strings.
// Add a new import here when creating a new doc entry.
import mdDiceRaw from "../doc-entries/md-dice.md";
import mdTableRaw from "../doc-entries/md-table.md";
import mdLinkRaw from "../doc-entries/md-link.md";
import mdPinsRaw from "../doc-entries/md-pins.md";
import mdFontRaw from "../doc-entries/md-font.md";
import mdBgRaw from "../doc-entries/md-bg.md";
import mdBorderRaw from "../doc-entries/md-border.md";
import mdEmbedRaw from "../doc-entries/md-embed.md";
import mdDeckRaw from "../doc-entries/md-deck.md";
import mdYarnRaw from "../doc-entries/md-yarn-spinner.md";
import mdTokenRaw from "../doc-entries/md-token.md";
import mdTokenViewerRaw from "../doc-entries/md-token-viewer.md";
import mdCommanderRaw from "../doc-entries/md-commander.md";
const rawDocuments: string[] = [
mdDiceRaw,
mdTableRaw,
mdLinkRaw,
mdPinsRaw,
mdFontRaw,
mdBgRaw,
mdBorderRaw,
mdEmbedRaw,
mdDeckRaw,
mdYarnRaw,
mdTokenRaw,
mdTokenViewerRaw,
mdCommanderRaw,
];
let _entries: DocEntry[] | null = null;
function loadDocEntries(): DocEntry[] {
if (_entries) return _entries;
_entries = rawDocuments.map(parseEntry).filter(Boolean) as DocEntry[];
_entries.sort((a, b) => a.tag.localeCompare(b.tag));
return _entries;
}
export const docEntries = loadDocEntries();