From 7e22c38f8eaf8d9e3ae3a5b25f4611a5f4503b26 Mon Sep 17 00:00:00 2001 From: Emile Bangma Date: Mon, 18 Mar 2024 02:16:04 +0100 Subject: [PATCH] fix(wikilinks): handle wikilinks inside tables seperately from other wikilinks (#1005) * fix(wikilinks): handle wikilinks inside tables seperately from other wikilinks * Prettier * Cleaned up duplicate code * Remove test logging * Refactored and fixed for non-aliased wikilinks inside table * Updated naming and comments * Updated comment of wikilink regex * Updated regex to match previous formatting * Match table even if EOF is immediately after the table. * Update quartz/plugins/transformers/ofm.ts Co-authored-by: Jacky Zhao * Change table escape replace to non-regex version * Prettier * Prettier --------- Co-authored-by: Jacky Zhao --- quartz/plugins/transformers/ofm.ts | 53 ++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index 50371c87a..3ee6480ca 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -99,17 +99,27 @@ export const externalLinkRegex = /^https?:\/\//i export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g") -// (\|[^\|\[\n]*)? -> optional check if wikilink is inside a table cell -// !? -> 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) -// ([^\|\n]*\|)? -> optional check if wikilink is inside a table cell +// !? -> optional embedding +// \[\[ -> open brace +// ([^\[\]\|\#]+) -> one or more non-special characters ([,],|, or #) (name) +// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link) +// (\\?\|[^\[\]\#]+)? -> optional escape \ then | then one or more non-special characters (alias) export const wikilinkRegex = new RegExp( - /(\|[^\|\[\n]*)?!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]([^\|\n]*\|)?/, + /!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/, "g", ) + +// ^\|([^\n])+\|\n(\|) -> matches the header row +// ( ?:?-{3,}:? ?\|)+ -> matches the header row separator +// (\|([^\n])+\|\n)+ -> matches the body rows +export const tableRegex = new RegExp( + /^\|([^\n])+\|\n(\|)( ?:?-{3,}:? ?\|)+\n(\|([^\n])+\|\n?)+/, + "gm", +) + +// matches any wikilink, only used for escaping wikilinks inside tables +export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\])/, "g") + const highlightRegex = new RegExp(/==([^=]+)==/, "g") const commentRegex = new RegExp(/%%[\s\S]*?%%/, "g") // from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts @@ -171,27 +181,34 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin src = src.toString() } + // replace all wikilinks inside a table first + src = src.replace(tableRegex, (value) => { + // escape all aliases and headers in wikilinks inside a table + return value.replace(tableWikilinkRegex, (value, ...capture) => { + const [raw]: (string | undefined)[] = capture + let escaped = raw ?? "" + escaped = escaped.replace("#", "\\#") + escaped = escaped.replace("|", "\\|") + + return escaped + }) + }) + + // replace all other wikilinks src = src.replace(wikilinkRegex, (value, ...capture) => { - const [rawTablePre, rawFp, rawHeader, rawAlias, rawTablePost]: (string | undefined)[] = - capture + const [rawFp, rawHeader, rawAlias]: (string | undefined)[] = capture const fp = rawFp ?? "" const anchor = rawHeader?.trim().replace(/^#+/, "") const blockRef = Boolean(anchor?.startsWith("^")) ? "^" : "" const displayAnchor = anchor ? `#${blockRef}${slugAnchor(anchor)}` : "" - let displayAlias = rawAlias ?? rawHeader?.replace("#", "|") ?? "" + const displayAlias = rawAlias ?? rawHeader?.replace("#", "|") ?? "" const embedDisplay = value.startsWith("!") ? "!" : "" if (rawFp?.match(externalLinkRegex)) { return `${embedDisplay}[${displayAlias.replace(/^\|/, "")}](${rawFp})` } - // transform `[[note#^block_ref|^block_ref]]` to `[[note#^block_ref\|^block_ref]]`, - // when the wikilink with alias is inside a table. - if (displayAlias && displayAlias.startsWith("|") && rawTablePre && rawTablePost) { - displayAlias = `\\${displayAlias}` - } - return `${embedDisplay}[[${fp}${displayAnchor}${displayAlias}]]` }) } @@ -211,7 +228,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin replacements.push([ wikilinkRegex, (value: string, ...capture: string[]) => { - let [_rawTablePre, rawFp, rawHeader, rawAlias, _rawTablePost] = capture + let [rawFp, rawHeader, rawAlias] = capture const fp = rawFp?.trim() ?? "" const anchor = rawHeader?.trim() ?? "" const alias = rawAlias?.slice(1).trim()