UNPKG

@photogabble/eleventy-plugin-interlinker

Version:
95 lines (78 loc) 3.45 kB
/** * This rule will be looped through an inline token by markdown-it. * * @param {WikilinkParser} wikilinkParser * @returns {(function(*, *): (boolean|undefined))|*} */ export const wikilinkInlineRule = (wikilinkParser) => (state, silent) => { // Have we found the start of a WikiLink Embed `![[` if (state.src.charAt(state.pos) === '[' && state.src.charAt(state.pos + 1) !== '[') return false; // Not wikilink opening if (state.src.charAt(state.pos) === '!' && state.src.substring(state.pos, state.pos + 3) !== '![[') return false; // Not embed opening const matches = state.src.match(wikilinkParser.wikiLinkRegExp); if (!matches) return false; // We have found the start of a WikiLink (`[[`) or Embed (`![[`) // char at state.pos will be either `[` or `!`, need to walk through state.src until `]]` is encountered let pos = state.pos; let text = ''; let found = false; while (pos <= state.posMax) { text += state.src.charAt(pos); if (text.length > 2 && text.substring(text.length - 2) === ']]') { found = true; break; } pos++; } if (!found) return false; const wikiLink = wikilinkParser.linkCache.get(text); // By this time in the execution cycle the wikilink parser's cache should contain all // wikilinks, including those linking to a stub. In the unlikely case that it doesn't // we ignore the wikilink. if (!wikiLink) return false; if (!silent) { // The wikilink content is HTML generated by a "Resolving Function" lets make use of // the builtin html_inline render rule to display it. const token = state.push('html_inline', '', 0); token.content = wikiLink.content.trim(); } state.pos = state.pos + text.length; return true; }; /** * This rule is to catch Wikilink Embeds that are bookended by new lines e.g `\n![[test]]\n`, the inline rule * would only get the content within the new lines with the newlines themselves getting tokenised as a paragraph. * That was causing the bugs raised in issues #65 and #66. * * @param wikilinkParser * @return {(function(*, *, *, *): boolean)|*} */ export const wikilinkBlockRule = (wikilinkParser) => (state, startLine, endLine, silent) => { let pos = state.bMarks[startLine] + state.tShift[startLine] let max = state.eMarks[startLine] // if it's indented more than 3 spaces, it should be a code block if (state.sCount[startLine] - state.blkIndent >= 4) { return false } // This block rule only cares about Wiki Link embeds that are at a block level (on a single line bookended by `\n`) // therefore if the line text doesn't begin with `![[` we do not continue. let lineText = state.src.slice(pos, max); if (lineText.substring(0, 3) !== '![[') return false; const wikiLink = wikilinkParser.linkCache.get(lineText); if (!wikiLink) return false; if (!silent) { const token = state.push('html_block', '', 0); token.content = wikiLink.content.trim(); } // Block level Wikilink embeds should be on a single line, increment the line counter and continue. state.line++; return true; }; export const install = (md, wikilinkParser) => { md.inline.ruler.push('inline_wikilink', wikilinkInlineRule( wikilinkParser, )); md.block.ruler.before('heading', 'block_wikilink', wikilinkBlockRule( wikilinkParser, ), { // alt contains a list of rules which can be terminated by this one alt: ['paragraph', 'reference', 'blockquote'] }); }