index.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. "use strict";
  2. var __assign = (this && this.__assign) || function () {
  3. __assign = Object.assign || function(t) {
  4. for (var s, i = 1, n = arguments.length; i < n; i++) {
  5. s = arguments[i];
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  7. t[p] = s[p];
  8. }
  9. return t;
  10. };
  11. return __assign.apply(this, arguments);
  12. };
  13. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  14. if (k2 === undefined) k2 = k;
  15. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  16. }) : (function(o, m, k, k2) {
  17. if (k2 === undefined) k2 = k;
  18. o[k2] = m[k];
  19. }));
  20. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  21. Object.defineProperty(o, "default", { enumerable: true, value: v });
  22. }) : function(o, v) {
  23. o["default"] = v;
  24. });
  25. var __importStar = (this && this.__importStar) || function (mod) {
  26. if (mod && mod.__esModule) return mod;
  27. var result = {};
  28. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  29. __setModuleDefault(result, mod);
  30. return result;
  31. };
  32. Object.defineProperty(exports, "__esModule", { value: true });
  33. /*
  34. * Module dependencies
  35. */
  36. var ElementType = __importStar(require("domelementtype"));
  37. var entities_1 = require("entities");
  38. /**
  39. * Mixed-case SVG and MathML tags & attributes
  40. * recognized by the HTML parser.
  41. *
  42. * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
  43. */
  44. var foreignNames_1 = require("./foreignNames");
  45. var unencodedElements = new Set([
  46. "style",
  47. "script",
  48. "xmp",
  49. "iframe",
  50. "noembed",
  51. "noframes",
  52. "plaintext",
  53. "noscript",
  54. ]);
  55. /**
  56. * Format attributes
  57. */
  58. function formatAttributes(attributes, opts) {
  59. if (!attributes)
  60. return;
  61. return Object.keys(attributes)
  62. .map(function (key) {
  63. var _a, _b;
  64. var value = (_a = attributes[key]) !== null && _a !== void 0 ? _a : "";
  65. if (opts.xmlMode === "foreign") {
  66. /* Fix up mixed-case attribute names */
  67. key = (_b = foreignNames_1.attributeNames.get(key)) !== null && _b !== void 0 ? _b : key;
  68. }
  69. if (!opts.emptyAttrs && !opts.xmlMode && value === "") {
  70. return key;
  71. }
  72. return key + "=\"" + (opts.decodeEntities !== false
  73. ? entities_1.encodeXML(value)
  74. : value.replace(/"/g, "&quot;")) + "\"";
  75. })
  76. .join(" ");
  77. }
  78. /**
  79. * Self-enclosing tags
  80. */
  81. var singleTag = new Set([
  82. "area",
  83. "base",
  84. "basefont",
  85. "br",
  86. "col",
  87. "command",
  88. "embed",
  89. "frame",
  90. "hr",
  91. "img",
  92. "input",
  93. "isindex",
  94. "keygen",
  95. "link",
  96. "meta",
  97. "param",
  98. "source",
  99. "track",
  100. "wbr",
  101. ]);
  102. /**
  103. * Renders a DOM node or an array of DOM nodes to a string.
  104. *
  105. * Can be thought of as the equivalent of the `outerHTML` of the passed node(s).
  106. *
  107. * @param node Node to be rendered.
  108. * @param options Changes serialization behavior
  109. */
  110. function render(node, options) {
  111. if (options === void 0) { options = {}; }
  112. var nodes = "length" in node ? node : [node];
  113. var output = "";
  114. for (var i = 0; i < nodes.length; i++) {
  115. output += renderNode(nodes[i], options);
  116. }
  117. return output;
  118. }
  119. exports.default = render;
  120. function renderNode(node, options) {
  121. switch (node.type) {
  122. case ElementType.Root:
  123. return render(node.children, options);
  124. case ElementType.Directive:
  125. case ElementType.Doctype:
  126. return renderDirective(node);
  127. case ElementType.Comment:
  128. return renderComment(node);
  129. case ElementType.CDATA:
  130. return renderCdata(node);
  131. case ElementType.Script:
  132. case ElementType.Style:
  133. case ElementType.Tag:
  134. return renderTag(node, options);
  135. case ElementType.Text:
  136. return renderText(node, options);
  137. }
  138. }
  139. var foreignModeIntegrationPoints = new Set([
  140. "mi",
  141. "mo",
  142. "mn",
  143. "ms",
  144. "mtext",
  145. "annotation-xml",
  146. "foreignObject",
  147. "desc",
  148. "title",
  149. ]);
  150. var foreignElements = new Set(["svg", "math"]);
  151. function renderTag(elem, opts) {
  152. var _a;
  153. // Handle SVG / MathML in HTML
  154. if (opts.xmlMode === "foreign") {
  155. /* Fix up mixed-case element names */
  156. elem.name = (_a = foreignNames_1.elementNames.get(elem.name)) !== null && _a !== void 0 ? _a : elem.name;
  157. /* Exit foreign mode at integration points */
  158. if (elem.parent &&
  159. foreignModeIntegrationPoints.has(elem.parent.name)) {
  160. opts = __assign(__assign({}, opts), { xmlMode: false });
  161. }
  162. }
  163. if (!opts.xmlMode && foreignElements.has(elem.name)) {
  164. opts = __assign(__assign({}, opts), { xmlMode: "foreign" });
  165. }
  166. var tag = "<" + elem.name;
  167. var attribs = formatAttributes(elem.attribs, opts);
  168. if (attribs) {
  169. tag += " " + attribs;
  170. }
  171. if (elem.children.length === 0 &&
  172. (opts.xmlMode
  173. ? // In XML mode or foreign mode, and user hasn't explicitly turned off self-closing tags
  174. opts.selfClosingTags !== false
  175. : // User explicitly asked for self-closing tags, even in HTML mode
  176. opts.selfClosingTags && singleTag.has(elem.name))) {
  177. if (!opts.xmlMode)
  178. tag += " ";
  179. tag += "/>";
  180. }
  181. else {
  182. tag += ">";
  183. if (elem.children.length > 0) {
  184. tag += render(elem.children, opts);
  185. }
  186. if (opts.xmlMode || !singleTag.has(elem.name)) {
  187. tag += "</" + elem.name + ">";
  188. }
  189. }
  190. return tag;
  191. }
  192. function renderDirective(elem) {
  193. return "<" + elem.data + ">";
  194. }
  195. function renderText(elem, opts) {
  196. var data = elem.data || "";
  197. // If entities weren't decoded, no need to encode them back
  198. if (opts.decodeEntities !== false &&
  199. !(!opts.xmlMode &&
  200. elem.parent &&
  201. unencodedElements.has(elem.parent.name))) {
  202. data = entities_1.encodeXML(data);
  203. }
  204. return data;
  205. }
  206. function renderCdata(elem) {
  207. return "<![CDATA[" + elem.children[0].data + "]]>";
  208. }
  209. function renderComment(elem) {
  210. return "<!--" + elem.data + "-->";
  211. }