UNPKG

5.3 kBJavaScriptView Raw
1import { TAG_NAMES as $, NS, hasUnescapedText } from '../common/html.js';
2import { escapeText, escapeAttribute } from 'entities/lib/escape.js';
3import { defaultTreeAdapter } from '../tree-adapters/default.js';
4// Sets
5const VOID_ELEMENTS = new Set([
6 $.AREA,
7 $.BASE,
8 $.BASEFONT,
9 $.BGSOUND,
10 $.BR,
11 $.COL,
12 $.EMBED,
13 $.FRAME,
14 $.HR,
15 $.IMG,
16 $.INPUT,
17 $.KEYGEN,
18 $.LINK,
19 $.META,
20 $.PARAM,
21 $.SOURCE,
22 $.TRACK,
23 $.WBR,
24]);
25function isVoidElement(node, options) {
26 return (options.treeAdapter.isElementNode(node) &&
27 options.treeAdapter.getNamespaceURI(node) === NS.HTML &&
28 VOID_ELEMENTS.has(options.treeAdapter.getTagName(node)));
29}
30const defaultOpts = { treeAdapter: defaultTreeAdapter, scriptingEnabled: true };
31/**
32 * Serializes an AST node to an HTML string.
33 *
34 * @example
35 *
36 * ```js
37 * const parse5 = require('parse5');
38 *
39 * const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
40 *
41 * // Serializes a document.
42 * const html = parse5.serialize(document);
43 *
44 * // Serializes the <html> element content.
45 * const str = parse5.serialize(document.childNodes[1]);
46 *
47 * console.log(str); //> '<head></head><body>Hi there!</body>'
48 * ```
49 *
50 * @param node Node to serialize.
51 * @param options Serialization options.
52 */
53export function serialize(node, options) {
54 const opts = { ...defaultOpts, ...options };
55 if (isVoidElement(node, opts)) {
56 return '';
57 }
58 return serializeChildNodes(node, opts);
59}
60/**
61 * Serializes an AST element node to an HTML string, including the element node.
62 *
63 * @example
64 *
65 * ```js
66 * const parse5 = require('parse5');
67 *
68 * const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
69 *
70 * // Serializes the <div> element.
71 * const html = parse5.serializeOuter(document.childNodes[0]);
72 *
73 * console.log(str); //> '<div>Hello, <b>world</b>!</div>'
74 * ```
75 *
76 * @param node Node to serialize.
77 * @param options Serialization options.
78 */
79export function serializeOuter(node, options) {
80 const opts = { ...defaultOpts, ...options };
81 return serializeNode(node, opts);
82}
83function serializeChildNodes(parentNode, options) {
84 let html = '';
85 // Get container of the child nodes
86 const container = options.treeAdapter.isElementNode(parentNode) &&
87 options.treeAdapter.getTagName(parentNode) === $.TEMPLATE &&
88 options.treeAdapter.getNamespaceURI(parentNode) === NS.HTML
89 ? options.treeAdapter.getTemplateContent(parentNode)
90 : parentNode;
91 const childNodes = options.treeAdapter.getChildNodes(container);
92 if (childNodes) {
93 for (const currentNode of childNodes) {
94 html += serializeNode(currentNode, options);
95 }
96 }
97 return html;
98}
99function serializeNode(node, options) {
100 if (options.treeAdapter.isElementNode(node)) {
101 return serializeElement(node, options);
102 }
103 if (options.treeAdapter.isTextNode(node)) {
104 return serializeTextNode(node, options);
105 }
106 if (options.treeAdapter.isCommentNode(node)) {
107 return serializeCommentNode(node, options);
108 }
109 if (options.treeAdapter.isDocumentTypeNode(node)) {
110 return serializeDocumentTypeNode(node, options);
111 }
112 // Return an empty string for unknown nodes
113 return '';
114}
115function serializeElement(node, options) {
116 const tn = options.treeAdapter.getTagName(node);
117 return `<${tn}${serializeAttributes(node, options)}>${isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`}`;
118}
119function serializeAttributes(node, { treeAdapter }) {
120 let html = '';
121 for (const attr of treeAdapter.getAttrList(node)) {
122 html += ' ';
123 if (!attr.namespace) {
124 html += attr.name;
125 }
126 else
127 switch (attr.namespace) {
128 case NS.XML: {
129 html += `xml:${attr.name}`;
130 break;
131 }
132 case NS.XMLNS: {
133 if (attr.name !== 'xmlns') {
134 html += 'xmlns:';
135 }
136 html += attr.name;
137 break;
138 }
139 case NS.XLINK: {
140 html += `xlink:${attr.name}`;
141 break;
142 }
143 default: {
144 html += `${attr.prefix}:${attr.name}`;
145 }
146 }
147 html += `="${escapeAttribute(attr.value)}"`;
148 }
149 return html;
150}
151function serializeTextNode(node, options) {
152 const { treeAdapter } = options;
153 const content = treeAdapter.getTextNodeContent(node);
154 const parent = treeAdapter.getParentNode(node);
155 const parentTn = parent && treeAdapter.isElementNode(parent) && treeAdapter.getTagName(parent);
156 return parentTn &&
157 treeAdapter.getNamespaceURI(parent) === NS.HTML &&
158 hasUnescapedText(parentTn, options.scriptingEnabled)
159 ? content
160 : escapeText(content);
161}
162function serializeCommentNode(node, { treeAdapter }) {
163 return `<!--${treeAdapter.getCommentNodeContent(node)}-->`;
164}
165function serializeDocumentTypeNode(node, { treeAdapter }) {
166 return `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node)}>`;
167}
168//# sourceMappingURL=index.js.map
\No newline at end of file