export class TFile { path: string; extension: string; constructor(path: string, extension = "md") { this.path = path; this.extension = extension; } } export class TFolder { path: string; constructor(path: string) { this.path = path; } } export const notices: string[] = []; export class Notice { constructor(message: string) { notices.push(message); } hide(): void {} } export class Plugin {} export class ItemView {} export class PluginSettingTab {} export class Setting {} export class Component {} export class FuzzySuggestModal {} export const Platform = { isMobile: false }; export const moment = () => undefined; export const requestUrl = () => Promise.reject(new Error("no network in the stub")); export const setIcon = () => undefined; function escapeHtml(value: string): string { return value .replace(/&/g, "&") .replace(//g, ">"); } // Enough of Obsidian's renderer for the panel: paragraphs, bold, code, // wikilinks as ``a.internal-link`` with ``data-href``, bare URLs. export const MarkdownRenderer = { render( _app: unknown, markdown: string, el: HTMLElement, _sourcePath: string, _component: unknown ): Promise { const blocks = markdown.split(/\n{2,}/).map((block) => { const html = escapeHtml(block) .replace( /!?\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, (_full, target: string, alias?: string) => `${alias ?? target}` ) .replace(/\*\*([^*]+)\*\*/g, "$1") .replace(/`([^`]+)`/g, "$1") .replace( /(^|\s)(https?:\/\/[^\s]+)/g, (_full, lead: string, url: string) => `${lead}${url}` ) .replace(/\n/g, "
"); if (block.startsWith("- ")) { const items = html .split("
") .map((line) => `
  • ${line.replace(/^- /, "")}
  • `); return ``; } return `

    ${html}

    `; }); el.innerHTML = blocks.join(""); return Promise.resolve(); }, };