UNPKG

rehype-custom-component

Version:

Rehype plugin to transform custom components into to handle with React

56 lines (55 loc) 1.72 kB
// src/index.ts import { visit } from "unist-util-visit"; function rehypeCustomComponent({ tagName = "custom-component", matchName = "CustomComponent" } = {}) { const REGEX = /<MATCH\s+([^>]*?)\/>/; const CC_REGEX = new RegExp(REGEX.source.replace("MATCH", matchName), "gs"); const processTextNode = (text) => { const nodes = []; let lastIndex = 0; for (const match of text.matchAll(CC_REGEX)) { const [fullMatch, attributesString] = match; const startIndex = match.index ?? 0; if (startIndex > lastIndex) { nodes.push({ type: "text", value: text.slice(lastIndex, startIndex) }); } const properties = [...attributesString.matchAll(/(\w+)(?:=(?:"([^"]*)"|([^\s>]+)))?/g)].reduce((acc, [, attrName, quotedValue, unquotedValue]) => ({ ...acc, [attrName]: quotedValue ?? unquotedValue ?? true }), {}); nodes.push({ type: "element", tagName, properties, children: [] }); lastIndex = startIndex + fullMatch.length; } if (lastIndex < text.length) { nodes.push({ type: "text", value: text.slice(lastIndex) }); } return nodes.length > 0 ? nodes : [{ type: "text", value: text }]; }; const onVisit = (node, index, parent) => { if (!parent || index === void 0 || !("children" in parent)) return; const processed = processTextNode(node.value); if (processed.length > 1 || processed[0]?.type === "element") { parent.children.splice(index, 1, ...processed); } }; return (tree) => { visit(tree, "text", onVisit); visit(tree, "raw", onVisit); }; } export { rehypeCustomComponent as default };