89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
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 {
|
||
// Handle CRLF line endings by normalizing to LF first
|
||
const normalized = raw.replace(/\r\n/g, "\n");
|
||
const match = normalized.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 normalized = raw.replace(/\r\n/g, "\n");
|
||
const match = normalized.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();
|