fix: parsing wikilinks that have codeblock anchors, scroll to anchor
This commit is contained in:
parent
1c7b5c88d8
commit
fc03f3dcec
@ -1,6 +1,7 @@
|
|||||||
import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||||
import style from "./styles/backlinks.scss"
|
import style from "./styles/backlinks.scss"
|
||||||
import { relativeToRoot } from "../path"
|
import { relativeToRoot } from "../path"
|
||||||
|
import { stripIndex } from "./scripts/util"
|
||||||
|
|
||||||
function Backlinks({ fileData, allFiles }: QuartzComponentProps) {
|
function Backlinks({ fileData, allFiles }: QuartzComponentProps) {
|
||||||
const slug = fileData.slug!
|
const slug = fileData.slug!
|
||||||
@ -9,7 +10,7 @@ function Backlinks({ fileData, allFiles }: QuartzComponentProps) {
|
|||||||
<h3>Backlinks</h3>
|
<h3>Backlinks</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{backlinkFiles.length > 0 ?
|
{backlinkFiles.length > 0 ?
|
||||||
backlinkFiles.map(f => <li><a href={relativeToRoot(slug, f.slug!)} class="internal">{f.frontmatter?.title}</a></li>)
|
backlinkFiles.map(f => <li><a href={stripIndex(relativeToRoot(slug, f.slug!))} class="internal">{f.frontmatter?.title}</a></li>)
|
||||||
: <li>No backlinks found</li>}
|
: <li>No backlinks found</li>}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ContentDetails } from "../../plugins/emitters/contentIndex"
|
import { ContentDetails } from "../../plugins/emitters/contentIndex"
|
||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3'
|
||||||
import { registerEscapeHandler } from "./handler"
|
import { registerEscapeHandler, relative, removeAllChildren } from "./util"
|
||||||
|
|
||||||
type NodeData = {
|
type NodeData = {
|
||||||
id: string,
|
id: string,
|
||||||
@ -13,18 +13,6 @@ type LinkData = {
|
|||||||
target: string
|
target: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function relative(from: string, to: string) {
|
|
||||||
const pieces = [location.protocol, '//', location.host, location.pathname]
|
|
||||||
const url = pieces.join('').slice(0, -from.length) + to
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeAllChildren(node: HTMLElement) {
|
|
||||||
while (node.firstChild) {
|
|
||||||
node.removeChild(node.firstChild)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderGraph(container: string, slug: string) {
|
async function renderGraph(container: string, slug: string) {
|
||||||
const graph = document.getElementById(container)
|
const graph = document.getElementById(container)
|
||||||
if (!graph) return
|
if (!graph) return
|
||||||
@ -117,7 +105,6 @@ async function renderGraph(container: string, slug: string) {
|
|||||||
|
|
||||||
// calculate radius
|
// calculate radius
|
||||||
const color = (d: NodeData) => {
|
const color = (d: NodeData) => {
|
||||||
// TODO: does this handle the index page
|
|
||||||
const isCurrent = d.id === slug
|
const isCurrent = d.id === slug
|
||||||
return isCurrent ? "var(--secondary)" : "var(--gray)"
|
return isCurrent ? "var(--secondary)" : "var(--gray)"
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,11 @@ document.addEventListener("nav", () => {
|
|||||||
link.addEventListener("mouseenter", async ({ clientX, clientY }) => {
|
link.addEventListener("mouseenter", async ({ clientX, clientY }) => {
|
||||||
async function setPosition(popoverElement: HTMLElement) {
|
async function setPosition(popoverElement: HTMLElement) {
|
||||||
const { x, y } = await computePosition(link, popoverElement, {
|
const { x, y } = await computePosition(link, popoverElement, {
|
||||||
middleware: [inline({
|
middleware: [
|
||||||
x: clientX,
|
inline({ x: clientX, y: clientY }),
|
||||||
y: clientY
|
shift(),
|
||||||
}), shift(), flip()]
|
flip()
|
||||||
|
]
|
||||||
})
|
})
|
||||||
Object.assign(popoverElement.style, {
|
Object.assign(popoverElement.style, {
|
||||||
left: `${x}px`,
|
left: `${x}px`,
|
||||||
@ -22,11 +23,17 @@ document.addEventListener("nav", () => {
|
|||||||
return setPosition(link.lastChild as HTMLElement)
|
return setPosition(link.lastChild as HTMLElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = link.href
|
const thisUrl = new URL(document.location.href)
|
||||||
const anchor = new URL(url).hash
|
thisUrl.hash = ""
|
||||||
if (anchor.startsWith("#")) return
|
thisUrl.search = ""
|
||||||
|
const targetUrl = new URL(link.href)
|
||||||
|
const hash = targetUrl.hash
|
||||||
|
targetUrl.hash = ""
|
||||||
|
targetUrl.search = ""
|
||||||
|
// prevent hover of the same page
|
||||||
|
if (thisUrl.toString() === targetUrl.toString()) return
|
||||||
|
|
||||||
const contents = await fetch(`${url}`)
|
const contents = await fetch(`${targetUrl}`)
|
||||||
.then((res) => res.text())
|
.then((res) => res.text())
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
@ -39,7 +46,6 @@ document.addEventListener("nav", () => {
|
|||||||
|
|
||||||
const popoverElement = document.createElement("div")
|
const popoverElement = document.createElement("div")
|
||||||
popoverElement.classList.add("popover")
|
popoverElement.classList.add("popover")
|
||||||
// TODO: scroll this element if we specify a header/anchor to jump to
|
|
||||||
const popoverInner = document.createElement("div")
|
const popoverInner = document.createElement("div")
|
||||||
popoverInner.classList.add("popover-inner")
|
popoverInner.classList.add("popover-inner")
|
||||||
popoverElement.appendChild(popoverInner)
|
popoverElement.appendChild(popoverInner)
|
||||||
@ -48,6 +54,12 @@ document.addEventListener("nav", () => {
|
|||||||
setPosition(popoverElement)
|
setPosition(popoverElement)
|
||||||
link.appendChild(popoverElement)
|
link.appendChild(popoverElement)
|
||||||
link.dataset.fetchedPopover = "true"
|
link.dataset.fetchedPopover = "true"
|
||||||
|
|
||||||
|
const heading = popoverInner.querySelector(hash) as HTMLElement | null
|
||||||
|
if (heading) {
|
||||||
|
// leave ~12px of buffer when scrolling to a heading
|
||||||
|
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: 'instant' })
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Document } from "flexsearch"
|
import { Document } from "flexsearch"
|
||||||
import { ContentDetails } from "../../plugins/emitters/contentIndex"
|
import { ContentDetails } from "../../plugins/emitters/contentIndex"
|
||||||
import { registerEscapeHandler } from "./handler"
|
import { registerEscapeHandler, relative, removeAllChildren } from "./util"
|
||||||
|
|
||||||
interface Item {
|
interface Item {
|
||||||
slug: string,
|
slug: string,
|
||||||
@ -9,16 +9,6 @@ interface Item {
|
|||||||
}
|
}
|
||||||
let index: Document<Item> | undefined = undefined
|
let index: Document<Item> | undefined = undefined
|
||||||
|
|
||||||
function relative(from: string, to: string) {
|
|
||||||
const pieces = [location.protocol, '//', location.host, location.pathname]
|
|
||||||
const url = pieces.join('').slice(0, -from.length) + to
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeAllChildren(node: HTMLElement) {
|
|
||||||
node.innerHTML = ``
|
|
||||||
}
|
|
||||||
|
|
||||||
const contextWindowWords = 30
|
const contextWindowWords = 30
|
||||||
function highlight(searchTerm: string, text: string, trim?: boolean) {
|
function highlight(searchTerm: string, text: string, trim?: boolean) {
|
||||||
const tokenizedTerms = searchTerm.split(/\s+/).filter(t => t !== "")
|
const tokenizedTerms = searchTerm.split(/\s+/).filter(t => t !== "")
|
||||||
|
@ -17,3 +17,22 @@ export function registerEscapeHandler(outsideContainer: HTMLElement | null, cb:
|
|||||||
document.removeEventListener("keydown", esc)
|
document.removeEventListener("keydown", esc)
|
||||||
document.addEventListener('keydown', esc)
|
document.addEventListener('keydown', esc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stripIndex(s: string): string {
|
||||||
|
return s.endsWith("index") ? s.slice(0, -"index".length) : s
|
||||||
|
}
|
||||||
|
|
||||||
|
export function relative(from: string, to: string) {
|
||||||
|
from = encodeURI(stripIndex(from))
|
||||||
|
to = encodeURI(stripIndex(to))
|
||||||
|
const start = [location.protocol, '//', location.host, location.pathname].join('')
|
||||||
|
const trimEnd = from.length === 0 ? start.length : -from.length
|
||||||
|
const url = start.slice(0, trimEnd) + to
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeAllChildren(node: HTMLElement) {
|
||||||
|
while (node.firstChild) {
|
||||||
|
node.removeChild(node.firstChild)
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|
||||||
& > .popover-inner {
|
& > .popover-inner {
|
||||||
|
position: relative;
|
||||||
width: 30rem;
|
width: 30rem;
|
||||||
height: 20rem;
|
height: 20rem;
|
||||||
padding: 0 1rem 1rem 1rem;
|
padding: 0 1rem 1rem 1rem;
|
||||||
|
@ -14,9 +14,6 @@ export const Description: QuartzTransformerPlugin<Partial<Options> | undefined>
|
|||||||
const opts = { ...defaultOptions, ...userOpts }
|
const opts = { ...defaultOptions, ...userOpts }
|
||||||
return {
|
return {
|
||||||
name: "Description",
|
name: "Description",
|
||||||
markdownPlugins() {
|
|
||||||
return []
|
|
||||||
},
|
|
||||||
htmlPlugins() {
|
htmlPlugins() {
|
||||||
return [
|
return [
|
||||||
() => {
|
() => {
|
||||||
|
@ -33,9 +33,6 @@ export const FrontMatter: QuartzTransformerPlugin<Partial<Options> | undefined>
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
htmlPlugins() {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +53,6 @@ export const CreatedModifiedDate: QuartzTransformerPlugin<Partial<Options> | und
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
htmlPlugins() {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { QuartzTransformerPlugin } from "../types"
|
import { QuartzTransformerPlugin } from "../types"
|
||||||
import { relative, relativeToRoot, slugify, trimPathSuffix } from "../../path"
|
import { relativeToRoot, slugify, trimPathSuffix } from "../../path"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { visit } from 'unist-util-visit'
|
import { visit } from 'unist-util-visit'
|
||||||
import isAbsoluteUrl from "is-absolute-url"
|
import isAbsoluteUrl from "is-absolute-url"
|
||||||
@ -24,9 +24,6 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> =
|
|||||||
const opts = { ...defaultOptions, ...userOpts }
|
const opts = { ...defaultOptions, ...userOpts }
|
||||||
return {
|
return {
|
||||||
name: "LinkProcessing",
|
name: "LinkProcessing",
|
||||||
markdownPlugins() {
|
|
||||||
return []
|
|
||||||
},
|
|
||||||
htmlPlugins() {
|
htmlPlugins() {
|
||||||
return [() => {
|
return [() => {
|
||||||
return (tree, file) => {
|
return (tree, file) => {
|
||||||
@ -34,7 +31,8 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> =
|
|||||||
const transformLink = (target: string) => {
|
const transformLink = (target: string) => {
|
||||||
const targetSlug = slugify(decodeURI(target).trim())
|
const targetSlug = slugify(decodeURI(target).trim())
|
||||||
if (opts.markdownLinkResolution === 'relative' && !path.isAbsolute(targetSlug)) {
|
if (opts.markdownLinkResolution === 'relative' && !path.isAbsolute(targetSlug)) {
|
||||||
return './' + relative(curSlug, targetSlug)
|
// TODO
|
||||||
|
// return './' + relative(curSlug, targetSlug)
|
||||||
} else {
|
} else {
|
||||||
return './' + relativeToRoot(curSlug, targetSlug)
|
return './' + relativeToRoot(curSlug, targetSlug)
|
||||||
}
|
}
|
||||||
@ -77,9 +75,9 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform all images
|
// transform all other resources that may use links
|
||||||
if (
|
if (
|
||||||
node.tagName === 'img' &&
|
["img", "video", "audio", "iframe"].includes(node.tagName) &&
|
||||||
node.properties &&
|
node.properties &&
|
||||||
typeof node.properties.src === 'string'
|
typeof node.properties.src === 'string'
|
||||||
) {
|
) {
|
||||||
|
@ -3,6 +3,7 @@ import { QuartzTransformerPlugin } from "../types"
|
|||||||
import { Root, HTML, BlockContent, DefinitionContent, Code } from 'mdast'
|
import { Root, HTML, BlockContent, DefinitionContent, Code } from 'mdast'
|
||||||
import { findAndReplace } from "mdast-util-find-and-replace"
|
import { findAndReplace } from "mdast-util-find-and-replace"
|
||||||
import { slugify } from "../../path"
|
import { slugify } from "../../path"
|
||||||
|
import { slug as slugAnchor } from 'github-slugger'
|
||||||
import rehypeRaw from "rehype-raw"
|
import rehypeRaw from "rehype-raw"
|
||||||
import { visit } from "unist-util-visit"
|
import { visit } from "unist-util-visit"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
@ -94,14 +95,6 @@ const capitalize = (s: string): string => {
|
|||||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
|
|
||||||
const opts = { ...defaultOptions, ...userOpts }
|
|
||||||
return {
|
|
||||||
name: "ObsidianFlavoredMarkdown",
|
|
||||||
markdownPlugins() {
|
|
||||||
const plugins: PluggableList = []
|
|
||||||
if (opts.wikilinks) {
|
|
||||||
plugins.push(() => {
|
|
||||||
// Match wikilinks
|
// Match wikilinks
|
||||||
// !? -> optional embedding
|
// !? -> optional embedding
|
||||||
// \[\[ -> open brace
|
// \[\[ -> open brace
|
||||||
@ -109,6 +102,36 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
|
|||||||
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
|
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
|
||||||
// (|[^\[\]\|\#]+)? -> | then one or more non-special characters (alias)
|
// (|[^\[\]\|\#]+)? -> | then one or more non-special characters (alias)
|
||||||
const backlinkRegex = new RegExp(/!?\[\[([^\[\]\|\#]+)(#[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/, "g")
|
const backlinkRegex = new RegExp(/!?\[\[([^\[\]\|\#]+)(#[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/, "g")
|
||||||
|
|
||||||
|
// Match highlights
|
||||||
|
const highlightRegex = new RegExp(/==(.+)==/, "g")
|
||||||
|
|
||||||
|
// from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
|
||||||
|
const calloutRegex = new RegExp(/^\[\!(\w+)\]([+-]?)/)
|
||||||
|
|
||||||
|
export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
|
||||||
|
const opts = { ...defaultOptions, ...userOpts }
|
||||||
|
return {
|
||||||
|
name: "ObsidianFlavoredMarkdown",
|
||||||
|
textTransform(src) {
|
||||||
|
// pre-transform wikilinks (fix anchors to things that may contain illegal syntax e.g. codeblocks, latex)
|
||||||
|
if (opts.wikilinks) {
|
||||||
|
src = src.toString()
|
||||||
|
return src.replaceAll(backlinkRegex, (value, ...capture) => {
|
||||||
|
const [fp, rawHeader, rawAlias] = capture
|
||||||
|
const anchor = rawHeader?.trim().slice(1)
|
||||||
|
const displayAnchor = anchor ? `#${slugAnchor(anchor)}` : ""
|
||||||
|
const displayAlias = rawAlias ?? ""
|
||||||
|
const embedDisplay = value.startsWith("!") ? "!" : ""
|
||||||
|
return `${embedDisplay}[[${fp}${displayAnchor}${displayAlias}]]`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return src
|
||||||
|
},
|
||||||
|
markdownPlugins() {
|
||||||
|
const plugins: PluggableList = []
|
||||||
|
if (opts.wikilinks) {
|
||||||
|
plugins.push(() => {
|
||||||
return (tree: Root, _file) => {
|
return (tree: Root, _file) => {
|
||||||
findAndReplace(tree, backlinkRegex, (value: string, ...capture: string[]) => {
|
findAndReplace(tree, backlinkRegex, (value: string, ...capture: string[]) => {
|
||||||
const [fp, rawHeader, rawAlias] = capture
|
const [fp, rawHeader, rawAlias] = capture
|
||||||
@ -170,8 +193,6 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
|
|||||||
|
|
||||||
if (opts.highlight) {
|
if (opts.highlight) {
|
||||||
plugins.push(() => {
|
plugins.push(() => {
|
||||||
// Match highlights
|
|
||||||
const highlightRegex = new RegExp(/==(.+)==/, "g")
|
|
||||||
return (tree: Root, _file) => {
|
return (tree: Root, _file) => {
|
||||||
findAndReplace(tree, highlightRegex, (_value: string, ...capture: string[]) => {
|
findAndReplace(tree, highlightRegex, (_value: string, ...capture: string[]) => {
|
||||||
const [inner] = capture
|
const [inner] = capture
|
||||||
@ -186,8 +207,6 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
|
|||||||
|
|
||||||
if (opts.callouts) {
|
if (opts.callouts) {
|
||||||
plugins.push(() => {
|
plugins.push(() => {
|
||||||
// from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
|
|
||||||
const calloutRegex = new RegExp(/^\[\!(\w+)\]([+-]?)/)
|
|
||||||
return (tree: Root, _file) => {
|
return (tree: Root, _file) => {
|
||||||
visit(tree, "blockquote", (node) => {
|
visit(tree, "blockquote", (node) => {
|
||||||
if (node.children.length === 0) {
|
if (node.children.length === 0) {
|
||||||
|
@ -3,9 +3,6 @@ import rehypePrettyCode, { Options as CodeOptions } from "rehype-pretty-code"
|
|||||||
|
|
||||||
export const SyntaxHighlighting: QuartzTransformerPlugin = () => ({
|
export const SyntaxHighlighting: QuartzTransformerPlugin = () => ({
|
||||||
name: "SyntaxHighlighting",
|
name: "SyntaxHighlighting",
|
||||||
markdownPlugins() {
|
|
||||||
return []
|
|
||||||
},
|
|
||||||
htmlPlugins() {
|
htmlPlugins() {
|
||||||
return [[rehypePrettyCode, {
|
return [[rehypePrettyCode, {
|
||||||
theme: 'css-variables',
|
theme: 'css-variables',
|
||||||
@ -15,10 +12,12 @@ export const SyntaxHighlighting: QuartzTransformerPlugin = () => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onVisitHighlightedLine(node) {
|
onVisitHighlightedLine(node) {
|
||||||
|
node.properties.className ??= []
|
||||||
node.properties.className.push('highlighted')
|
node.properties.className.push('highlighted')
|
||||||
},
|
},
|
||||||
onVisitHighlightedWord(node) {
|
onVisitHighlightedWord(node) {
|
||||||
node.properties.className = ['word']
|
node.properties.className ??= []
|
||||||
|
node.properties.className.push('word')
|
||||||
},
|
},
|
||||||
} satisfies Partial<CodeOptions>]]
|
} satisfies Partial<CodeOptions>]]
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,6 @@ export const TableOfContents: QuartzTransformerPlugin<Partial<Options> | undefin
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
htmlPlugins() {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,10 @@ type OptionType = object | undefined
|
|||||||
export type QuartzTransformerPlugin<Options extends OptionType = undefined> = (opts?: Options) => QuartzTransformerPluginInstance
|
export type QuartzTransformerPlugin<Options extends OptionType = undefined> = (opts?: Options) => QuartzTransformerPluginInstance
|
||||||
export type QuartzTransformerPluginInstance = {
|
export type QuartzTransformerPluginInstance = {
|
||||||
name: string
|
name: string
|
||||||
markdownPlugins(): PluggableList
|
textTransform?: (src: string | Buffer) => string | Buffer
|
||||||
htmlPlugins(): PluggableList
|
markdownPlugins?: () => PluggableList
|
||||||
externalResources?(): Partial<StaticResources>
|
htmlPlugins?: () => PluggableList
|
||||||
|
externalResources?: () => Partial<StaticResources>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QuartzFilterPlugin<Options extends OptionType = undefined> = (opts?: Options) => QuartzFilterPluginInstance
|
export type QuartzFilterPlugin<Options extends OptionType = undefined> = (opts?: Options) => QuartzFilterPluginInstance
|
||||||
|
@ -21,8 +21,8 @@ export function createProcessor(transformers: QuartzTransformerPluginInstance[])
|
|||||||
let processor = unified().use(remarkParse)
|
let processor = unified().use(remarkParse)
|
||||||
|
|
||||||
// MD AST -> MD AST transforms
|
// MD AST -> MD AST transforms
|
||||||
for (const plugin of transformers) {
|
for (const plugin of transformers.filter(p => p.markdownPlugins)) {
|
||||||
processor = processor.use(plugin.markdownPlugins())
|
processor = processor.use(plugin.markdownPlugins!())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MD AST -> HTML AST
|
// MD AST -> HTML AST
|
||||||
@ -30,8 +30,8 @@ export function createProcessor(transformers: QuartzTransformerPluginInstance[])
|
|||||||
|
|
||||||
|
|
||||||
// HTML AST -> HTML AST transforms
|
// HTML AST -> HTML AST transforms
|
||||||
for (const plugin of transformers) {
|
for (const plugin of transformers.filter(p => p.htmlPlugins)) {
|
||||||
processor = processor.use(plugin.htmlPlugins())
|
processor = processor.use(plugin.htmlPlugins!())
|
||||||
}
|
}
|
||||||
|
|
||||||
return processor
|
return processor
|
||||||
@ -73,13 +73,18 @@ async function transpileWorkerScript() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createFileParser(baseDir: string, fps: string[], verbose: boolean) {
|
export function createFileParser(transformers: QuartzTransformerPluginInstance[], baseDir: string, fps: string[], verbose: boolean) {
|
||||||
return async (processor: QuartzProcessor) => {
|
return async (processor: QuartzProcessor) => {
|
||||||
const res: ProcessedContent[] = []
|
const res: ProcessedContent[] = []
|
||||||
for (const fp of fps) {
|
for (const fp of fps) {
|
||||||
try {
|
try {
|
||||||
const file = await read(fp)
|
const file = await read(fp)
|
||||||
|
|
||||||
|
// Text -> Text transforms
|
||||||
|
for (const plugin of transformers.filter(p => p.textTransform)) {
|
||||||
|
file.value = plugin.textTransform!(file.value)
|
||||||
|
}
|
||||||
|
|
||||||
// base data properties that plugins may use
|
// base data properties that plugins may use
|
||||||
file.data.slug = slugify(path.relative(baseDir, file.path))
|
file.data.slug = slugify(path.relative(baseDir, file.path))
|
||||||
file.data.filePath = fp
|
file.data.filePath = fp
|
||||||
@ -111,9 +116,8 @@ export async function parseMarkdown(transformers: QuartzTransformerPluginInstanc
|
|||||||
|
|
||||||
log.start(`Parsing input files using ${concurrency} threads`)
|
log.start(`Parsing input files using ${concurrency} threads`)
|
||||||
if (concurrency === 1) {
|
if (concurrency === 1) {
|
||||||
// single-thread
|
|
||||||
const processor = createProcessor(transformers)
|
const processor = createProcessor(transformers)
|
||||||
const parse = createFileParser(baseDir, fps, verbose)
|
const parse = createFileParser(transformers, baseDir, fps, verbose)
|
||||||
res = await parse(processor)
|
res = await parse(processor)
|
||||||
} else {
|
} else {
|
||||||
await transpileWorkerScript()
|
await transpileWorkerScript()
|
||||||
|
@ -6,6 +6,6 @@ const processor = createProcessor(transformers)
|
|||||||
|
|
||||||
// only called from worker thread
|
// only called from worker thread
|
||||||
export async function parseFiles(baseDir: string, fps: string[], verbose: boolean) {
|
export async function parseFiles(baseDir: string, fps: string[], verbose: boolean) {
|
||||||
const parse = createFileParser(baseDir, fps, verbose)
|
const parse = createFileParser(transformers, baseDir, fps, verbose)
|
||||||
return parse(processor)
|
return parse(processor)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user