import { JSDOM } from 'jsdom'; import type { DecodedHtmlDocument, DecodedXmlDocument, ImportRuntimeAdapters, MarkupDocumentAdapter, TextDecoderAdapter } from '../src/importers/runtime-adapters'; import { decodeHtmlDocument, decodeHtmlLexically, isHtmlStackOverflow, shouldUseBoundedHtmlExtraction } from '../src/importers/html-extraction'; function walkXml(node: Element, path: string, rows: Array<{ path: string; attributes: string; text: string }>): void { const attributes = [...node.attributes].map(attribute => `${attribute.name}="${attribute.value}"`).join('; '); const text = [...node.childNodes] .filter(child => child.nodeType === 3) .map(child => child.textContent?.trim() ?? '') .filter(Boolean) .join(' '); rows.push({ path, attributes, text }); [...node.children].forEach((child, index) => walkXml(child, `${path}/${child.nodeName}[${index + 1}]`, rows)); } export const nodeMarkupDocumentAdapter: MarkupDocumentAdapter = { decodeHtml(text: string): DecodedHtmlDocument { if (shouldUseBoundedHtmlExtraction(text)) return decodeHtmlLexically(text); try { const documentNode = new JSDOM(text, { contentType: 'text/html' }).window.document; return decodeHtmlDocument(documentNode); } catch (error) { if (isHtmlStackOverflow(error)) return decodeHtmlLexically(text); throw error; } }, decodeXml(text: string): DecodedXmlDocument { if (/ = []; walkXml(root, root.nodeName, rows); return { valid: true, rootName: root.nodeName, rows }; } catch { return { valid: false, message: 'Die XML-Struktur ist nicht wohlgeformt.' }; } } }; export const nodeTextDecoderAdapter: TextDecoderAdapter = { decode(bytes) { try { return { text: new TextDecoder('utf-8', { fatal: true }).decode(bytes), encoding: 'utf-8' }; } catch { return { text: new TextDecoder('windows-1252').decode(bytes), encoding: 'windows-1252' }; } } }; export const nodeImportRuntimeAdapters: ImportRuntimeAdapters = { textDecoder: nodeTextDecoderAdapter, markup: nodeMarkupDocumentAdapter };