UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

1 lines 7.77 kB
{"version":3,"file":"remarkVideo.mjs","names":["properties: Record<string, string>"],"sources":["../../../src/Markdown/plugins/remarkVideo.ts"],"sourcesContent":["import { visit } from 'unist-util-visit';\n\ninterface RemarkVideoOptions {\n /**\n * 支持的视频标签名,默认为 ['video']\n */\n videoTags?: string[];\n}\n\n/**\n * Remark plugin to handle <video> tags in markdown text\n * This plugin converts <video> tags to proper video elements\n * without requiring allowHtml to be enabled\n *\n * @example\n * <video src=\"https://example.com/video.mp4\" />\n * <video src=\"https://example.com/video.mp4\" controls width=\"400\" height=\"300\" />\n */\nexport const remarkVideo = (options: RemarkVideoOptions = {}) => {\n const { videoTags = ['video'] } = options;\n\n return (tree: any) => {\n // 处理HTML节点中的video标签\n visit(tree, 'html', (node, index = 0, parent) => {\n if (!node.value || typeof node.value !== 'string') return;\n\n for (const tagName of videoTags) {\n // 匹配自闭合的video标签,支持属性\n const selfClosingPattern = `^<${tagName}([^>]*?)\\\\s*\\\\/?\\\\s*>$`;\n const selfClosingMatch = node.value.trim().match(new RegExp(selfClosingPattern, 'i'));\n\n if (selfClosingMatch) {\n const attributesStr = selfClosingMatch[1]?.trim() || '';\n\n // 解析属性\n const properties: Record<string, string> = {};\n const attrRegex = /(\\w+)=[\"']([^\"']*?)[\"']/g;\n let attrMatch;\n\n while ((attrMatch = attrRegex.exec(attributesStr)) !== null) {\n properties[attrMatch[1]] = attrMatch[2];\n }\n\n // 创建video节点\n const newNode = {\n children: [],\n data: {\n hName: tagName,\n hProperties: properties,\n },\n type: tagName,\n };\n\n // 替换html节点为video节点\n parent.children.splice(index, 1, newNode);\n return index;\n }\n\n // 匹配成对的video标签(虽然不太常见,但也支持)\n const pairedPattern = `^<${tagName}([^>]*?)>(.*?)<\\\\/${tagName}>$`;\n const pairedMatch = node.value.trim().match(new RegExp(pairedPattern, 'is'));\n\n if (pairedMatch) {\n const attributesStr = pairedMatch[1]?.trim() || '';\n const content = pairedMatch[2] || '';\n\n // 解析属性\n const properties: Record<string, string> = {};\n const attrRegex = /(\\w+)=[\"']([^\"']*?)[\"']/g;\n let attrMatch;\n\n while ((attrMatch = attrRegex.exec(attributesStr)) !== null) {\n properties[attrMatch[1]] = attrMatch[2];\n }\n\n // 创建video节点\n const newNode = {\n children: content ? [{ type: 'text', value: content }] : [],\n data: {\n hName: tagName,\n hProperties: properties,\n },\n type: tagName,\n };\n\n // 替换html节点为video节点\n parent.children.splice(index, 1, newNode);\n return index;\n }\n }\n });\n\n // 处理文本节点中的video标签(HTML实体编码形式)\n visit(tree, 'text', (node, index = 0, parent) => {\n if (!node.value || typeof node.value !== 'string') return;\n\n for (const tagName of videoTags) {\n // 处理HTML实体编码的自闭合video标签\n const encodedSelfClosingPattern = `&lt;${tagName}([^&]*?)\\\\s*\\\\/?\\\\s*&gt;`;\n const encodedSelfClosingRegex = new RegExp(encodedSelfClosingPattern, 'gi');\n\n if (!encodedSelfClosingRegex.test(node.value)) continue;\n\n // 重置正则表达式的 lastIndex\n encodedSelfClosingRegex.lastIndex = 0;\n\n const text = node.value;\n const newNodes = [];\n let lastIndex = 0;\n let match;\n\n while ((match = encodedSelfClosingRegex.exec(text)) !== null) {\n const [fullMatch, attributesStr] = match;\n const startIndex = match.index;\n\n // 添加匹配前的文本\n if (startIndex > lastIndex) {\n newNodes.push({\n type: 'text',\n value: text.slice(lastIndex, startIndex),\n });\n }\n\n // 解析属性(需要解码HTML实体)\n const decodedAttrs = attributesStr\n .replaceAll('&quot;', '\"')\n .replaceAll('&#39;', \"'\")\n .replaceAll('&amp;', '&')\n .replaceAll('&lt;', '<')\n .replaceAll('&gt;', '>');\n\n const properties: Record<string, string> = {};\n const attrRegex = /(\\w+)=[\"']([^\"']*?)[\"']/g;\n let attrMatch;\n\n while ((attrMatch = attrRegex.exec(decodedAttrs)) !== null) {\n properties[attrMatch[1]] = attrMatch[2];\n }\n\n // 添加video节点\n newNodes.push({\n children: [],\n data: {\n hName: tagName,\n hProperties: properties,\n },\n type: tagName,\n });\n\n lastIndex = startIndex + fullMatch.length;\n }\n\n // 添加剩余文本\n if (lastIndex < text.length) {\n newNodes.push({\n type: 'text',\n value: text.slice(lastIndex),\n });\n }\n\n // 替换当前节点\n if (newNodes.length > 0 && parent) {\n parent.children.splice(index, 1, ...newNodes);\n return index + newNodes.length - 1;\n }\n }\n });\n };\n};\n"],"mappings":"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"}