@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 7.58 kB
Source Map (JSON)
{"version":3,"file":"hastTableToMarkdown.mjs","names":[],"sources":["../../../../src/Markdown/components/MarkdownTable/hastTableToMarkdown.ts"],"sourcesContent":["type HastNode = {\n children?: HastNode[];\n properties?: Record<string, any>;\n tagName?: string;\n type: string;\n value?: string;\n};\n\nconst escapeCell = (text: string) => text.replaceAll('|', '\\\\|').replaceAll(/\\r?\\n/g, '<br>');\n\nconst matchAlign = (source: string): 'center' | 'left' | 'right' | null => {\n if (source.includes('center')) return 'center';\n if (source.includes('right')) return 'right';\n if (source.includes('left')) return 'left';\n return null;\n};\n\nconst readAlign = (node: HastNode | undefined): 'center' | 'left' | 'right' | null => {\n const style = node?.properties?.style;\n const align = node?.properties?.align;\n const styleStr = typeof style === 'string' ? style.toLowerCase() : '';\n const alignStr = typeof align === 'string' ? align.toLowerCase() : '';\n // Prefer the inline style hint (more specific) but fall back to the\n // explicit `align` attribute when style has no alignment keyword —\n // otherwise an unrelated style like `color: red` would suppress\n // `align=\"right\"`.\n return matchAlign(styleStr) ?? matchAlign(alignStr);\n};\n\n// CommonMark code-span rule: open and close with N backticks where N is\n// longer than any run of consecutive backticks inside the content. If the\n// content starts or ends with a backtick, pad with a single space on each\n// side (the parser strips one space when both sides are padded).\nconst encodeInlineCode = (text: string): string => {\n let longestRun = 0;\n const runs = text.match(/`+/g);\n if (runs) for (const run of runs) longestRun = Math.max(longestRun, run.length);\n const fence = '`'.repeat(longestRun + 1);\n const needsPad = text.startsWith('`') || text.endsWith('`');\n const body = needsPad ? ` ${text} ` : text;\n return `${fence}${body}${fence}`;\n};\n\nconst renderInline = (node: HastNode): string => {\n if (node.type === 'text') return node.value ?? '';\n if (node.type !== 'element') return '';\n\n const inner = (node.children ?? []).map((child) => renderInline(child)).join('');\n\n switch (node.tagName) {\n case 'br': {\n return '<br>';\n }\n case 'code': {\n return encodeInlineCode(inner);\n }\n case 'strong':\n case 'b': {\n return `**${inner}**`;\n }\n case 'em':\n case 'i': {\n return `*${inner}*`;\n }\n case 'del':\n case 's': {\n return `~~${inner}~~`;\n }\n case 'a': {\n const href = node.properties?.href;\n return href ? `[${inner}](${href})` : inner;\n }\n case 'img': {\n const src = node.properties?.src ?? '';\n const alt = node.properties?.alt ?? '';\n return ``;\n }\n default: {\n return inner;\n }\n }\n};\n\nconst renderCell = (cell: HastNode): string => escapeCell(renderInline(cell)).trim();\n\nconst findChild = (node: HastNode | undefined, tag: string): HastNode | undefined =>\n node?.children?.find((child) => child.type === 'element' && child.tagName === tag);\n\nconst findAllChildren = (node: HastNode | undefined, tag: string): HastNode[] =>\n (node?.children ?? []).filter((child) => child.type === 'element' && child.tagName === tag);\n\nconst getRowCells = (row: HastNode): HastNode[] =>\n (row.children ?? []).filter(\n (child) => child.type === 'element' && (child.tagName === 'th' || child.tagName === 'td'),\n );\n\nconst alignToDivider = (align: 'center' | 'left' | 'right' | null): string => {\n switch (align) {\n case 'center': {\n return ':---:';\n }\n case 'left': {\n return ':---';\n }\n case 'right': {\n return '---:';\n }\n default: {\n return '---';\n }\n }\n};\n\nexport const hastTableToMarkdown = (node: HastNode | undefined): string => {\n if (!node) return '';\n\n const thead = findChild(node, 'thead');\n const tbody = findChild(node, 'tbody');\n\n const headerRow = findChild(thead, 'tr');\n const headerCells = headerRow ? getRowCells(headerRow) : [];\n\n const bodyRows = findAllChildren(tbody, 'tr');\n const columnCount = Math.max(\n headerCells.length,\n ...bodyRows.map((row) => getRowCells(row).length),\n );\n\n if (columnCount === 0) return '';\n\n const headerTexts = Array.from({ length: columnCount }, (_, i) =>\n headerCells[i] ? renderCell(headerCells[i]) : '',\n );\n\n const aligns = Array.from({ length: columnCount }, (_, i) => readAlign(headerCells[i]));\n\n const headerLine = `| ${headerTexts.join(' | ')} |`;\n const dividerLine = `| ${aligns.map((a) => alignToDivider(a)).join(' | ')} |`;\n const bodyLines = bodyRows.map((row) => {\n const cells = getRowCells(row);\n const texts = Array.from({ length: columnCount }, (_, i) =>\n cells[i] ? renderCell(cells[i]) : '',\n );\n return `| ${texts.join(' | ')} |`;\n });\n\n return [headerLine, dividerLine, ...bodyLines].join('\\n');\n};\n"],"mappings":";AAQA,MAAM,cAAc,SAAiB,KAAK,WAAW,KAAK,KAAK,CAAC,CAAC,WAAW,UAAU,MAAM;AAE5F,MAAM,cAAc,WAAuD;CACzE,IAAI,OAAO,SAAS,QAAQ,GAAG,OAAO;CACtC,IAAI,OAAO,SAAS,OAAO,GAAG,OAAO;CACrC,IAAI,OAAO,SAAS,MAAM,GAAG,OAAO;CACpC,OAAO;AACT;AAEA,MAAM,aAAa,SAAmE;CACpF,MAAM,QAAQ,MAAM,YAAY;CAChC,MAAM,QAAQ,MAAM,YAAY;CAChC,MAAM,WAAW,OAAO,UAAU,WAAW,MAAM,YAAY,IAAI;CACnE,MAAM,WAAW,OAAO,UAAU,WAAW,MAAM,YAAY,IAAI;CAKnE,OAAO,WAAW,QAAQ,KAAK,WAAW,QAAQ;AACpD;AAMA,MAAM,oBAAoB,SAAyB;CACjD,IAAI,aAAa;CACjB,MAAM,OAAO,KAAK,MAAM,KAAK;CAC7B,IAAI,MAAM,KAAK,MAAM,OAAO,MAAM,aAAa,KAAK,IAAI,YAAY,IAAI,MAAM;CAC9E,MAAM,QAAQ,IAAI,OAAO,aAAa,CAAC;CAGvC,OAAO,GAAG,QAFO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,IAClC,IAAI,KAAK,KAAK,OACb;AAC3B;AAEA,MAAM,gBAAgB,SAA2B;CAC/C,IAAI,KAAK,SAAS,QAAQ,OAAO,KAAK,SAAS;CAC/C,IAAI,KAAK,SAAS,WAAW,OAAO;CAEpC,MAAM,SAAS,KAAK,YAAY,CAAC,EAAA,CAAG,KAAK,UAAU,aAAa,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE;CAE/E,QAAQ,KAAK,SAAb;EACE,KAAK,MACH,OAAO;EAET,KAAK,QACH,OAAO,iBAAiB,KAAK;EAE/B,KAAK;EACL,KAAK,KACH,OAAO,KAAK,MAAM;EAEpB,KAAK;EACL,KAAK,KACH,OAAO,IAAI,MAAM;EAEnB,KAAK;EACL,KAAK,KACH,OAAO,KAAK,MAAM;EAEpB,KAAK,KAAK;GACR,MAAM,OAAO,KAAK,YAAY;GAC9B,OAAO,OAAO,IAAI,MAAM,IAAI,KAAK,KAAK;EACxC;EACA,KAAK,OAAO;GACV,MAAM,MAAM,KAAK,YAAY,OAAO;GAEpC,OAAO,KADK,KAAK,YAAY,OAAO,GACpB,IAAI,IAAI;EAC1B;EACA,SACE,OAAO;CAEX;AACF;AAEA,MAAM,cAAc,SAA2B,WAAW,aAAa,IAAI,CAAC,CAAC,CAAC,KAAK;AAEnF,MAAM,aAAa,MAA4B,QAC7C,MAAM,UAAU,MAAM,UAAU,MAAM,SAAS,aAAa,MAAM,YAAY,GAAG;AAEnF,MAAM,mBAAmB,MAA4B,SAClD,MAAM,YAAY,CAAC,EAAA,CAAG,QAAQ,UAAU,MAAM,SAAS,aAAa,MAAM,YAAY,GAAG;AAE5F,MAAM,eAAe,SAClB,IAAI,YAAY,CAAC,EAAA,CAAG,QAClB,UAAU,MAAM,SAAS,cAAc,MAAM,YAAY,QAAQ,MAAM,YAAY,KACtF;AAEF,MAAM,kBAAkB,UAAsD;CAC5E,QAAQ,OAAR;EACE,KAAK,UACH,OAAO;EAET,KAAK,QACH,OAAO;EAET,KAAK,SACH,OAAO;EAET,SACE,OAAO;CAEX;AACF;AAEA,MAAa,uBAAuB,SAAuC;CACzE,IAAI,CAAC,MAAM,OAAO;CAElB,MAAM,QAAQ,UAAU,MAAM,OAAO;CACrC,MAAM,QAAQ,UAAU,MAAM,OAAO;CAErC,MAAM,YAAY,UAAU,OAAO,IAAI;CACvC,MAAM,cAAc,YAAY,YAAY,SAAS,IAAI,CAAC;CAE1D,MAAM,WAAW,gBAAgB,OAAO,IAAI;CAC5C,MAAM,cAAc,KAAK,IACvB,YAAY,QACZ,GAAG,SAAS,KAAK,QAAQ,YAAY,GAAG,CAAC,CAAC,MAAM,CAClD;CAEA,IAAI,gBAAgB,GAAG,OAAO;CAE9B,MAAM,cAAc,MAAM,KAAK,EAAE,QAAQ,YAAY,IAAI,GAAG,MAC1D,YAAY,KAAK,WAAW,YAAY,EAAE,IAAI,EAChD;CAEA,MAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,YAAY,IAAI,GAAG,MAAM,UAAU,YAAY,EAAE,CAAC;CAYtF,OAAO;EAAC,KAVgB,YAAY,KAAK,KAAK,EAAE;EAU5B,KATK,OAAO,KAAK,MAAM,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE;EASzC,GARf,SAAS,KAAK,QAAQ;GACtC,MAAM,QAAQ,YAAY,GAAG;GAI7B,OAAO,KAHO,MAAM,KAAK,EAAE,QAAQ,YAAY,IAAI,GAAG,MACpD,MAAM,KAAK,WAAW,MAAM,EAAE,IAAI,EAEpB,CAAC,CAAC,KAAK,KAAK,EAAE;EAChC,CAE4C;CAAC,CAAC,CAAC,KAAK,IAAI;AAC1D"}