From f176486cf2e1e5adcadd74dd396984ad279fcf80 Mon Sep 17 00:00:00 2001 From: Emile Bangma Date: Thu, 19 Sep 2024 13:28:37 +0000 Subject: [PATCH] Updated parser typing + Mermaid parser --- quartz/plugins/parsers/custom/default.ts | 12 +- quartz/plugins/parsers/obsidian/arrows.ts | 12 +- quartz/plugins/parsers/obsidian/callouts.ts | 33 ++-- quartz/plugins/parsers/obsidian/comments.ts | 17 +- quartz/plugins/parsers/obsidian/highlights.ts | 12 +- quartz/plugins/parsers/obsidian/index.ts | 1 + quartz/plugins/parsers/obsidian/mermaid.ts | 78 +++++++++ quartz/plugins/parsers/obsidian/wikilinks.ts | 148 +++++++++--------- quartz/plugins/transformers/markdown.ts | 5 + quartz/plugins/types.ts | 4 +- 10 files changed, 204 insertions(+), 118 deletions(-) diff --git a/quartz/plugins/parsers/custom/default.ts b/quartz/plugins/parsers/custom/default.ts index 6a05b6bba..00882bb41 100644 --- a/quartz/plugins/parsers/custom/default.ts +++ b/quartz/plugins/parsers/custom/default.ts @@ -24,10 +24,8 @@ export const CustomDefault: QuartzParserPlugin> = (userOpts) => }, markdownPlugins(_ctx) { const plug: Pluggable = (tree: Root, _file) => { - if (opts.enabled) { - const replacements: [RegExp, string | ReplaceFunction][] = [] - mdastFindReplace(tree, replacements) - } + const replacements: [RegExp, string | ReplaceFunction][] = [] + mdastFindReplace(tree, replacements) } return plug }, @@ -35,9 +33,9 @@ export const CustomDefault: QuartzParserPlugin> = (userOpts) => const plug: Pluggable = () => {} return plug }, - externalResources(_ctx) { - const js = [] as JSResource[] - return { js } + externalResources() { + const js = {} as JSResource + return js }, } } diff --git a/quartz/plugins/parsers/obsidian/arrows.ts b/quartz/plugins/parsers/obsidian/arrows.ts index 93cd48668..f5e42a33f 100644 --- a/quartz/plugins/parsers/obsidian/arrows.ts +++ b/quartz/plugins/parsers/obsidian/arrows.ts @@ -31,8 +31,10 @@ export const ObsidianArrow: QuartzParserPlugin> = (userOpts) => return { name: "ObsidianArrow", textTransform(_ctx, src: string | Buffer) { - if (src instanceof Buffer) { - src = src.toString() + if (opts.enabled) { + if (src instanceof Buffer) { + src = src.toString() + } } return src }, @@ -60,9 +62,9 @@ export const ObsidianArrow: QuartzParserPlugin> = (userOpts) => const plug: Pluggable = () => {} return plug }, - externalResources(_ctx) { - const js = [] as JSResource[] - return { js } + externalResources() { + const js = {} as JSResource + return js }, } } diff --git a/quartz/plugins/parsers/obsidian/callouts.ts b/quartz/plugins/parsers/obsidian/callouts.ts index 3b80ec729..3f80973f9 100644 --- a/quartz/plugins/parsers/obsidian/callouts.ts +++ b/quartz/plugins/parsers/obsidian/callouts.ts @@ -68,15 +68,16 @@ export const ObsidianCallouts: QuartzParserPlugin> = (userOpts) return { name: "ObsidianCallouts", textTransform(_ctx, src: string | Buffer) { - if (src instanceof Buffer) { - src = src.toString() + if (opts.enabled) { + if (src instanceof Buffer) { + src = src.toString() + } + src = src.replace(calloutLineRegex, (value) => { + // force newline after title of callout + return value + "\n> " + }) } - src = src.replace(calloutLineRegex, (value) => { - // force newline after title of callout - return value + "\n> " - }) - return src }, markdownPlugins(_ctx) { @@ -190,14 +191,16 @@ export const ObsidianCallouts: QuartzParserPlugin> = (userOpts) const plug: Pluggable = () => {} return plug }, - externalResources(_ctx) { - const js = [] as JSResource[] - js.push({ - script: calloutScript, - loadTime: "afterDOMReady", - contentType: "inline", - }) - return { js } + externalResources() { + if (opts.enabled) { + const js: JSResource = { + script: calloutScript, + loadTime: "afterDOMReady", + contentType: "inline", + } + return js + } + return {} as JSResource }, } } diff --git a/quartz/plugins/parsers/obsidian/comments.ts b/quartz/plugins/parsers/obsidian/comments.ts index 235c75baf..b432966d4 100644 --- a/quartz/plugins/parsers/obsidian/comments.ts +++ b/quartz/plugins/parsers/obsidian/comments.ts @@ -19,12 +19,13 @@ export const ObsidianComments: QuartzParserPlugin> = (userOpts) return { name: "ObsidianComments", textTransform(_ctx, src: string | Buffer) { - // do comments at text level - if (src instanceof Buffer) { - src = src.toString() - } + if (opts.enabled) { + if (src instanceof Buffer) { + src = src.toString() + } - src = src.replace(commentRegex, "") + src = src.replace(commentRegex, "") + } return src }, @@ -41,9 +42,9 @@ export const ObsidianComments: QuartzParserPlugin> = (userOpts) const plug: Pluggable = () => {} return plug }, - externalResources(_ctx) { - const js = [] as JSResource[] - return { js } + externalResources() { + const js = {} as JSResource + return js }, } } diff --git a/quartz/plugins/parsers/obsidian/highlights.ts b/quartz/plugins/parsers/obsidian/highlights.ts index 774aab1a2..3befeed7b 100644 --- a/quartz/plugins/parsers/obsidian/highlights.ts +++ b/quartz/plugins/parsers/obsidian/highlights.ts @@ -19,8 +19,10 @@ export const ObsidianHighlights: QuartzParserPlugin> = (userOpt return { name: "ObsidianHighlights", textTransform(_ctx, src: string | Buffer) { - if (src instanceof Buffer) { - src = src.toString() + if (opts.enabled) { + if (src instanceof Buffer) { + src = src.toString() + } } return src }, @@ -47,9 +49,9 @@ export const ObsidianHighlights: QuartzParserPlugin> = (userOpt const plug: Pluggable = () => {} return plug }, - externalResources(_ctx) { - const js = [] as JSResource[] - return { js } + externalResources() { + const js = {} as JSResource + return js }, } } diff --git a/quartz/plugins/parsers/obsidian/index.ts b/quartz/plugins/parsers/obsidian/index.ts index ca865e2da..33378d42a 100644 --- a/quartz/plugins/parsers/obsidian/index.ts +++ b/quartz/plugins/parsers/obsidian/index.ts @@ -2,4 +2,5 @@ export { ObsidianArrow } from "./arrows" export { ObsidianCallouts } from "./callouts" export { ObsidianComments } from "./comments" export { ObsidianHighlights } from "./highlights" +export { ObsidianMermaid } from "./mermaid" export { ObsidianWikilinks } from "./wikilinks" diff --git a/quartz/plugins/parsers/obsidian/mermaid.ts b/quartz/plugins/parsers/obsidian/mermaid.ts index e69de29bb..e338386ac 100644 --- a/quartz/plugins/parsers/obsidian/mermaid.ts +++ b/quartz/plugins/parsers/obsidian/mermaid.ts @@ -0,0 +1,78 @@ +import { QuartzParserPlugin } from "../../types" +import { JSResource } from "../../../util/resources" +import { visit } from "unist-util-visit" +import { Root, Code } from "mdast" +import { Pluggable } from "unified" + +interface Options { + enabled: Boolean +} + +const defaultOptions: Options = { + enabled: true, +} + +export const ObsidianMermaid: QuartzParserPlugin> = (userOpts) => { + const opts: Options = { ...defaultOptions, ...userOpts } + return { + name: "ObsidianMermaid", + textTransform(_ctx, src: string | Buffer) { + if (opts.enabled) { + if (src instanceof Buffer) { + src = src.toString() + } + } + return src + }, + markdownPlugins(_ctx) { + const plug: Pluggable = (tree: Root, _file) => { + if (opts.enabled) { + visit(tree, "code", (node: Code) => { + if (node.lang === "mermaid") { + node.data = { + hProperties: { + className: ["mermaid"], + }, + } + } + }) + } + } + return plug + }, + htmlPlugins(_ctx) { + const plug: Pluggable = () => {} + return plug + }, + externalResources() { + if (opts.enabled) { + const js: JSResource = { + script: ` + let mermaidImport = undefined + document.addEventListener('nav', async () => { + if (document.querySelector("code.mermaid")) { + mermaidImport ||= await import('https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs') + const mermaid = mermaidImport.default + const darkMode = document.documentElement.getAttribute('saved-theme') === 'dark' + mermaid.initialize({ + startOnLoad: false, + securityLevel: 'loose', + theme: darkMode ? 'dark' : 'default' + }) + + await mermaid.run({ + querySelector: '.mermaid' + }) + } + }); + `, + loadTime: "afterDOMReady", + moduleType: "module", + contentType: "inline", + } + return js + } + return {} as JSResource + }, + } +} diff --git a/quartz/plugins/parsers/obsidian/wikilinks.ts b/quartz/plugins/parsers/obsidian/wikilinks.ts index f6b427ac1..b46f716c0 100644 --- a/quartz/plugins/parsers/obsidian/wikilinks.ts +++ b/quartz/plugins/parsers/obsidian/wikilinks.ts @@ -80,83 +80,79 @@ export const ObsidianWikilinks: QuartzParserPlugin> = (userOpts }, markdownPlugins(_ctx) { const plug: Pluggable = (tree: Root, path) => { - if (opts.enabled) { - const replacements: [RegExp, string | ReplaceFunction][] = [] - replacements.push([ - wikilinkRegex, - (value: string, ...capture: string[]) => { - let [rawFp, rawHeader, rawAlias] = capture - const fp = rawFp?.trim() ?? "" - const anchor = rawHeader?.trim() ?? "" - const alias = rawAlias?.slice(1).trim() + const replacements: [RegExp, string | ReplaceFunction][] = [] + replacements.push([ + wikilinkRegex, + (value: string, ...capture: string[]) => { + let [rawFp, rawHeader, rawAlias] = capture + const fp = rawFp?.trim() ?? "" + const anchor = rawHeader?.trim() ?? "" + const alias = rawAlias?.slice(1).trim() - // embed cases - if (value.startsWith("!")) { - const ext: string = path.extname(fp).toLowerCase() - const url = slugifyFilePath(fp as FilePath) - if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg", ".webp"].includes(ext)) { - const match = wikilinkImageEmbedRegex.exec(alias ?? "") - const alt = match?.groups?.alt ?? "" - const width = match?.groups?.width ?? "auto" - const height = match?.groups?.height ?? "auto" - return { - type: "image", - url, - data: { - hProperties: { - width, - height, - alt, - }, + // embed cases + if (value.startsWith("!")) { + const ext: string = path.extname(fp).toLowerCase() + const url = slugifyFilePath(fp as FilePath) + if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg", ".webp"].includes(ext)) { + const match = wikilinkImageEmbedRegex.exec(alias ?? "") + const alt = match?.groups?.alt ?? "" + const width = match?.groups?.width ?? "auto" + const height = match?.groups?.height ?? "auto" + return { + type: "image", + url, + data: { + hProperties: { + width, + height, + alt, }, - } - } else if ([".mp4", ".webm", ".ogv", ".mov", ".mkv"].includes(ext)) { - return { - type: "html", - value: ``, - } - } else if ( - [".mp3", ".webm", ".wav", ".m4a", ".ogg", ".3gp", ".flac"].includes(ext) - ) { - return { - type: "html", - value: ``, - } - } else if ([".pdf"].includes(ext)) { - return { - type: "html", - value: ``, - } - } else { - const block = anchor - return { - type: "html", - data: { hProperties: { transclude: true } }, - value: `
Transclude of ${url}${block}
`, - } - } - - // otherwise, fall through to regular link - } - - // internal link - const url = fp + anchor - return { - type: "link", - url, - children: [ - { - type: "text", - value: alias ?? fp, }, - ], + } + } else if ([".mp4", ".webm", ".ogv", ".mov", ".mkv"].includes(ext)) { + return { + type: "html", + value: ``, + } + } else if ([".mp3", ".webm", ".wav", ".m4a", ".ogg", ".3gp", ".flac"].includes(ext)) { + return { + type: "html", + value: ``, + } + } else if ([".pdf"].includes(ext)) { + return { + type: "html", + value: ``, + } + } else { + const block = anchor + return { + type: "html", + data: { hProperties: { transclude: true } }, + value: `
Transclude of ${url}${block}
`, + } } - }, - ]) - mdastFindReplace(tree, replacements) - } + + // otherwise, fall through to regular link + } + + // internal link + const url = fp + anchor + return { + type: "link", + url, + children: [ + { + type: "text", + value: alias ?? fp, + }, + ], + } + }, + ]) + mdastFindReplace(tree, replacements) } return plug }, @@ -164,9 +160,9 @@ export const ObsidianWikilinks: QuartzParserPlugin> = (userOpts const plug: Pluggable = () => {} return plug }, - externalResources(_ctx) { - const js = [] as JSResource[] - return { js } + externalResources() { + const js = {} as JSResource + return js }, } } diff --git a/quartz/plugins/transformers/markdown.ts b/quartz/plugins/transformers/markdown.ts index fdfecfa3c..88aba4b68 100644 --- a/quartz/plugins/transformers/markdown.ts +++ b/quartz/plugins/transformers/markdown.ts @@ -40,6 +40,7 @@ import { ObsidianCallouts, ObsidianComments, ObsidianHighlights, + ObsidianMermaid, ObsidianWikilinks, } from "../parsers/obsidian" @@ -206,6 +207,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin string | Buffer markdownPlugins: (ctx: BuildCtx) => Pluggable htmlPlugins: (ctx: BuildCtx) => Pluggable - externalResources: (ctx: BuildCtx) => Partial + externalResources: () => JSResource | string }