conventions.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. 'use strict';
  2. /**
  3. * Ponyfill for `Array.prototype.find` which is only available in ES6 runtimes.
  4. *
  5. * Works with anything that has a `length` property and index access properties,
  6. * including NodeList.
  7. *
  8. * @param {T[] | { length: number; [number]: T }} list
  9. * @param {function (item: T, index: number, list:T[]):boolean} predicate
  10. * @param {Partial<Pick<ArrayConstructor['prototype'], 'find'>>?} ac
  11. * Allows injecting a custom implementation in tests (`Array.prototype` by default).
  12. * @returns {T | undefined}
  13. * @template {unknown} T
  14. * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
  15. * @see https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.find
  16. */
  17. function find(list, predicate, ac) {
  18. if (ac === undefined) {
  19. ac = Array.prototype;
  20. }
  21. if (list && typeof ac.find === 'function') {
  22. return ac.find.call(list, predicate);
  23. }
  24. for (var i = 0; i < list.length; i++) {
  25. if (hasOwn(list, i)) {
  26. var item = list[i];
  27. if (predicate.call(undefined, item, i, list)) {
  28. return item;
  29. }
  30. }
  31. }
  32. }
  33. /**
  34. * "Shallow freezes" an object to render it immutable.
  35. * Uses `Object.freeze` if available,
  36. * otherwise the immutability is only in the type.
  37. *
  38. * Is used to create "enum like" objects.
  39. *
  40. * If `Object.getOwnPropertyDescriptors` is available,
  41. * a new object with all properties of object but without any prototype is created and returned
  42. * after freezing it.
  43. *
  44. * @param {T} object
  45. * The object to freeze.
  46. * @param {Pick<ObjectConstructor, 'create' | 'freeze' | 'getOwnPropertyDescriptors'>} [oc=Object]
  47. * `Object` by default,
  48. * allows to inject custom object constructor for tests.
  49. * @returns {Readonly<T>}
  50. * @template {Object} T
  51. * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
  52. * @prettierignore
  53. */
  54. function freeze(object, oc) {
  55. if (oc === undefined) {
  56. oc = Object;
  57. }
  58. if (oc && typeof oc.getOwnPropertyDescriptors === 'function') {
  59. object = oc.create(null, oc.getOwnPropertyDescriptors(object));
  60. }
  61. return oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object;
  62. }
  63. /**
  64. * Implementation for `Object.hasOwn` but ES5 compatible.
  65. *
  66. * @param {any} object
  67. * @param {string | number} key
  68. * @returns {boolean}
  69. */
  70. function hasOwn(object, key) {
  71. return Object.prototype.hasOwnProperty.call(object, key);
  72. }
  73. /**
  74. * Since xmldom can not rely on `Object.assign`,
  75. * it uses/provides a simplified version that is sufficient for its needs.
  76. *
  77. * @param {Object} target
  78. * @param {Object | null | undefined} source
  79. * @returns {Object}
  80. * The target with the merged/overridden properties.
  81. * @throws {TypeError}
  82. * If target is not an object.
  83. * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  84. * @see https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign
  85. */
  86. function assign(target, source) {
  87. if (target === null || typeof target !== 'object') {
  88. throw new TypeError('target is not an object');
  89. }
  90. for (var key in source) {
  91. if (hasOwn(source, key)) {
  92. target[key] = source[key];
  93. }
  94. }
  95. return target;
  96. }
  97. /**
  98. * A number of attributes are boolean attributes.
  99. * The presence of a boolean attribute on an element represents the `true` value,
  100. * and the absence of the attribute represents the `false` value.
  101. *
  102. * If the attribute is present, its value must either be the empty string, or a value that is
  103. * an ASCII case-insensitive match for the attribute's canonical name,
  104. * with no leading or trailing whitespace.
  105. *
  106. * Note: The values `"true"` and `"false"` are not allowed on boolean attributes.
  107. * To represent a `false` value, the attribute has to be omitted altogether.
  108. *
  109. * @see https://html.spec.whatwg.org/#boolean-attributes
  110. * @see https://html.spec.whatwg.org/#attributes-3
  111. */
  112. var HTML_BOOLEAN_ATTRIBUTES = freeze({
  113. allowfullscreen: true,
  114. async: true,
  115. autofocus: true,
  116. autoplay: true,
  117. checked: true,
  118. controls: true,
  119. default: true,
  120. defer: true,
  121. disabled: true,
  122. formnovalidate: true,
  123. hidden: true,
  124. ismap: true,
  125. itemscope: true,
  126. loop: true,
  127. multiple: true,
  128. muted: true,
  129. nomodule: true,
  130. novalidate: true,
  131. open: true,
  132. playsinline: true,
  133. readonly: true,
  134. required: true,
  135. reversed: true,
  136. selected: true,
  137. });
  138. /**
  139. * Check if `name` is matching one of the HTML boolean attribute names.
  140. * This method doesn't check if such attributes are allowed in the context of the current
  141. * document/parsing.
  142. *
  143. * @param {string} name
  144. * @returns {boolean}
  145. * @see {@link HTML_BOOLEAN_ATTRIBUTES}
  146. * @see https://html.spec.whatwg.org/#boolean-attributes
  147. * @see https://html.spec.whatwg.org/#attributes-3
  148. */
  149. function isHTMLBooleanAttribute(name) {
  150. return hasOwn(HTML_BOOLEAN_ATTRIBUTES, name.toLowerCase());
  151. }
  152. /**
  153. * Void elements only have a start tag; end tags must not be specified for void elements.
  154. * These elements should be written as self-closing like this: `<area />`.
  155. * This should not be confused with optional tags that HTML allows to omit the end tag for
  156. * (like `li`, `tr` and others), which can have content after them,
  157. * so they can not be written as self-closing.
  158. * xmldom does not have any logic for optional end tags cases,
  159. * and will report them as a warning.
  160. * Content that would go into the unopened element,
  161. * will instead be added as a sibling text node.
  162. *
  163. * @type {Readonly<{
  164. * area: boolean;
  165. * col: boolean;
  166. * img: boolean;
  167. * wbr: boolean;
  168. * link: boolean;
  169. * hr: boolean;
  170. * source: boolean;
  171. * br: boolean;
  172. * input: boolean;
  173. * param: boolean;
  174. * meta: boolean;
  175. * embed: boolean;
  176. * track: boolean;
  177. * base: boolean;
  178. * }>}
  179. * @see https://html.spec.whatwg.org/#void-elements
  180. * @see https://html.spec.whatwg.org/#optional-tags
  181. */
  182. var HTML_VOID_ELEMENTS = freeze({
  183. area: true,
  184. base: true,
  185. br: true,
  186. col: true,
  187. embed: true,
  188. hr: true,
  189. img: true,
  190. input: true,
  191. link: true,
  192. meta: true,
  193. param: true,
  194. source: true,
  195. track: true,
  196. wbr: true,
  197. });
  198. /**
  199. * Check if `tagName` is matching one of the HTML void element names.
  200. * This method doesn't check if such tags are allowed in the context of the current
  201. * document/parsing.
  202. *
  203. * @param {string} tagName
  204. * @returns {boolean}
  205. * @see {@link HTML_VOID_ELEMENTS}
  206. * @see https://html.spec.whatwg.org/#void-elements
  207. */
  208. function isHTMLVoidElement(tagName) {
  209. return hasOwn(HTML_VOID_ELEMENTS, tagName.toLowerCase());
  210. }
  211. /**
  212. * Tag names that are raw text elements according to HTML spec.
  213. * The value denotes whether they are escapable or not.
  214. *
  215. * @see {@link isHTMLEscapableRawTextElement}
  216. * @see {@link isHTMLRawTextElement}
  217. * @see https://html.spec.whatwg.org/#raw-text-elements
  218. * @see https://html.spec.whatwg.org/#escapable-raw-text-elements
  219. */
  220. var HTML_RAW_TEXT_ELEMENTS = freeze({
  221. script: false,
  222. style: false,
  223. textarea: true,
  224. title: true,
  225. });
  226. /**
  227. * Check if `tagName` is matching one of the HTML raw text element names.
  228. * This method doesn't check if such tags are allowed in the context of the current
  229. * document/parsing.
  230. *
  231. * @param {string} tagName
  232. * @returns {boolean}
  233. * @see {@link isHTMLEscapableRawTextElement}
  234. * @see {@link HTML_RAW_TEXT_ELEMENTS}
  235. * @see https://html.spec.whatwg.org/#raw-text-elements
  236. * @see https://html.spec.whatwg.org/#escapable-raw-text-elements
  237. */
  238. function isHTMLRawTextElement(tagName) {
  239. var key = tagName.toLowerCase();
  240. return hasOwn(HTML_RAW_TEXT_ELEMENTS, key) && !HTML_RAW_TEXT_ELEMENTS[key];
  241. }
  242. /**
  243. * Check if `tagName` is matching one of the HTML escapable raw text element names.
  244. * This method doesn't check if such tags are allowed in the context of the current
  245. * document/parsing.
  246. *
  247. * @param {string} tagName
  248. * @returns {boolean}
  249. * @see {@link isHTMLRawTextElement}
  250. * @see {@link HTML_RAW_TEXT_ELEMENTS}
  251. * @see https://html.spec.whatwg.org/#raw-text-elements
  252. * @see https://html.spec.whatwg.org/#escapable-raw-text-elements
  253. */
  254. function isHTMLEscapableRawTextElement(tagName) {
  255. var key = tagName.toLowerCase();
  256. return hasOwn(HTML_RAW_TEXT_ELEMENTS, key) && HTML_RAW_TEXT_ELEMENTS[key];
  257. }
  258. /**
  259. * Only returns true if `value` matches MIME_TYPE.HTML, which indicates an HTML document.
  260. *
  261. * @param {string} mimeType
  262. * @returns {mimeType is 'text/html'}
  263. * @see https://www.iana.org/assignments/media-types/text/html
  264. * @see https://en.wikipedia.org/wiki/HTML
  265. * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString
  266. * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring
  267. */
  268. function isHTMLMimeType(mimeType) {
  269. return mimeType === MIME_TYPE.HTML;
  270. }
  271. /**
  272. * For both the `text/html` and the `application/xhtml+xml` namespace the spec defines that the
  273. * HTML namespace is provided as the default.
  274. *
  275. * @param {string} mimeType
  276. * @returns {boolean}
  277. * @see https://dom.spec.whatwg.org/#dom-document-createelement
  278. * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
  279. * @see https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
  280. */
  281. function hasDefaultHTMLNamespace(mimeType) {
  282. return isHTMLMimeType(mimeType) || mimeType === MIME_TYPE.XML_XHTML_APPLICATION;
  283. }
  284. /**
  285. * All mime types that are allowed as input to `DOMParser.parseFromString`
  286. *
  287. * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02
  288. * MDN
  289. * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype
  290. * WHATWG HTML Spec
  291. * @see {@link DOMParser.prototype.parseFromString}
  292. */
  293. var MIME_TYPE = freeze({
  294. /**
  295. * `text/html`, the only mime type that triggers treating an XML document as HTML.
  296. *
  297. * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
  298. * @see https://en.wikipedia.org/wiki/HTML Wikipedia
  299. * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
  300. * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring
  301. * WHATWG HTML Spec
  302. */
  303. HTML: 'text/html',
  304. /**
  305. * `application/xml`, the standard mime type for XML documents.
  306. *
  307. * @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType
  308. * registration
  309. * @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303
  310. * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
  311. */
  312. XML_APPLICATION: 'application/xml',
  313. /**
  314. * `text/xml`, an alias for `application/xml`.
  315. *
  316. * @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303
  317. * @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration
  318. * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
  319. */
  320. XML_TEXT: 'text/xml',
  321. /**
  322. * `application/xhtml+xml`, indicates an XML document that has the default HTML namespace,
  323. * but is parsed as an XML document.
  324. *
  325. * @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType
  326. * registration
  327. * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec
  328. * @see https://en.wikipedia.org/wiki/XHTML Wikipedia
  329. */
  330. XML_XHTML_APPLICATION: 'application/xhtml+xml',
  331. /**
  332. * `image/svg+xml`,
  333. *
  334. * @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration
  335. * @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1
  336. * @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia
  337. */
  338. XML_SVG_IMAGE: 'image/svg+xml',
  339. });
  340. /**
  341. * @typedef {'application/xhtml+xml' | 'application/xml' | 'image/svg+xml' | 'text/html' | 'text/xml'}
  342. * MimeType
  343. */
  344. /**
  345. * @type {MimeType[]}
  346. * @private
  347. * Basically `Object.values`, which is not available in ES5.
  348. */
  349. var _MIME_TYPES = Object.keys(MIME_TYPE).map(function (key) {
  350. return MIME_TYPE[key];
  351. });
  352. /**
  353. * Only returns true if `mimeType` is one of the allowed values for
  354. * `DOMParser.parseFromString`.
  355. *
  356. * @param {string} mimeType
  357. * @returns {mimeType is 'application/xhtml+xml' | 'application/xml' | 'image/svg+xml' | 'text/html' | 'text/xml'}
  358. *
  359. */
  360. function isValidMimeType(mimeType) {
  361. return _MIME_TYPES.indexOf(mimeType) > -1;
  362. }
  363. /**
  364. * Namespaces that are used in this code base.
  365. *
  366. * @see http://www.w3.org/TR/REC-xml-names
  367. */
  368. var NAMESPACE = freeze({
  369. /**
  370. * The XHTML namespace.
  371. *
  372. * @see http://www.w3.org/1999/xhtml
  373. */
  374. HTML: 'http://www.w3.org/1999/xhtml',
  375. /**
  376. * The SVG namespace.
  377. *
  378. * @see http://www.w3.org/2000/svg
  379. */
  380. SVG: 'http://www.w3.org/2000/svg',
  381. /**
  382. * The `xml:` namespace.
  383. *
  384. * @see http://www.w3.org/XML/1998/namespace
  385. */
  386. XML: 'http://www.w3.org/XML/1998/namespace',
  387. /**
  388. * The `xmlns:` namespace.
  389. *
  390. * @see https://www.w3.org/2000/xmlns/
  391. */
  392. XMLNS: 'http://www.w3.org/2000/xmlns/',
  393. });
  394. exports.assign = assign;
  395. exports.find = find;
  396. exports.freeze = freeze;
  397. exports.HTML_BOOLEAN_ATTRIBUTES = HTML_BOOLEAN_ATTRIBUTES;
  398. exports.HTML_RAW_TEXT_ELEMENTS = HTML_RAW_TEXT_ELEMENTS;
  399. exports.HTML_VOID_ELEMENTS = HTML_VOID_ELEMENTS;
  400. exports.hasDefaultHTMLNamespace = hasDefaultHTMLNamespace;
  401. exports.hasOwn = hasOwn;
  402. exports.isHTMLBooleanAttribute = isHTMLBooleanAttribute;
  403. exports.isHTMLRawTextElement = isHTMLRawTextElement;
  404. exports.isHTMLEscapableRawTextElement = isHTMLEscapableRawTextElement;
  405. exports.isHTMLMimeType = isHTMLMimeType;
  406. exports.isHTMLVoidElement = isHTMLVoidElement;
  407. exports.isValidMimeType = isValidMimeType;
  408. exports.MIME_TYPE = MIME_TYPE;
  409. exports.NAMESPACE = NAMESPACE;