173 lines
No EOL
5.8 KiB
JavaScript
Executable file
173 lines
No EOL
5.8 KiB
JavaScript
Executable file
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.serializeOuter = exports.serialize = void 0;
|
|
const html_js_1 = require("../common/html.js");
|
|
const escape_js_1 = require("entities/lib/escape.js");
|
|
const default_js_1 = require("../tree-adapters/default.js");
|
|
// Sets
|
|
const VOID_ELEMENTS = new Set([
|
|
html_js_1.TAG_NAMES.AREA,
|
|
html_js_1.TAG_NAMES.BASE,
|
|
html_js_1.TAG_NAMES.BASEFONT,
|
|
html_js_1.TAG_NAMES.BGSOUND,
|
|
html_js_1.TAG_NAMES.BR,
|
|
html_js_1.TAG_NAMES.COL,
|
|
html_js_1.TAG_NAMES.EMBED,
|
|
html_js_1.TAG_NAMES.FRAME,
|
|
html_js_1.TAG_NAMES.HR,
|
|
html_js_1.TAG_NAMES.IMG,
|
|
html_js_1.TAG_NAMES.INPUT,
|
|
html_js_1.TAG_NAMES.KEYGEN,
|
|
html_js_1.TAG_NAMES.LINK,
|
|
html_js_1.TAG_NAMES.META,
|
|
html_js_1.TAG_NAMES.PARAM,
|
|
html_js_1.TAG_NAMES.SOURCE,
|
|
html_js_1.TAG_NAMES.TRACK,
|
|
html_js_1.TAG_NAMES.WBR,
|
|
]);
|
|
function isVoidElement(node, options) {
|
|
return (options.treeAdapter.isElementNode(node) &&
|
|
options.treeAdapter.getNamespaceURI(node) === html_js_1.NS.HTML &&
|
|
VOID_ELEMENTS.has(options.treeAdapter.getTagName(node)));
|
|
}
|
|
const defaultOpts = { treeAdapter: default_js_1.defaultTreeAdapter, scriptingEnabled: true };
|
|
/**
|
|
* Serializes an AST node to an HTML string.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* const parse5 = require('parse5');
|
|
*
|
|
* const document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>');
|
|
*
|
|
* // Serializes a document.
|
|
* const html = parse5.serialize(document);
|
|
*
|
|
* // Serializes the <html> element content.
|
|
* const str = parse5.serialize(document.childNodes[1]);
|
|
*
|
|
* console.log(str); //> '<head></head><body>Hi there!</body>'
|
|
* ```
|
|
*
|
|
* @param node Node to serialize.
|
|
* @param options Serialization options.
|
|
*/
|
|
function serialize(node, options) {
|
|
const opts = Object.assign(Object.assign({}, defaultOpts), options);
|
|
if (isVoidElement(node, opts)) {
|
|
return '';
|
|
}
|
|
return serializeChildNodes(node, opts);
|
|
}
|
|
exports.serialize = serialize;
|
|
/**
|
|
* Serializes an AST element node to an HTML string, including the element node.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* const parse5 = require('parse5');
|
|
*
|
|
* const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
|
|
*
|
|
* // Serializes the <div> element.
|
|
* const html = parse5.serializeOuter(document.childNodes[0]);
|
|
*
|
|
* console.log(str); //> '<div>Hello, <b>world</b>!</div>'
|
|
* ```
|
|
*
|
|
* @param node Node to serialize.
|
|
* @param options Serialization options.
|
|
*/
|
|
function serializeOuter(node, options) {
|
|
const opts = Object.assign(Object.assign({}, defaultOpts), options);
|
|
return serializeNode(node, opts);
|
|
}
|
|
exports.serializeOuter = serializeOuter;
|
|
function serializeChildNodes(parentNode, options) {
|
|
let html = '';
|
|
// Get container of the child nodes
|
|
const container = options.treeAdapter.isElementNode(parentNode) &&
|
|
options.treeAdapter.getTagName(parentNode) === html_js_1.TAG_NAMES.TEMPLATE &&
|
|
options.treeAdapter.getNamespaceURI(parentNode) === html_js_1.NS.HTML
|
|
? options.treeAdapter.getTemplateContent(parentNode)
|
|
: parentNode;
|
|
const childNodes = options.treeAdapter.getChildNodes(container);
|
|
if (childNodes) {
|
|
for (const currentNode of childNodes) {
|
|
html += serializeNode(currentNode, options);
|
|
}
|
|
}
|
|
return html;
|
|
}
|
|
function serializeNode(node, options) {
|
|
if (options.treeAdapter.isElementNode(node)) {
|
|
return serializeElement(node, options);
|
|
}
|
|
if (options.treeAdapter.isTextNode(node)) {
|
|
return serializeTextNode(node, options);
|
|
}
|
|
if (options.treeAdapter.isCommentNode(node)) {
|
|
return serializeCommentNode(node, options);
|
|
}
|
|
if (options.treeAdapter.isDocumentTypeNode(node)) {
|
|
return serializeDocumentTypeNode(node, options);
|
|
}
|
|
// Return an empty string for unknown nodes
|
|
return '';
|
|
}
|
|
function serializeElement(node, options) {
|
|
const tn = options.treeAdapter.getTagName(node);
|
|
return `<${tn}${serializeAttributes(node, options)}>${isVoidElement(node, options) ? '' : `${serializeChildNodes(node, options)}</${tn}>`}`;
|
|
}
|
|
function serializeAttributes(node, { treeAdapter }) {
|
|
let html = '';
|
|
for (const attr of treeAdapter.getAttrList(node)) {
|
|
html += ' ';
|
|
if (!attr.namespace) {
|
|
html += attr.name;
|
|
}
|
|
else
|
|
switch (attr.namespace) {
|
|
case html_js_1.NS.XML: {
|
|
html += `xml:${attr.name}`;
|
|
break;
|
|
}
|
|
case html_js_1.NS.XMLNS: {
|
|
if (attr.name !== 'xmlns') {
|
|
html += 'xmlns:';
|
|
}
|
|
html += attr.name;
|
|
break;
|
|
}
|
|
case html_js_1.NS.XLINK: {
|
|
html += `xlink:${attr.name}`;
|
|
break;
|
|
}
|
|
default: {
|
|
html += `${attr.prefix}:${attr.name}`;
|
|
}
|
|
}
|
|
html += `="${(0, escape_js_1.escapeAttribute)(attr.value)}"`;
|
|
}
|
|
return html;
|
|
}
|
|
function serializeTextNode(node, options) {
|
|
const { treeAdapter } = options;
|
|
const content = treeAdapter.getTextNodeContent(node);
|
|
const parent = treeAdapter.getParentNode(node);
|
|
const parentTn = parent && treeAdapter.isElementNode(parent) && treeAdapter.getTagName(parent);
|
|
return parentTn &&
|
|
treeAdapter.getNamespaceURI(parent) === html_js_1.NS.HTML &&
|
|
(0, html_js_1.hasUnescapedText)(parentTn, options.scriptingEnabled)
|
|
? content
|
|
: (0, escape_js_1.escapeText)(content);
|
|
}
|
|
function serializeCommentNode(node, { treeAdapter }) {
|
|
return `<!--${treeAdapter.getCommentNodeContent(node)}-->`;
|
|
}
|
|
function serializeDocumentTypeNode(node, { treeAdapter }) {
|
|
return `<!DOCTYPE ${treeAdapter.getDocumentTypeNodeName(node)}>`;
|
|
}
|
|
//# sourceMappingURL=index.js.map
|