obsidian-visualiser/shared/markdown.util.ts

75 lines
2.4 KiB
TypeScript

import type { Root, RootContent } from "hast";
import { dom, styling, text, type Class, type Node } from "./dom.util";
import prose, { a, blockquote, tag, h1, h2, h3, h4, h5, hr, li, small, table, td, th, callout, type Prose } from "./proses";
import { heading } from "hast-util-heading";
import { headingRank } from "hast-util-heading-rank";
import { parseId } from "./general.util";
import { loading } from "#shared/proses";
export function renderMarkdown(markdown: Root, proses: Record<string, Prose>): HTMLDivElement
{
return dom('div', {}, markdown.children.map(e => renderContent(e, proses)));
}
function renderContent(node: RootContent, proses: Record<string, Prose>): Node
{
if(node.type === 'text' && node.value.length > 0 && node.value !== '\n')
{
return text(node.value);
}
else if(node.type === 'comment' && node.value.length > 0 && node.value !== '\n')
{
return undefined;
}
else if(node.type === 'element')
{
const children = node.children.map(e => renderContent(e, proses)), properties = { ...node.properties, class: node.properties.className as string | string[] };
if(node.tagName in proses)
return prose(node.tagName, proses[node.tagName], children, properties);
else
return dom(node.tagName as keyof HTMLElementTagNameMap, properties, children);
}
return undefined;
}
export interface MDProperties
{
class?: Class;
style?: string | Record<string, string>;
tags?: Record<string, Prose>;
}
export default function(content: string, filter?: string, properties?: MDProperties): HTMLElement
{
const load = loading('normal');
queueMicrotask(() => {
useMarkdown().parse(content).then(data => {
if(filter)
{
const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1;
if(start !== -1)
{
let end = start;
const rank = headingRank(data.children[start])!;
while(end < data.children.length)
{
end++;
if(heading(data.children[end]) && headingRank(data.children[end])! <= rank)
break;
}
data = { ...data, children: data.children.slice(start, end) };
}
}
const el = renderMarkdown(data, { a, blockquote, tag, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th, ...properties?.tags });
if(properties) styling(el, properties);
load.parentElement?.replaceChild(el, load);
});
})
return load;
}