import { marked } from 'marked'; import { create_renderer } from './renderer'; import { mark_ext } from './mark'; import { section_ext } from './section'; import { icon_ext } from './icon'; import { CustomElementHandling, sanitize_html } from './html-sanitize'; import { katex_block_ext, katex_inline_ext } from './katex'; import { footnote_list_ext, footnote_ref_ext } from './footnotes'; import { description_list_ext } from './description-list'; import { resolve_async_bindings } from './async-steps'; import { base_url_walk_tokens } from './base-url'; export interface MarkdownOptions { base_url?: string; breaks?: boolean; inline?: boolean; katex_macros?: Record; extensions?: MarkdownExtension[]; custom_elements?: CustomElementHandling; } export interface MarkdownExtension { (renderer: marked.Renderer, opts: MarkdownOptions): marked.TokenizerExtension & marked.RendererExtension } export async function render_markdown_to_html(markdown: string, options: MarkdownOptions = { }) { const marked_options = marked_opts(options); setup_marked(options, marked_options); const unsafe_html = options.inline ? marked.parseInline(markdown, marked_options) : marked.parse(markdown, marked_options); return sanitize_html(await resolve_async_bindings(unsafe_html), options.custom_elements); } export function render_markdown_to_html_inline_sync(markdown: string, options: MarkdownOptions = { }) { const marked_options = marked_opts(options); setup_marked(options, marked_options); const unsafe_html = marked.parseInline(markdown, marked_options); return sanitize_html(unsafe_html, options.custom_elements); } function marked_opts(options: MarkdownOptions) : marked.MarkedOptions { return { breaks: options.breaks || false, renderer: create_renderer(options), mangle: false, headerIds: false, }; } function setup_marked(options: MarkdownOptions, marked_options: marked.MarkedOptions) { marked.use({ walkTokens(token) { base_url_walk_tokens(token, options); }, extensions: [ katex_block_ext(marked_options.renderer, options), katex_inline_ext(marked_options.renderer, options), footnote_ref_ext(marked_options.renderer, options), footnote_list_ext(marked_options.renderer, options), mark_ext(marked_options.renderer, options), description_list_ext(marked_options.renderer, options), section_ext(marked_options.renderer, options), icon_ext(marked_options.renderer, options), ...(options.extensions || [ ]).map((ext) => { return ext(marked_options.renderer, options); }), ], tokenizer: { url(src) { // disable auto-linking; more can be added here to auto-link only sometimes // see: https://github.com/markedjs/marked/issues/882#issuecomment-781628889 return null; } }, }); }