diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2024-03-01 07:34:13 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2024-03-31 17:59:30 -0300 |
commit | fb9d1e9721209c842d186308ba30c9f3201bed4e (patch) | |
tree | 8d625db0782f717ed933983abce601778c607af0 /src/util | |
parent | 4ce32acb7e55d2299e086d67d571fc4ebf87f10b (diff) |
replacer: parse external links as nodes w/ marked's regex
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/replacer.js | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/util/replacer.js b/src/util/replacer.js index 0a3117ed..f37fb5b5 100644 --- a/src/util/replacer.js +++ b/src/util/replacer.js @@ -5,6 +5,8 @@ // function, which converts nodes parsed here into actual HTML, links, etc // for embedding in a wiki webpage. +import * as marked from 'marked'; + import * as html from '#html'; import {escapeRegex, typeAppearance} from '#sugar'; @@ -580,6 +582,60 @@ export function postprocessHeadings(inputNodes) { return outputNodes; } +export function postprocessExternalLinks(inputNodes) { + const outputNodes = []; + + for (const node of inputNodes) { + if (node.type !== 'text') { + outputNodes.push(node); + continue; + } + + const plausibleLinkRegexp = /\[.*\)/g; + + let textContent = ''; + + let plausibleMatch = null, parseFrom = 0; + while (plausibleMatch = plausibleLinkRegexp.exec(node.data)) { + textContent += node.data.slice(parseFrom, plausibleMatch.index); + + const definiteMatch = + marked.Lexer.rules.inline.link.exec( + node.data.slice(plausibleMatch.index)); + + if (definiteMatch) { + const {1: label, 2: href} = definiteMatch; + + // Split the containing text node into two - the second of these will + // be added after iterating over matches, or by the next match. + if (textContent.length) { + outputNodes.push({type: 'text', data: textContent}); + textContent = ''; + } + + outputNodes.push({type: 'external-link', data: {label, href}}); + + parseFrom = + plausibleMatch.index + + definiteMatch.index + + definiteMatch[0].length; + } else { + parseFrom = plausibleMatch.index; + } + } + + if (parseFrom !== node.data.length) { + textContent += node.data.slice(parseFrom); + } + + if (textContent.length) { + outputNodes.push({type: 'text', data: textContent}); + } + } + + return outputNodes; +} + export function parseInput(input) { if (typeof input !== 'string') { throw new TypeError(`Expected input to be string, got ${typeAppearance(input)}`); @@ -589,6 +645,7 @@ export function parseInput(input) { let output = parseNodes(input, 0); output = postprocessImages(output); output = postprocessHeadings(output); + output = postprocessExternalLinks(output); return output; } catch (errorNode) { if (errorNode.type !== 'error') { |