1import { html, type TreeAdapter, type TreeAdapterTypeMap, type Token } from 'parse5'; 2 3function getSerializedTreeIndent(indent: number): string { 4 return '|'.padEnd(indent + 2, ' '); 5} 6 7function getElementSerializedNamespaceURI<T extends TreeAdapterTypeMap>( 8 element: T['element'], 9 treeAdapter: TreeAdapter<T> 10): string { 11 switch (treeAdapter.getNamespaceURI(element)) { 12 case html.NS.SVG: { 13 return 'svg '; 14 } 15 case html.NS.MATHML: { 16 return 'math '; 17 } 18 default: { 19 return ''; 20 } 21 } 22} 23 24function serializeNodeList<T extends TreeAdapterTypeMap>( 25 nodes: T['node'][], 26 indent: number, 27 treeAdapter: TreeAdapter<T> 28): string { 29 let str = ''; 30 31 for (let node of nodes) { 32 str += getSerializedTreeIndent(indent); 33 34 if (treeAdapter.isCommentNode(node)) { 35 str += `<!-- ${treeAdapter.getCommentNodeContent(node)} -->\n`; 36 } else if (treeAdapter.isTextNode(node)) { 37 str += `"${treeAdapter.getTextNodeContent(node)}"\n`; 38 } else if (treeAdapter.isDocumentTypeNode(node)) { 39 const publicId = treeAdapter.getDocumentTypeNodePublicId(node); 40 const systemId = treeAdapter.getDocumentTypeNodeSystemId(node); 41 42 str += `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node) || ''}`; 43 44 if (publicId || systemId) { 45 str += ` "${publicId}" "${systemId}"`; 46 } 47 48 str += '>\n'; 49 } else { 50 const tn = treeAdapter.getTagName(node); 51 52 str += `<${getElementSerializedNamespaceURI(node, treeAdapter) + tn}>\n`; 53 54 let childrenIndent = indent + 2; 55 const serializedAttrs = treeAdapter.getAttrList(node).map((attr: Token.Attribute) => { 56 let attrStr = getSerializedTreeIndent(childrenIndent); 57 58 if (attr.prefix) { 59 attrStr += `${attr.prefix} `; 60 } 61 62 attrStr += `${attr.name}="${attr.value}"\n`; 63 64 return attrStr; 65 }); 66 67 str += serializedAttrs.sort().join(''); 68 69 if (tn === html.TAG_NAMES.TEMPLATE && treeAdapter.getNamespaceURI(node) === html.NS.HTML) { 70 str += `${getSerializedTreeIndent(childrenIndent)}content\n`; 71 childrenIndent += 2; 72 node = treeAdapter.getTemplateContent(node); 73 } 74 75 str += serializeNodeList(treeAdapter.getChildNodes(node), childrenIndent, treeAdapter); 76 } 77 } 78 79 return str; 80} 81 82export function serializeToDatFileFormat<T extends TreeAdapterTypeMap>( 83 rootNode: T['parentNode'], 84 treeAdapter: TreeAdapter<T> 85): string { 86 return serializeNodeList(treeAdapter.getChildNodes(rootNode), 0, treeAdapter); 87} 88