UNPKG

@wordpress/element

Version:
173 lines (172 loc) 4.96 kB
// packages/element/src/create-interpolate-element.ts import { createElement, cloneElement, Fragment, isValidElement } from "./react.mjs"; var indoc; var offset; var output; var stack; var tokenizer = /<(\/)?(\w+)\s*(\/)?>/g; function createFrame(element, tokenStart, tokenLength, prevOffset, leadingTextStart) { return { element, tokenStart, tokenLength, prevOffset, leadingTextStart, children: [] }; } function createInterpolateElement(interpolatedString, conversionMap) { indoc = interpolatedString; offset = 0; output = []; stack = []; tokenizer.lastIndex = 0; if (!isValidConversionMap(conversionMap)) { throw new TypeError( "The conversionMap provided is not valid. It must be an object with values that are React Elements" ); } do { } while (proceed(conversionMap)); return createElement(Fragment, null, ...output); } var isValidConversionMap = (conversionMap) => { const isObject = typeof conversionMap === "object" && conversionMap !== null; const values = isObject && Object.values(conversionMap); return isObject && values.length > 0 && values.every((element) => isValidElement(element)); }; function proceed(conversionMap) { const next = nextToken(); const [tokenType, name, startOffset, tokenLength] = next; const stackDepth = stack.length; const leadingTextStart = startOffset > offset ? offset : null; if (name && !conversionMap[name]) { addText(); return false; } switch (tokenType) { case "no-more-tokens": if (stackDepth !== 0) { const { leadingTextStart: stackLeadingText, tokenStart } = stack.pop(); output.push(indoc.substr(stackLeadingText, tokenStart)); } addText(); return false; case "self-closed": if (0 === stackDepth) { if (null !== leadingTextStart) { output.push( indoc.substr( leadingTextStart, startOffset - leadingTextStart ) ); } output.push(conversionMap[name]); offset = startOffset + tokenLength; return true; } addChild( createFrame(conversionMap[name], startOffset, tokenLength) ); offset = startOffset + tokenLength; return true; case "opener": stack.push( createFrame( conversionMap[name], startOffset, tokenLength, startOffset + tokenLength, leadingTextStart ) ); offset = startOffset + tokenLength; return true; case "closer": if (1 === stackDepth) { closeOuterElement(startOffset); offset = startOffset + tokenLength; return true; } const stackTop = stack.pop(); const text = indoc.substr( stackTop.prevOffset, startOffset - stackTop.prevOffset ); stackTop.children.push(text); stackTop.prevOffset = startOffset + tokenLength; const frame = createFrame( stackTop.element, stackTop.tokenStart, stackTop.tokenLength, startOffset + tokenLength ); frame.children = stackTop.children; addChild(frame); offset = startOffset + tokenLength; return true; default: addText(); return false; } } function nextToken() { const matches = tokenizer.exec(indoc); if (null === matches) { return ["no-more-tokens"]; } const startedAt = matches.index; const [match, isClosing, name, isSelfClosed] = matches; const length = match.length; if (isSelfClosed) { return ["self-closed", name, startedAt, length]; } if (isClosing) { return ["closer", name, startedAt, length]; } return ["opener", name, startedAt, length]; } function addText() { const length = indoc.length - offset; if (0 === length) { return; } output.push(indoc.substr(offset, length)); } function addChild(frame) { const { element, tokenStart, tokenLength, prevOffset, children } = frame; const parent = stack[stack.length - 1]; const text = indoc.substr( parent.prevOffset, tokenStart - parent.prevOffset ); if (text) { parent.children.push(text); } parent.children.push(cloneElement(element, null, ...children)); parent.prevOffset = prevOffset ? prevOffset : tokenStart + tokenLength; } function closeOuterElement(endOffset) { const { element, leadingTextStart, prevOffset, tokenStart, children } = stack.pop(); const text = endOffset ? indoc.substr(prevOffset, endOffset - prevOffset) : indoc.substr(prevOffset); if (text) { children.push(text); } if (null !== leadingTextStart) { output.push( indoc.substr(leadingTextStart, tokenStart - leadingTextStart) ); } output.push(cloneElement(element, null, ...children)); } var create_interpolate_element_default = createInterpolateElement; export { create_interpolate_element_default as default }; //# sourceMappingURL=create-interpolate-element.mjs.map