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