UNPKG

@helpwave/hightide

Version:

helpwave's component and theming library

1 lines 13.3 kB
{"version":3,"sources":["../../../src/components/layout-and-navigation/MarkdownInterpreter.tsx"],"sourcesContent":["type ASTNodeModifierType =\n 'none'\n | 'italic'\n | 'bold'\n | 'underline'\n | 'font-space'\n | 'primary'\n | 'secondary'\n | 'warn'\n | 'positive'\n | 'negative'\n\nconst astNodeInserterType = ['helpwave', 'newline'] as const\ntype ASTNodeInserterType = typeof astNodeInserterType[number]\ntype ASTNodeDefaultType = 'text'\n\ntype ASTNode = {\n type: ASTNodeModifierType,\n children: ASTNode[],\n} | {\n type: ASTNodeInserterType,\n} | {\n type: ASTNodeDefaultType,\n text: string,\n}\n\nexport type ASTNodeInterpreterProps = {\n node: ASTNode,\n isRoot?: boolean,\n className?: string,\n}\nexport const ASTNodeInterpreter = ({\n node,\n isRoot = false,\n className = '',\n }: ASTNodeInterpreterProps) => {\n switch (node.type) {\n case 'newline':\n return <br/>\n case 'text':\n return isRoot ? <span className={className}>{node.text}</span> : node.text\n case 'helpwave':\n return (<span className=\"font-bold font-space no-underline\">helpwave</span>)\n case 'none':\n return isRoot ? (\n <span className={className}>{node.children.map((value, index) => (\n <ASTNodeInterpreter key={index}\n node={value}/>\n ))}</span>\n ) :\n <>{node.children.map((value, index) => <ASTNodeInterpreter key={index} node={value}/>)}</>\n case 'bold':\n return <b>{node.children.map((value, index) => <ASTNodeInterpreter key={index} node={value}/>)}</b>\n case 'italic':\n return <i>{node.children.map((value, index) => <ASTNodeInterpreter key={index} node={value}/>)}</i>\n case 'underline':\n return (<u>{node.children.map((value, index) => (<ASTNodeInterpreter key={index} node={value}/>))}</u>)\n case 'font-space':\n return (\n <span className=\"font-space\">{node.children.map((value, index) => (\n <ASTNodeInterpreter key={index}\n node={value}/>\n ))}</span>\n )\n case 'primary':\n return (\n <span className=\"text-primary\">{node.children.map((value, index) => (\n <ASTNodeInterpreter\n key={index} node={value}/>\n ))}</span>\n )\n case 'secondary':\n return (\n <span className=\"text-secondary\">{node.children.map((value, index) => (\n <ASTNodeInterpreter\n key={index} node={value}/>\n ))}</span>\n )\n case 'warn':\n return (\n <span className=\"text-warning\">{node.children.map((value, index) => (\n <ASTNodeInterpreter\n key={index} node={value}/>\n ))}</span>\n )\n case 'positive':\n return (\n <span className=\"text-positive\">{node.children.map((value, index) => (\n <ASTNodeInterpreter\n key={index} node={value}/>\n ))}</span>\n )\n case 'negative':\n return (\n <span className=\"text-negative\">{node.children.map((value, index) => (\n <ASTNodeInterpreter\n key={index} node={value}/>\n ))}</span>\n )\n default:\n return null\n }\n}\n\nconst modifierIdentifierMapping = [\n { id: 'i', name: 'italic' },\n { id: 'b', name: 'bold' },\n { id: 'u', name: 'underline' },\n { id: 'space', name: 'font-space' },\n { id: 'primary', name: 'primary' },\n { id: 'secondary', name: 'secondary' },\n { id: 'warn', name: 'warn' },\n { id: 'positive', name: 'positive' },\n { id: 'negative', name: 'negative' },\n] as const\n\nconst inserterIdentifierMapping = [\n { id: 'helpwave', name: 'helpwave' },\n { id: 'newline', name: 'newline' }\n] as const\nconst parseMarkdown = (\n text: string,\n commandStart: string = '\\\\',\n open: string = '{',\n close: string = '}'\n): ASTNode => {\n let start = text.indexOf(commandStart)\n const children: ASTNode[] = []\n\n // parse the text step by step\n while (text !== '') {\n if (start === -1) {\n children.push({\n type: 'text',\n text\n })\n break\n }\n children.push(parseMarkdown(text.substring(0, start)))\n text = text.substring(start)\n if (text.length <= 1) {\n children.push({\n type: 'text',\n text\n })\n text = ''\n continue\n }\n const simpleReplace = [commandStart, open, close]\n if (simpleReplace.some(value => text[1] === value)) {\n children.push({\n type: 'text',\n text: simpleReplace.find(value => text[1] === value)!\n })\n text = text.substring(2)\n start = text.indexOf(commandStart)\n continue\n }\n const inserter = inserterIdentifierMapping.find(value => text.substring(1).startsWith(value.id))\n if (inserter) {\n children.push({\n type: inserter.name,\n })\n text = text.substring(inserter.id.length + 1)\n start = text.indexOf(commandStart)\n continue\n }\n const modifier = modifierIdentifierMapping.find(value => text.substring(1).startsWith(value.id))\n if (modifier) {\n // check brackets\n if (text[modifier.id.length + 1] !== open) {\n children.push({\n type: 'text',\n text: text.substring(0, modifier.id.length + 1)\n })\n text = text.substring(modifier.id.length + 2)\n start = text.indexOf(commandStart)\n continue\n }\n let closing = -1\n let index = modifier.id.length + 2\n let counter = 1\n let escaping = false\n while (index < text.length) {\n if (text[index] === open && !escaping) {\n counter++\n }\n if (text[index] === close && !escaping) {\n counter--\n if (counter === 0) {\n closing = index\n break\n }\n }\n escaping = text[index] === commandStart\n index++\n }\n\n if (closing !== -1) {\n children.push({\n type: modifier.name,\n children: [parseMarkdown(text.substring(modifier.id.length + 2, closing))]\n })\n text = text.substring(closing + 1)\n start = text.indexOf(commandStart)\n continue\n }\n }\n // nothing could be applied to command start\n children.push({\n type: 'text',\n text: text[0]!\n })\n text = text.substring(1)\n start = text.indexOf(commandStart)\n }\n\n return {\n type: 'none',\n children\n }\n}\n\nconst optimizeTree = (node: ASTNode) => {\n if (node.type === 'text') {\n return !node.text ? undefined : node\n }\n if (astNodeInserterType.some(value => value === node.type)) {\n return node\n }\n\n const currentNode = node as\n { type: ASTNodeModifierType, children: ASTNode[] }\n\n if (currentNode.children.length === 0) {\n return undefined\n }\n\n let children: ASTNode[] = []\n for (let i = 0; i < currentNode.children.length; i++) {\n const child = optimizeTree(currentNode.children[i]!)\n if (!child) {\n continue\n }\n if (child.type === 'none') {\n children.push(...child.children)\n } else {\n children.push(child)\n }\n }\n\n currentNode.children = children\n children = []\n\n for (let i = 0; i < currentNode.children.length; i++) {\n const child = currentNode.children[i]!\n if (child) {\n if (child.type === 'text' && children[children.length - 1]?.type === 'text') {\n (children[children.length - 1]! as { type: ASTNodeDefaultType, text: string }).text += child.text\n } else {\n children.push(child)\n }\n }\n }\n currentNode.children = children\n return currentNode\n}\n\nexport type MarkdownInterpreterProps = {\n text: string,\n className?: string,\n}\n\nexport const MarkdownInterpreter = ({ text, className }: MarkdownInterpreterProps) => {\n const tree = parseMarkdown(text)\n const optimizedTree = optimizeTree(tree)!\n return <ASTNodeInterpreter node={optimizedTree} isRoot={true} className={className}/>\n}\n"],"mappings":"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","names":[]}