UNPKG

react-refractor

Version:

Super-thin React wrapper for refractor (Syntax highlighting using VDOM)

207 lines (206 loc) 10.7 kB
import { jsx } from "react/jsx-runtime"; import { refractor } from "refractor/core"; import { filter } from "unist-util-filter"; import { visitParents } from "unist-util-visit-parents"; import { createElement } from "react"; var __defProp$2 = Object.defineProperty, __defProps$2 = Object.defineProperties, __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors, __getOwnPropSymbols$2 = Object.getOwnPropertySymbols, __hasOwnProp$2 = Object.prototype.hasOwnProperty, __propIsEnum$2 = Object.prototype.propertyIsEnumerable, __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __spreadValues$2 = (a, b) => { for (var prop in b || (b = {})) __hasOwnProp$2.call(b, prop) && __defNormalProp$2(a, prop, b[prop]); if (__getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(b)) __propIsEnum$2.call(b, prop) && __defNormalProp$2(a, prop, b[prop]); return a; }, __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b)); function addMarkers(ast, options) { const markers = options.markers.map((marker) => typeof marker == "number" ? { line: marker } : marker).sort((nodeA, nodeB) => nodeA.line - nodeB.line), numbered = lineNumberify(ast.children).nodes; return markers.length === 0 || numbered.length === 0 ? __spreadProps$2(__spreadValues$2({}, ast), { children: numbered }) : wrapLines(numbered, markers, options); } function lineNumberify(ast, context = { lineNumber: 1 }) { const resultNodes = []; return ast.reduce( (result, node) => { if (node.type === "doctype") return result; const lineStart = context.lineNumber; if (node.type === "text") { if (node.value.indexOf(` `) === -1) return setLineInfo(node, lineStart, lineStart), result.nodes.push(node), result; const lines = node.value.split(` `); for (let i = 0; i < lines.length; i++) { const lineNum = i === 0 ? context.lineNumber : ++context.lineNumber, text = { type: "text", value: i === lines.length - 1 ? lines[i] : `${lines[i]} ` }, withLineInfo = setLineInfo(text, lineNum, lineNum); result.nodes.push(withLineInfo); } return result.lineNumber = context.lineNumber, result; } if (node.type === "element" && node.children) { const processed = lineNumberify(node.children, context), firstChild = processed.nodes.find(isElementOrText), lastChild = processed.nodes.findLast(isElementOrText); return setLineInfo( node, firstChild ? getLineStart(firstChild, lineStart) : lineStart, lastChild ? getLineEnd(lastChild, lineStart) : lineStart ), node.children = processed.nodes, result.lineNumber = processed.lineNumber, result.nodes.push(node), result; } return result.nodes.push(node), result; }, { nodes: resultNodes, lineNumber: context.lineNumber } ); } function isElementOrText(node) { return node.type === "element" || node.type === "text"; } function getLineStart(node, fallbackLineStart = 1) { return node.data && typeof node.data.lineStart == "number" ? node.data.lineStart : fallbackLineStart; } function getLineEnd(node, fallbackLineEnd = 1) { return node.data && typeof node.data.lineEnd == "number" ? node.data.lineEnd : fallbackLineEnd; } function setLineInfo(node, lineStart, lineEnd) { return node.data || (node.data = {}), node.data.lineStart = lineStart, node.data.lineEnd = lineEnd, node; } function unwrapLine(markerLine, nodes) { const tree = { type: "root", children: nodes }, headMap = /* @__PURE__ */ new WeakMap(), lineMap = /* @__PURE__ */ new WeakMap(), tailMap = /* @__PURE__ */ new WeakMap(), cloned = []; function addCopy(map, node, ancestors) { cloned.push(node), ancestors.forEach((ancestor) => { map.has(ancestor) || (map.set(ancestor, Object.assign({}, ancestor, { children: [] })), ancestor !== tree && cloned.push(ancestor)); }); let i = ancestors.length; for (; i--; ) { const ancestor = map.get(ancestors[i]); if (!ancestor || !("children" in ancestor)) continue; const child = ancestors[i + 1], leaf = map.get(child) || node; ancestor.children.indexOf(leaf) === -1 && ancestor.children.push(leaf); } } visitParents(tree, (node, ancestors) => { if (!("children" in node || !isElementOrText(node))) { if (getLineStart(node) < markerLine) { addCopy(headMap, node, ancestors); return; } if (getLineStart(node) === markerLine) { addCopy(lineMap, node, ancestors); return; } getLineEnd(node) > markerLine && cloned.some((clone) => ancestors.includes(clone)) && addCopy(tailMap, node, ancestors); } }); const filtered = filter(tree, (node) => cloned.indexOf(node) === -1), getChildren = (map) => { const rootNode = map.get(tree); return rootNode ? (visitParents(rootNode, (leaf, ancestors) => { if (isElementOrText(leaf) && "children" in leaf) { setLineInfo(leaf, 0, 0); return; } ancestors.forEach((ancestor) => { setLineInfo( ancestor, Math.max(getLineStart(ancestor), getLineStart(leaf)), Math.max(getLineEnd(ancestor), getLineEnd(leaf)) ); }); }), rootNode.children) : []; }; return [ ...getChildren(headMap), ...getChildren(lineMap), ...getChildren(tailMap), ...filtered ? filtered.children : [] ]; } function wrapBatch(children, marker, options) { const className = marker.className || "refractor-marker", baseData = { lineStart: marker.line, lineEnd: getLineEnd(children[children.length - 1]), isMarker: !0 }; return { type: "element", tagName: "div", data: marker.component ? __spreadProps$2(__spreadValues$2({}, baseData), { component: marker.component, markerProperties: options }) : baseData, properties: { className }, children }; } function wrapLines(treeNodes, markers, options) { const ast = markers.reduce( (acc, marker) => unwrapLine(marker.line, acc), treeNodes ), wrapped = []; let astIndex = 0; for (let m = 0; m < markers.length; m++) { const marker = markers[m]; for (let node = ast[astIndex]; node && getLineEnd(node) < marker.line; node = ast[++astIndex]) wrapped.push(node); const batch = []; for (let node = ast[astIndex]; node && getLineEnd(node) === marker.line; node = ast[++astIndex]) node.type !== "doctype" && batch.push(node); batch.length > 0 && wrapped.push(wrapBatch(batch, marker, options)); } for (; astIndex < ast.length; ) wrapped.push(ast[astIndex++]); return { type: "root", children: wrapped }; } var __defProp$1 = Object.defineProperty, __defProps$1 = Object.defineProperties, __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors, __getOwnPropSymbols$1 = Object.getOwnPropertySymbols, __hasOwnProp$1 = Object.prototype.hasOwnProperty, __propIsEnum$1 = Object.prototype.propertyIsEnumerable, __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __spreadValues$1 = (a, b) => { for (var prop in b || (b = {})) __hasOwnProp$1.call(b, prop) && __defNormalProp$1(a, prop, b[prop]); if (__getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(b)) __propIsEnum$1.call(b, prop) && __defNormalProp$1(a, prop, b[prop]); return a; }, __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b)); function mapWithDepth(depth) { return function(child, i) { return mapChild(child, i, depth); }; } function mapChild(child, i, depth) { if (child.type === "doctype") return null; if (!("tagName" in child)) return child.value; let className = ""; typeof child.properties < "u" && (className = Array.isArray(child.properties.className) ? child.properties.className.join(" ") : `${child.properties.className}`); const key = `fract-${depth}-${i}`, children = child.children && child.children.map(mapWithDepth(depth + 1)); return isReactRefractorMarkerDataWithComponent(child.data) ? createElement( child.data.component, __spreadProps$1(__spreadValues$1(__spreadValues$1({ key }, child.properties), child.data.markerProperties), { className }), children ) : createElement(child.tagName, { key, className }, children); } function isReactRefractorMarkerDataWithComponent(data) { return typeof data == "object" && data !== null && "component" in data && "markerProperties" in data; } var __defProp = Object.defineProperty, __defProps = Object.defineProperties, __getOwnPropDescs = Object.getOwnPropertyDescriptors, __getOwnPropSymbols = Object.getOwnPropertySymbols, __hasOwnProp = Object.prototype.hasOwnProperty, __propIsEnum = Object.prototype.propertyIsEnumerable, __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value, __spreadValues = (a, b) => { for (var prop in b || (b = {})) __hasOwnProp.call(b, prop) && __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) __propIsEnum.call(b, prop) && __defNormalProp(a, prop, b[prop]); return a; }, __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); const DEFAULT_CLASSNAME = "refractor"; function Refractor(props) { const className = props.className || DEFAULT_CLASSNAME, langClassName = `language-${props.language}`, codeProps = { className: langClassName }, preClass = [className, langClassName].filter(Boolean).join(" "); if (props.inline && (codeProps.style = { display: "inline" }, codeProps.className = className), props.plainText) { const code2 = /* @__PURE__ */ jsx("code", __spreadProps(__spreadValues({}, codeProps), { children: props.value })); return props.inline ? code2 : /* @__PURE__ */ jsx("pre", { className: preClass, children: code2 }); } let ast = refractor.highlight(props.value, props.language); props.markers && props.markers.length > 0 && (ast = addMarkers(ast, { markers: props.markers })); const value = ast.children.length === 0 ? props.value : ast.children.map(mapWithDepth(0)), code = /* @__PURE__ */ jsx("code", __spreadProps(__spreadValues({}, codeProps), { children: value })); return props.inline ? code : /* @__PURE__ */ jsx("pre", { className: preClass, children: code }); } const registerLanguage = (lang) => refractor.register(lang), hasLanguage = (lang) => refractor.registered(lang); export { Refractor, hasLanguage, registerLanguage }; //# sourceMappingURL=index.js.map