diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index 624308ca4..b23e39e2c 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -20,6 +20,9 @@ import { toHtml } from "hast-util-to-html" import { PhrasingContent } from "mdast-util-find-and-replace/lib" import { capitalize } from "../../util/lang" import { PluggableList } from "unified" +import yaml from "js-yaml" +import toml from "toml" +import matter from "gray-matter" export interface Options { comments: boolean @@ -34,6 +37,9 @@ export interface Options { enableYouTubeEmbed: boolean enableVideoEmbed: boolean enableCheckbox: boolean + parsePropertiesWikilinks: boolean + delims: string + language: "yaml" | "toml" } const defaultOptions: Options = { @@ -49,6 +55,9 @@ const defaultOptions: Options = { enableYouTubeEmbed: true, enableVideoEmbed: true, enableCheckbox: false, + parsePropertiesWikilinks: true, + delims: "---", + language: "yaml", } const calloutMapping = { @@ -98,6 +107,27 @@ function canonicalizeCallout(calloutName: string): keyof typeof calloutMapping { return calloutMapping[normalizedCallout] ?? calloutName } +function propertyLinksToRegularMarkdown(obj: { [key: string]: any }): string { + // Parses wikilinks from FrontMatter properties and returns a string with all. + let result = "" + + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + if ( + Array.isArray(obj[key]) && + typeof obj[key][0] === "string" && + obj[key][0].includes("[[") + ) { + result += `- ${key}: ${obj[key].join(", ")}\n` + } else if (typeof obj[key] === "string" && obj[key].includes("[[")) { + result += `- ${key}: ${obj[key]}\n` + } + } + } + + return result +} + export const externalLinkRegex = /^https?:\/\//i export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/g) @@ -191,6 +221,39 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin> }) }) + // move Obsidian properties with links to the top of the file + if (opts.parsePropertiesWikilinks) { + if (src instanceof Buffer) { + src = src.toString() + } + + const { data } = matter(Buffer.from(src), { + ...opts, + engines: { + yaml: (s) => yaml.load(s, { schema: yaml.JSON_SCHEMA }) as object, + toml: (s) => toml.parse(s) as object, + }, + }) + const prop_links = propertyLinksToRegularMarkdown(data) + if (prop_links !== "") { + const yaml_props = src.split(opts.delims)[1] + const content = src.split(opts.delims).slice(2).join(opts.delims) + + src = + opts.delims + + "\n" + + yaml_props + + "\n" + + opts.delims + + "\n" + + prop_links + + "\n" + + opts.delims + + "\n" + + content + } + } + // replace all other wikilinks src = src.replace(wikilinkRegex, (value, ...capture) => { const [rawFp, rawHeader, rawAlias]: (string | undefined)[] = capture