UNPKG

xmldom-sre

Version:

A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.

376 lines (353 loc) 12.2 kB
'use strict'; /** * Ponyfill for `Array.prototype.find` which is only available in ES6 runtimes. * * Works with anything that has a `length` property and index access properties, including NodeList. * * @template {unknown} T * @param {Array<T> | ({length:number, [number]: T})} list * @param {function (item: T, index: number, list:Array<T> | ({length:number, [number]: T})):boolean} predicate * @param {Partial<Pick<ArrayConstructor['prototype'], 'find'>>?} ac `Array.prototype` by default, * allows injecting a custom implementation in tests * @returns {T | undefined} * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find * @see https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.find */ function find(list, predicate, ac) { if (ac === undefined) { ac = Array.prototype; } if (list && typeof ac.find === 'function') { return ac.find.call(list, predicate); } for (var i = 0; i < list.length; i++) { if (Object.prototype.hasOwnProperty.call(list, i)) { var item = list[i]; if (predicate.call(undefined, item, i, list)) { return item; } } } } /** * "Shallow freezes" an object to render it immutable. * Uses `Object.freeze` if available, * otherwise the immutability is only in the type. * * Is used to create "enum like" objects. * * @template T * @param {T} object the object to freeze * @param {Pick<ObjectConstructor, 'freeze'>} [oc=Object] `Object` by default, * allows to inject custom object constructor for tests * @returns {Readonly<T>} * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze */ function freeze(object, oc) { if (oc === undefined) { oc = Object; } return oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object; } /** * Since we can not rely on `Object.assign` we provide a simplified version * that is sufficient for our needs. * * @param {Object} target * @param {Object | null | undefined} source * * @returns {Object} target * @throws TypeError if target is not an object * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign * @see https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign */ function assign(target, source) { if (target === null || typeof target !== 'object') { throw new TypeError('target is not an object'); } for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } return target; } /** * A number of attributes are boolean attributes. * The presence of a boolean attribute on an element represents the `true` value, * and the absence of the attribute represents the `false` value. * * If the attribute is present, its value must either be the empty string * or a value that is an ASCII case-insensitive match for the attribute's canonical name, * with no leading or trailing whitespace. * * Note: The values `"true"` and `"false"` are not allowed on boolean attributes. * To represent a `false` value, the attribute has to be omitted altogether. * * @see https://html.spec.whatwg.org/#boolean-attributes * @see https://html.spec.whatwg.org/#attributes-3 */ var HTML_BOOLEAN_ATTRIBUTES = freeze({ allowfullscreen: true, async: true, autofocus: true, autoplay: true, checked: true, controls: true, default: true, defer: true, disabled: true, formnovalidate: true, hidden: true, ismap: true, itemscope: true, loop: true, multiple: true, muted: true, nomodule: true, novalidate: true, open: true, playsinline: true, readonly: true, required: true, reversed: true, selected: true, }); /** * Check if `name` is matching one of the HTML boolean attribute names. * This method doesn't check if such attributes are allowed in the context of the current document/parsing. * * @param {string} name * @return {boolean} * @see HTML_BOOLEAN_ATTRIBUTES * @see https://html.spec.whatwg.org/#boolean-attributes * @see https://html.spec.whatwg.org/#attributes-3 */ function isHTMLBooleanAttribute(name) { return HTML_BOOLEAN_ATTRIBUTES.hasOwnProperty(name.toLowerCase()); } /** * Void elements only have a start tag; end tags must not be specified for void elements. * These elements should be written as self closing like this: `<area />`. * This should not be confused with optional tags that HTML allows to omit the end tag for * (like `li`, `tr` and others), which can have content after them, * so they can not be written as self closing. * xmldom does not have any logic for optional end tags cases and will report them as a warning. * Content that would go into the unopened element will instead be added as a sibling text node. * * @type {Readonly<{area: boolean, col: boolean, img: boolean, wbr: boolean, link: boolean, hr: boolean, source: boolean, br: boolean, input: boolean, param: boolean, meta: boolean, embed: boolean, track: boolean, base: boolean}>} * @see https://html.spec.whatwg.org/#void-elements * @see https://html.spec.whatwg.org/#optional-tags */ var HTML_VOID_ELEMENTS = freeze({ area: true, base: true, br: true, col: true, embed: true, hr: true, img: true, input: true, link: true, meta: true, param: true, source: true, track: true, wbr: true, }); /** * Check if `tagName` is matching one of the HTML void element names. * This method doesn't check if such tags are allowed * in the context of the current document/parsing. * * @param {string} tagName * @return {boolean} * @see HTML_VOID_ELEMENTS * @see https://html.spec.whatwg.org/#void-elements */ function isHTMLVoidElement(tagName) { return HTML_VOID_ELEMENTS.hasOwnProperty(tagName.toLowerCase()); } /** * Tag names that are raw text elements according to HTML spec. * The value denotes whether they are escapable or not. * * @see isHTMLEscapableRawTextElement * @see isHTMLRawTextElement * @see https://html.spec.whatwg.org/#raw-text-elements * @see https://html.spec.whatwg.org/#escapable-raw-text-elements */ var HTML_RAW_TEXT_ELEMENTS = freeze({ script: false, style: false, textarea: true, title: true, }); /** * Check if `tagName` is matching one of the HTML raw text element names. * This method doesn't check if such tags are allowed * in the context of the current document/parsing. * * @param {string} tagName * @return {boolean} * @see isHTMLEscapableRawTextElement * @see HTML_RAW_TEXT_ELEMENTS * @see https://html.spec.whatwg.org/#raw-text-elements * @see https://html.spec.whatwg.org/#escapable-raw-text-elements */ function isHTMLRawTextElement(tagName) { var key = tagName.toLowerCase(); return HTML_RAW_TEXT_ELEMENTS.hasOwnProperty(key) && !HTML_RAW_TEXT_ELEMENTS[key]; } /** * Check if `tagName` is matching one of the HTML escapable raw text element names. * This method doesn't check if such tags are allowed * in the context of the current document/parsing. * * @param {string} tagName * @return {boolean} * @see isHTMLRawTextElement * @see HTML_RAW_TEXT_ELEMENTS * @see https://html.spec.whatwg.org/#raw-text-elements * @see https://html.spec.whatwg.org/#escapable-raw-text-elements */ function isHTMLEscapableRawTextElement(tagName) { var key = tagName.toLowerCase(); return HTML_RAW_TEXT_ELEMENTS.hasOwnProperty(key) && HTML_RAW_TEXT_ELEMENTS[key]; } /** * All mime types that are allowed as input to `DOMParser.parseFromString` * * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02 MDN * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype WHATWG HTML Spec * @see DOMParser.prototype.parseFromString */ var MIME_TYPE = freeze({ /** * `text/html`, the only mime type that triggers treating an XML document as HTML. * * @see DOMParser.SupportedType.isHTML * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration * @see https://en.wikipedia.org/wiki/HTML Wikipedia * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring WHATWG HTML Spec */ HTML: 'text/html', /** * Helper method to check a mime type if it indicates an HTML document * * @param {string} [value] * @returns {boolean} * * @see [IANA MimeType registration](https://www.iana.org/assignments/media-types/text/html) * @see [Wikipedia](https://en.wikipedia.org/wiki/HTML) * @see [`DOMParser.parseFromString` @ MDN](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString) * @see [`DOMParser.parseFromString` @ HTML Specification](https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring) */ isHTML: function (value) { return value === MIME_TYPE.HTML; }, /** * For both the `text/html` and the `application/xhtml+xml` namespace * the spec defines that the HTML namespace is provided as the default in some cases. * * @param {string} mimeType * @returns {boolean} * * @see https://dom.spec.whatwg.org/#dom-document-createelement * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument * @see https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument */ hasDefaultHTMLNamespace: function (mimeType) { return MIME_TYPE.isHTML(mimeType) || mimeType === MIME_TYPE.XML_XHTML_APPLICATION; }, /** * `application/xml`, the standard mime type for XML documents. * * @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType registration * @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303 * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia */ XML_APPLICATION: 'application/xml', /** * `text/html`, an alias for `application/xml`. * * @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303 * @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia */ XML_TEXT: 'text/xml', /** * `application/xhtml+xml`, indicates an XML document that has the default HTML namespace, * but is parsed as an XML document. * * @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType registration * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec * @see https://en.wikipedia.org/wiki/XHTML Wikipedia */ XML_XHTML_APPLICATION: 'application/xhtml+xml', /** * `image/svg+xml`, * * @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration * @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1 * @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia */ XML_SVG_IMAGE: 'image/svg+xml', }); /** * Namespaces that are used in this code base. * * @see http://www.w3.org/TR/REC-xml-names */ var NAMESPACE = freeze({ /** * The XHTML namespace. * * @see http://www.w3.org/1999/xhtml */ HTML: 'http://www.w3.org/1999/xhtml', /** * Checks if `uri` equals `NAMESPACE.HTML`. * * @param {string} [uri] * * @see NAMESPACE.HTML */ isHTML: function (uri) { return uri === NAMESPACE.HTML; }, /** * The SVG namespace. * * @see http://www.w3.org/2000/svg */ SVG: 'http://www.w3.org/2000/svg', /** * The `xml:` namespace. * * @see http://www.w3.org/XML/1998/namespace */ XML: 'http://www.w3.org/XML/1998/namespace', /** * The `xmlns:` namespace * * @see https://www.w3.org/2000/xmlns/ */ XMLNS: 'http://www.w3.org/2000/xmlns/', }); exports.assign = assign; exports.find = find; exports.freeze = freeze; exports.HTML_BOOLEAN_ATTRIBUTES = HTML_BOOLEAN_ATTRIBUTES; exports.HTML_RAW_TEXT_ELEMENTS = HTML_RAW_TEXT_ELEMENTS; exports.HTML_VOID_ELEMENTS = HTML_VOID_ELEMENTS; exports.isHTMLBooleanAttribute = isHTMLBooleanAttribute; exports.isHTMLRawTextElement = isHTMLRawTextElement; exports.isHTMLEscapableRawTextElement = isHTMLEscapableRawTextElement; exports.isHTMLVoidElement = isHTMLVoidElement; exports.MIME_TYPE = MIME_TYPE; exports.NAMESPACE = NAMESPACE;