roadmap/quartz/plugins/transformers/ofm.ts

86 lines
2.5 KiB
TypeScript
Raw Normal View History

2023-06-01 16:33:20 +00:00
import { PluggableList } from "unified"
import { QuartzTransformerPlugin } from "../types"
import { Root } from 'mdast'
import { findAndReplace } from "mdast-util-find-and-replace"
import { slugify } from "../../path"
import rehypeRaw from "rehype-raw"
export interface Options {
highlight: boolean
wikilinks: boolean
}
const defaultOptions: Options = {
highlight: true,
2023-06-03 19:07:19 +00:00
wikilinks: true,
2023-06-01 16:33:20 +00:00
}
export class ObsidianFlavoredMarkdown extends QuartzTransformerPlugin {
name = "ObsidianFlavoredMarkdown"
opts: Options
constructor(opts?: Options) {
super()
this.opts = { ...defaultOptions, ...opts }
}
markdownPlugins(): PluggableList {
const plugins: PluggableList = []
if (this.opts.wikilinks) {
plugins.push(() => {
// Match wikilinks
// !? -> optional embedding
// \[\[ -> open brace
// ([^\[\]\|\#]+) -> one or more non-special characters ([,],|, or #) (name)
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
// (|[^\[\]\|\#]+)? -> | then one or more non-special characters (alias)
const backlinkRegex = new RegExp(/!?\[\[([^\[\]\|\#]+)(#[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/, "g")
return (tree: Root, _file) => {
findAndReplace(tree, backlinkRegex, (value: string, ...capture: string[]) => {
2023-06-01 21:35:31 +00:00
if (value.startsWith("!")) {
2023-06-03 19:07:19 +00:00
// TODO: handle embeds
2023-06-01 21:35:31 +00:00
} else {
const [path, rawHeader, rawAlias] = capture
2023-06-03 19:07:19 +00:00
const anchor = rawHeader?.trim() ?? ""
2023-06-01 21:35:31 +00:00
const alias = rawAlias?.slice(1).trim() ?? path
2023-06-01 23:48:38 +00:00
const url = slugify(path.trim() + anchor)
2023-06-01 21:35:31 +00:00
return {
type: 'link',
url,
children: [{
type: 'text',
value: alias
}]
}
2023-06-01 16:33:20 +00:00
}
})
}
}
)
}
if (this.opts.highlight) {
plugins.push(() => {
// Match highlights
const highlightRegex = new RegExp(/==(.+)==/, "g")
return (tree: Root, _file) => {
findAndReplace(tree, highlightRegex, (_value: string, ...capture: string[]) => {
const [inner] = capture
return {
type: 'html',
value: `<span class="text-highlight">${inner}</span>`
}
})
}
})
}
return plugins
}
htmlPlugins(): PluggableList {
return [rehypeRaw]
}
}