@shapio/schema 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","names":[],"sources":["../src/richtext/fromHtml.ts"],"sourcesContent":["import { parseFragment, type DefaultTreeAdapterTypes } from 'parse5';\nimport { RICHTEXT_FORMAT, RICHTEXT_FORMAT_VERSION } from '../types/valueFormats.js';\nimport { MAX_RICHTEXT_DEPTH, SAFE_LINK_PATTERN } from './spec.js';\nimport { validateRichText, type RichTextDocument, type RichTextNode } from './validate.js';\n\n/**\n * HTML → Shapio rich text (ADR 0003), for importers: WordPress post bodies, Markdown rendered to HTML. Runs in\n * Node without a browser DOM (parse5). Everything maps to the baseline node and mark set in `spec.ts`;\n * anything else is unwrapped (its text is kept) or, for embeds and scripts, dropped with a warning. The result\n * always passes `validateRichText`.\n *\n * Images become `image` nodes only when `resolveImage` returns a media asset ID for them: rich text never\n * stores a URL, so an image the caller could not import is dropped (and reported).\n */\n\ntype Element = DefaultTreeAdapterTypes.Element;\ntype ChildNode = DefaultTreeAdapterTypes.ChildNode;\ntype Mark = NonNullable<RichTextNode['marks']>[number];\n\nexport type HtmlImage = { src: string; alt: string | null; title: string | null };\n\nexport type HtmlConversionWarningCode = 'imageUnresolved' | 'unsafeLink' | 'embedDropped' | 'invalidOutput';\nexport type HtmlConversionWarning = { code: HtmlConversionWarningCode; detail: string };\n\nexport type HtmlToRichTextOptions = {\n /** Returns the media asset ID for an image, or undefined to drop it. Without it every image is dropped. */\n resolveImage?: (image: HtmlImage) => string | undefined;\n};\n\nexport type HtmlToRichTextResult = { document: RichTextDocument; warnings: HtmlConversionWarning[] };\n\nconst MARK_TAGS: Readonly<Record<string, Mark['type']>> = {\n strong: 'bold',\n b: 'bold',\n em: 'italic',\n i: 'italic',\n code: 'code',\n kbd: 'code',\n samp: 'code',\n tt: 'code',\n};\n\n/** Elements whose content is block-level and simply unwrapped into the surrounding blocks. */\nconst CONTAINER_TAGS = new Set([\n 'div',\n 'section',\n 'article',\n 'aside',\n 'header',\n 'footer',\n 'main',\n 'nav',\n 'figure',\n 'center',\n 'details',\n 'dl',\n 'address',\n 'form',\n 'fieldset',\n 'hgroup',\n 'body',\n 'html',\n]);\n\n/** Elements that become one paragraph of their inline content. */\nconst PARAGRAPH_TAGS = new Set(['p', 'figcaption', 'dt', 'dd', 'summary', 'caption', 'legend', 'li']);\n\n/** Dropped with their content; embeds are reported because something visible is lost. */\nconst SILENT_DROP_TAGS = new Set([\n 'script',\n 'style',\n 'template',\n 'head',\n 'noscript',\n 'title',\n 'meta',\n 'link',\n]);\nconst EMBED_TAGS = new Set([\n 'iframe',\n 'video',\n 'audio',\n 'object',\n 'embed',\n 'svg',\n 'math',\n 'canvas',\n 'button',\n 'input',\n 'select',\n 'textarea',\n]);\n\nconst HEADING_LEVELS: Readonly<Record<string, number>> = { h1: 1, h2: 2, h3: 3, h4: 4, h5: 5, h6: 6 };\nconst LIST_TYPES = new Set(['1', 'a', 'A', 'i', 'I']);\nconst LANGUAGE_PATTERN = /^[A-Za-z0-9_+#.-]{1,32}$/;\nconst MAX_ATTR_TEXT = 1000;\n/** Containers deeper than this are unwrapped, so the document stays within MAX_RICHTEXT_DEPTH. */\nconst MAX_BLOCK_DEPTH = MAX_RICHTEXT_DEPTH - 6;\n\ntype Context = { options: HtmlToRichTextOptions; warnings: HtmlConversionWarning[] };\n\n/** Collects one textblock's inline content; `flush` turns it into a block and starts the next one. */\ntype Sink = {\n blocks: RichTextNode[];\n inline: RichTextNode[];\n textblock: (content: RichTextNode[]) => RichTextNode;\n};\n\nconst isElement = (node: ChildNode): node is Element => 'tagName' in node;\n\nconst attrOf = (element: Element, name: string): string | null =>\n element.attrs.find((attr) => attr.name === name)?.value ?? null;\n\nconst textContent = (node: ChildNode): string =>\n node.nodeName === '#text'\n ? (node as DefaultTreeAdapterTypes.TextNode).value\n : isElement(node)\n ? node.childNodes.map(textContent).join('')\n : '';\n\nconst paragraph = (content: RichTextNode[]): RichTextNode =>\n content.length > 0 ? { type: 'paragraph', content } : { type: 'paragraph' };\n\nconst newSink = (textblock: Sink['textblock'] = paragraph): Sink => ({ blocks: [], inline: [], textblock });\n\nconst sameMarks = (left: RichTextNode['marks'], right: RichTextNode['marks']) =>\n JSON.stringify(left ?? []) === JSON.stringify(right ?? []);\n\n/** HTML whitespace rules for one textblock: collapse runs, trim the edges and around hard breaks, merge texts. */\nconst normalizeInline = (nodes: readonly RichTextNode[]): RichTextNode[] => {\n const out: RichTextNode[] = [];\n let atLineStart = true;\n for (const node of nodes) {\n if (node.type !== 'text') {\n const last = out.at(-1);\n if (node.type === 'hardBreak' && last?.type === 'text' && last.text) {\n last.text = last.text.replace(/ +$/, '');\n }\n out.push(node);\n atLineStart = node.type === 'hardBreak';\n continue;\n }\n let text = (node.text ?? '').replace(/[ \\t\\n\\r\\f]+/g, ' ');\n if (atLineStart) {\n text = text.replace(/^ +/, '');\n }\n if (text.length === 0) {\n continue;\n }\n atLineStart = text.endsWith(' ');\n const last = out.at(-1);\n if (last?.type === 'text' && sameMarks(last.marks, node.marks)) {\n last.text = `${last.text ?? ''}${text}`;\n } else {\n out.push(node.marks ? { type: 'text', text, marks: node.marks } : { type: 'text', text });\n }\n }\n const last = out.at(-1);\n if (last?.type === 'text' && last.text) {\n last.text = last.text.replace(/ +$/, '');\n }\n return out.filter((node) => node.type !== 'text' || (node.text ?? '').length > 0);\n};\n\n/** Ends the current textblock. Blocks with no visible text (e.g. `<p>&nbsp;</p>`: `trim` covers U+00A0) are dropped. */\nconst flush = (sink: Sink) => {\n const content = normalizeInline(sink.inline);\n sink.inline = [];\n const visible = content.some((node) => node.type !== 'text' || (node.text ?? '').trim().length > 0);\n if (visible) {\n sink.blocks.push(sink.textblock(content));\n }\n};\n\nconst withMark = (marks: readonly Mark[], mark: Mark): Mark[] => [\n ...marks.filter((existing) => existing.type !== mark.type),\n mark,\n];\n\nconst linkMark = (element: Element, context: Context): Mark | undefined => {\n const href = attrOf(element, 'href')?.trim();\n if (!href) {\n return undefined;\n }\n if (href.length > 2048 || !SAFE_LINK_PATTERN.test(href)) {\n context.warnings.push({ code: 'unsafeLink', detail: href.slice(0, 200) });\n return undefined;\n }\n const target = attrOf(element, 'target') === '_blank' ? '_blank' : null;\n return { type: 'link', attrs: { href, target, rel: null, class: null } };\n};\n\nconst clip = (value: string | null) => (value === null ? null : value.slice(0, MAX_ATTR_TEXT));\n\nconst imageNode = (element: Element, context: Context): RichTextNode | undefined => {\n const src = attrOf(element, 'src')?.trim() ?? '';\n const image: HtmlImage = { src, alt: clip(attrOf(element, 'alt')), title: clip(attrOf(element, 'title')) };\n const mediaId = src ? context.options.resolveImage?.(image) : undefined;\n if (!mediaId) {\n context.warnings.push({ code: 'imageUnresolved', detail: src.slice(0, 500) });\n return undefined;\n }\n return { type: 'image', attrs: { mediaId, alt: image.alt, title: image.title } };\n};\n\nconst listItems = (element: Element, context: Context, depth: number): RichTextNode[] => {\n const items: RichTextNode[] = [];\n let stray: ChildNode[] = [];\n const pushItem = (nodes: ChildNode[]) => {\n const content = convertChildren(nodes, context, depth + 2);\n if (content.length > 0 || nodes.some(isElement)) {\n items.push({ type: 'listItem', content: content.length > 0 ? content : [paragraph([])] });\n }\n };\n for (const child of element.childNodes) {\n if (isElement(child) && child.tagName === 'li') {\n if (stray.length > 0) {\n pushItem(stray);\n stray = [];\n }\n pushItem(child.childNodes);\n } else if (textContent(child).trim().length > 0 || isElement(child)) {\n stray.push(child);\n }\n }\n if (stray.length > 0) {\n pushItem(stray);\n }\n return items;\n};\n\nconst listNode = (element: Element, context: Context, depth: number): RichTextNode[] => {\n const items = listItems(element, context, depth);\n if (items.length === 0) {\n return [];\n }\n if (element.tagName === 'ul') {\n return [{ type: 'bulletList', content: items }];\n }\n const start = Number.parseInt(attrOf(element, 'start') ?? '1', 10);\n const type = attrOf(element, 'type');\n return [\n {\n type: 'orderedList',\n attrs: {\n start: Number.isInteger(start) && start >= 0 && start <= 1_000_000 ? start : 1,\n type: type !== null && LIST_TYPES.has(type) ? type : null,\n },\n content: items,\n },\n ];\n};\n\nconst codeLanguage = (element: Element): string | null => {\n const code = element.childNodes.find(\n (child): child is Element => isElement(child) && child.tagName === 'code',\n );\n const classes = `${attrOf(element, 'class') ?? ''} ${code ? (attrOf(code, 'class') ?? '') : ''}`;\n const language = /(?:^|\\s)(?:language|lang)-(\\S+)/.exec(classes)?.[1] ?? null;\n return language !== null && LANGUAGE_PATTERN.test(language) ? language : null;\n};\n\nconst codeBlockNode = (element: Element): RichTextNode => {\n const text = textContent(element).replace(/\\r\\n?/g, '\\n').replace(/\\n$/, '');\n return {\n type: 'codeBlock',\n attrs: { language: codeLanguage(element) },\n ...(text.length > 0 ? { content: [{ type: 'text', text }] } : {}),\n };\n};\n\nconst CELL_SPAN_MAX = 1000;\n\nconst span = (element: Element, name: string) => {\n const value = Number.parseInt(attrOf(element, name) ?? '1', 10);\n return Number.isInteger(value) && value >= 1 && value <= CELL_SPAN_MAX ? value : 1;\n};\n\nconst tableRows = (element: Element): Element[] =>\n element.childNodes.filter(isElement).flatMap((child) => {\n if (child.tagName === 'tr') {\n return [child];\n }\n return ['thead', 'tbody', 'tfoot'].includes(child.tagName) ? tableRows(child) : [];\n });\n\nconst tableNodes = (element: Element, context: Context, depth: number): RichTextNode[] => {\n const caption = element.childNodes.find(\n (child): child is Element => isElement(child) && child.tagName === 'caption',\n );\n const rows = tableRows(element).flatMap((row): RichTextNode[] => {\n const cells = row.childNodes\n .filter((cell): cell is Element => isElement(cell) && (cell.tagName === 'td' || cell.tagName === 'th'))\n .map((cell): RichTextNode => {\n const content = convertChildren(cell.childNodes, context, depth + 3);\n return {\n type: cell.tagName === 'th' ? 'tableHeader' : 'tableCell',\n attrs: { colspan: span(cell, 'colspan'), rowspan: span(cell, 'rowspan'), colwidth: null },\n content: content.length > 0 ? content : [paragraph([])],\n };\n });\n return cells.length > 0 ? [{ type: 'tableRow', content: cells }] : [];\n });\n return [\n ...(caption ? convertChildren([caption], context, depth) : []),\n ...(rows.length > 0 ? [{ type: 'table', content: rows }] : []),\n ];\n};\n\n/** A block-level element → zero or more blocks. Undefined when the element is not block-level. */\nconst convertBlock = (element: Element, context: Context, depth: number): RichTextNode[] | undefined => {\n const tag = element.tagName;\n const nested = depth < MAX_BLOCK_DEPTH;\n const level = HEADING_LEVELS[tag];\n if (level !== undefined) {\n const sink = newSink((content) => ({\n type: 'heading',\n attrs: { level },\n ...(content.length > 0 ? { content } : {}),\n }));\n walkChildren(element.childNodes, sink, [], context, depth);\n flush(sink);\n return sink.blocks;\n }\n if (\n PARAGRAPH_TAGS.has(tag) ||\n CONTAINER_TAGS.has(tag) ||\n (!nested && (tag === 'blockquote' || tag === 'ul' || tag === 'ol'))\n ) {\n return convertChildren(element.childNodes, context, depth);\n }\n switch (tag) {\n case 'blockquote': {\n const content = convertChildren(element.childNodes, context, depth + 1);\n return content.length > 0 ? [{ type: 'blockquote', content }] : [];\n }\n case 'ul':\n case 'ol':\n return listNode(element, context, depth);\n case 'pre':\n return [codeBlockNode(element)];\n case 'hr':\n return [{ type: 'horizontalRule' }];\n case 'table':\n return nested\n ? tableNodes(element, context, depth)\n : convertChildren(element.childNodes, context, depth);\n default:\n return undefined;\n }\n};\n\n/** Walks nodes in inline context, adding text to the sink and ending its textblock at every block element. */\nconst walkChildren = (\n nodes: readonly ChildNode[],\n sink: Sink,\n marks: readonly Mark[],\n context: Context,\n depth: number,\n) => {\n for (const node of nodes) {\n if (node.nodeName === '#text') {\n const text = (node as DefaultTreeAdapterTypes.TextNode).value;\n sink.inline.push(marks.length > 0 ? { type: 'text', text, marks: [...marks] } : { type: 'text', text });\n continue;\n }\n if (isElement(node)) {\n walkElement(node, sink, marks, context, depth);\n }\n }\n};\n\nconst walkElement = (\n element: Element,\n sink: Sink,\n marks: readonly Mark[],\n context: Context,\n depth: number,\n) => {\n const tag = element.tagName;\n if (SILENT_DROP_TAGS.has(tag)) {\n return;\n }\n if (EMBED_TAGS.has(tag)) {\n context.warnings.push({ code: 'embedDropped', detail: tag });\n return;\n }\n if (tag === 'br') {\n sink.inline.push({ type: 'hardBreak' });\n return;\n }\n if (tag === 'img') {\n const image = imageNode(element, context);\n if (image) {\n flush(sink);\n sink.blocks.push(image);\n }\n return;\n }\n const blocks = convertBlock(element, context, depth);\n if (blocks) {\n flush(sink);\n sink.blocks.push(...blocks);\n return;\n }\n const markType = MARK_TAGS[tag];\n const mark = markType ? { type: markType } : tag === 'a' ? linkMark(element, context) : undefined;\n walkChildren(element.childNodes, sink, mark ? withMark(marks, mark) : marks, context, depth);\n};\n\n/** Converts nodes in block context: loose inline content becomes paragraphs. */\nconst convertChildren = (nodes: readonly ChildNode[], context: Context, depth: number): RichTextNode[] => {\n const sink = newSink();\n walkChildren(nodes, sink, [], context, depth);\n flush(sink);\n return sink.blocks;\n};\n\nconst envelope = (content: RichTextNode[]): RichTextDocument => ({\n format: RICHTEXT_FORMAT,\n version: RICHTEXT_FORMAT_VERSION,\n doc: content.length > 0 ? { type: 'doc', content } : { type: 'doc' },\n});\n\n/** Converts an HTML fragment to a validated rich-text document, with what was lost on the way. */\nexport const htmlToRichText = (html: string, options: HtmlToRichTextOptions = {}): HtmlToRichTextResult => {\n const context: Context = { options, warnings: [] };\n const blocks = convertChildren(parseFragment(html).childNodes, context, 1);\n const result = validateRichText(envelope(blocks));\n if (result.ok) {\n return { document: result.document, warnings: context.warnings };\n }\n // A converter bug, never expected: keep the text rather than lose the content.\n context.warnings.push({ code: 'invalidOutput', detail: JSON.stringify(result.problems.slice(0, 3)) });\n const text = parseFragment(html).childNodes.map(textContent).join('').replace(/\\s+/g, ' ').trim();\n const fallback = validateRichText(envelope(text ? [paragraph([{ type: 'text', text }])] : []));\n if (!fallback.ok) {\n throw new Error('Rich-text fallback document is invalid');\n }\n return { document: fallback.document, warnings: context.warnings };\n};\n\n/** Every `<img>` in a fragment (in document order), so an importer can fetch them before converting. */\nexport const collectHtmlImages = (html: string): HtmlImage[] => {\n const images: HtmlImage[] = [];\n const walk = (node: ChildNode) => {\n if (!isElement(node)) {\n return;\n }\n if (node.tagName === 'img') {\n const src = attrOf(node, 'src')?.trim();\n if (src) {\n images.push({ src, alt: clip(attrOf(node, 'alt')), title: clip(attrOf(node, 'title')) });\n }\n }\n node.childNodes.forEach(walk);\n };\n parseFragment(html).childNodes.forEach(walk);\n return images;\n};\n"],"mappings":"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"}