From 60bdef9c54d3ee73745f5be2d2eaa3bab67af7ed Mon Sep 17 00:00:00 2001 From: Paul Gottschling Date: Mon, 18 Nov 2024 12:58:34 -0500 Subject: [PATCH] Clean up the replacement loop ...but return the logic to the original. No longer ranging over the children of a code snippet since HLJS spans can be nested. --- server/rehype-hljs-var.ts | 159 ++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 92 deletions(-) diff --git a/server/rehype-hljs-var.ts b/server/rehype-hljs-var.ts index ad31f9b236..22da488da1 100644 --- a/server/rehype-hljs-var.ts +++ b/server/rehype-hljs-var.ts @@ -44,7 +44,6 @@ export const rehypeVarInHLJS = ( // We only visit text nodes inside code snippets if ( node.type !== "text" || - !parent || !parent.hasOwnProperty("tagName") || (parent as Element).tagName !== "code" ) { @@ -87,109 +86,85 @@ export const rehypeVarInHLJS = ( // inserting these as HTML AST nodes. visit(root, undefined, (node: Node, index: number, parent: Parent) => { const el = node as Element; - // We only visit code fences - if (!el || el.tagName !== "code") { + // We expect the element to have a single text node + if ( + el.type !== "element" || + el.children.length !== 1 || + el.children[0].type !== "text" + ) { return [CONTINUE]; } + const hljsSpanValue = (el.children[0] as Text).value; - for (let i = 0; i < el.children.length; i++) { - if ( - el.children[i].type !== "text" && - el.children[i].tagName !== "span" - ) { - continue; - } - - let textValue; - if ((el.children[i] as Element).tagName == "span") { - textValue = (el.children[i].children[0] as Text).value; - } else { - textValue = el.children[i].value; - } - if (!textValue) { - continue; - } + // This is an hljs span with only the placeholder as its child. + // We don't need the span, so replace it with the original Var. + if (placeholdersToVars[hljsSpanValue]) { + (parent as any).children[index] = placeholdersToVars[hljsSpanValue]; + return [CONTINUE]; + } - // This is an hljs span with only the placeholder as its child. - // We don't need the span, so replace it with the original Var. - if (placeholdersToVars[textValue]) { - el.children[i] = placeholdersToVars[textValue]; - continue; - } + const placeholders = Array.from( + hljsSpanValue.matchAll(new RegExp(placeholderPattern, "g")) + ); - const placeholders = Array.from( - textValue.matchAll(new RegExp(placeholderPattern, "g")) - ); + // No placeholders to recover, so there's nothing more to do. + if (placeholders.length == 0) { + return [CONTINUE]; + } - // No placeholders to recover, so there's nothing more to do. - if (placeholders.length == 0) { + // The element's text includes one or more Vars among other content, so + // we need to replace the span with a series of spans separated by + // Vars. + let newChildren: Array = []; + + // Assemble a map of indexes to their corresponding placeholders so we + // can tell whether a given index falls within a placeholder. + const placeholderIndices = new Map(); + placeholders.forEach((p) => { + placeholderIndices.set(p.index, p[0]); + }); + + let valueIdx = 0; + while (valueIdx < hljsSpanValue.length) { + // The current index is in a placeholder, so add the original Var + // component to newChildren. + if (placeholderIndices.has(valueIdx)) { + const placeholder = placeholderIndices.get(valueIdx); + valueIdx += placeholder.length; + newChildren.push(placeholdersToVars[placeholder]); continue; } + // The current index is outside a placeholder, so assemble a text or + // span node and push that to newChildren. + let textVal = ""; + while ( + !placeholderIndices.has(valueIdx) && + valueIdx < hljsSpanValue.length + ) { + textVal += hljsSpanValue[valueIdx]; + valueIdx++; + } - // The element's text includes one or more Vars among other content, so - // we need to replace the span with a series of spans separated by - // Vars. Advance through the value we're splitting. If the current - // index lands inside a placeholder, add a Var tag to an array of new - // children. Otherwise add a text node or a span, depending on the - // value's parent. - let newChildren: Array = []; - - // Assemble a map of indexes to their corresponding placeholders so we - // can tell whether a given index falls within a placeholder. - const placeholderIndices = new Map(); - placeholders.forEach((p) => { - placeholderIndices.set(p.index, p[0]); - }); - - let valueIdx = 0; - while (valueIdx < textValue.length) { - // The current index is in a placeholder, so add the original Var - // component to newChildren. - if (placeholderIndices.has(valueIdx)) { - const placeholder = placeholderIndices.get(valueIdx); - console.log("placeholder:", placeholder); - valueIdx += placeholder.length; - newChildren.push(placeholdersToVars[placeholder]); - continue; - } - // The current index is outside a placeholder, so assemble a text or - // span node and push that to newChildren. - let textVal = ""; - while ( - !placeholderIndices.has(valueIdx) && - valueIdx < textValue.length - ) { - textVal += textValue[valueIdx]; - valueIdx++; - } - if (el.children[i].type == "text") { - newChildren.push({ + newChildren.push({ + tagName: "span", + type: "element", + properties: el.properties, + children: [ + { type: "text", value: textVal, - }); - continue; - } - newChildren.push({ - tagName: "span", - type: "element", - properties: el.children[i].properties, - children: [ - { - type: "text", - value: textVal, - }, - ], - }); - } - - // Delete the current span and replace it with the new children. - (parent.children as Array).splice( - index, - 1, - ...newChildren - ); + }, + ], + }); } - return [CONTINUE]; + + // Delete the current span and replace it with the new children. + (parent.children as Array).splice( + index, + 1, + ...newChildren + ); + return [SKIP, index + newChildren.length]; }); }; };