data.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author sheo13666q @sheo13666q
  4. */
  5. "use strict";
  6. // GENERATED by tooling/generate-html-data.js — do not edit.
  7. // cspell:ignore advasoft altglyph altglyphdef altglyphitem animatecolor animatemotion animatetransform arcrole aswedit attributename attributetype basefrequency baseprofile bgsound calcmode clippathunits contenteditable diffuseconstant enterkeyhint fedropshadow filterunits formenctype formmethod formtarget glyphref gradienttransform gradientunits hotjava hotmetal inputmode jscript kernelmatrix kernelunitlength keypoints keysplines keytimes limitingconeangle livescript markerheight markerwidth maskcontentunits maskunits metrius mtext numoctaves pathlength patterncontentunits patterntransform patternunits pointsatx pointsaty pointsatz preservealpha primitiveunits refx refy repeatcount repeatdur requiredextensions requiredfeatures silmaril softquad specularconstant specularexponent startoffset stddeviation stitchtiles surfacescale systemlanguage tablevalues targetx targety textlength viewbox viewtarget webtechs writingsuggestions xchannelselector ychannelselector
  8. // Reflected-attribute tables from webref's extraction of the HTML IDL (see tooling/generate-html-data.js); everything else is the
  9. // generator's SUPPLEMENT, which carries the spec facts no dataset states.
  10. /**
  11. * An "adjust … name" table: each name under the lowercase spelling the tokenizer
  12. * hands over, which is that name lowercased — so only the names are stated and
  13. * no key can drift from the value it maps to. Null-prototype, so a name like
  14. * `constructor` is a miss rather than a hit.
  15. * @param {string[]} names the adjusted names
  16. * @returns {Record<string, string>} the table
  17. */
  18. const adjusted = (names) => {
  19. /** @type {Record<string, string>} */
  20. const table = Object.create(null);
  21. for (const name of names) table[name.toLowerCase()] = name;
  22. return table;
  23. };
  24. /**
  25. * §13.1.2.4: the elements a `<p>` end tag may be omitted in front of.
  26. * @type {Set<string>}
  27. */
  28. const P_FOLLOWED_BY = new Set([
  29. "address",
  30. "article",
  31. "aside",
  32. "blockquote",
  33. "details",
  34. "div",
  35. "dl",
  36. "fieldset",
  37. "figcaption",
  38. "figure",
  39. "footer",
  40. "form",
  41. "h1",
  42. "h2",
  43. "h3",
  44. "h4",
  45. "h5",
  46. "h6",
  47. "header",
  48. "hgroup",
  49. "hr",
  50. "main",
  51. "menu",
  52. "nav",
  53. "ol",
  54. "p",
  55. "pre",
  56. "section",
  57. "table",
  58. "ul"
  59. ]);
  60. /**
  61. * §13.1.2.4: the element names whose end tag may be omitted when the next
  62. * sibling is one of the mapped names. `<html>`, `<head>` and `<body>` are
  63. * deliberately absent — their end tags are omissible too, but non-browser
  64. * consumers routinely mis-parse a document that is missing them.
  65. * @type {Map<string, Set<string>>}
  66. */
  67. const OPTIONAL_END_TAG_FOLLOWERS = new Map([
  68. ["li", new Set(["li"])],
  69. ["dt", new Set(["dt", "dd"])],
  70. ["dd", new Set(["dd", "dt"])],
  71. ["rt", new Set(["rt", "rp"])],
  72. ["rp", new Set(["rt", "rp"])],
  73. ["optgroup", new Set(["optgroup"])],
  74. ["option", new Set(["option", "optgroup"])],
  75. ["thead", new Set(["tbody", "tfoot"])],
  76. ["tbody", new Set(["tbody", "tfoot"])],
  77. ["tfoot", new Set()],
  78. ["tr", new Set(["tr"])],
  79. ["td", new Set(["td", "th"])],
  80. ["th", new Set(["td", "th"])],
  81. ["p", P_FOLLOWED_BY]
  82. ]);
  83. /**
  84. * §13.1.2.4: the elements whose end tag may be omitted unless ASCII whitespace
  85. * or a comment follows. A different condition from the follower-set rule above:
  86. * what closes these is the insertion mode, whatever the next element is, so only
  87. * a node that would move inside them keeps the tag.
  88. * @type {Set<string>}
  89. */
  90. const OPTIONAL_END_TAG_UNLESS_TRAILING_NODE = new Set(["caption", "colgroup"]);
  91. /**
  92. * The subset of `OPTIONAL_END_TAG_FOLLOWERS` that may also drop the end tag with
  93. * nothing left in the parent. `<dt>` and `<thead>` are absent: the spec gives
  94. * them no such clause.
  95. * @type {Set<string>}
  96. */
  97. const OPTIONAL_END_TAG_AT_END = new Set([
  98. "li",
  99. "dd",
  100. "rt",
  101. "rp",
  102. "optgroup",
  103. "option",
  104. "tbody",
  105. "tfoot",
  106. "tr",
  107. "td",
  108. "th",
  109. "p"
  110. ]);
  111. /**
  112. * Every attribute name a value rewrite can act on. One miss here rules an
  113. * attribute out of the whole chain, which is what most of them are.
  114. * @type {Set<string>}
  115. */
  116. const REWRITABLE_ATTRIBUTES = new Set([
  117. "accept",
  118. "accesskey",
  119. "action",
  120. "autocapitalize",
  121. "autocomplete",
  122. "blocking",
  123. "cite",
  124. "class",
  125. "codebase",
  126. "cols",
  127. "colspan",
  128. "content",
  129. "contenteditable",
  130. "coords",
  131. "crossorigin",
  132. "data",
  133. "decoding",
  134. "dir",
  135. "draggable",
  136. "enctype",
  137. "enterkeyhint",
  138. "fetchpriority",
  139. "for",
  140. "formaction",
  141. "formenctype",
  142. "formmethod",
  143. "headers",
  144. "headingoffset",
  145. "height",
  146. "hidden",
  147. "href",
  148. "hspace",
  149. "imagesrcset",
  150. "inputmode",
  151. "itemprop",
  152. "itemref",
  153. "itemtype",
  154. "kind",
  155. "loading",
  156. "longdesc",
  157. "lowsrc",
  158. "manifest",
  159. "maxlength",
  160. "method",
  161. "minlength",
  162. "part",
  163. "ping",
  164. "popover",
  165. "poster",
  166. "preload",
  167. "referrerpolicy",
  168. "rel",
  169. "rows",
  170. "rowspan",
  171. "sandbox",
  172. "scope",
  173. "size",
  174. "sizes",
  175. "span",
  176. "spellcheck",
  177. "src",
  178. "srcset",
  179. "start",
  180. "style",
  181. "tabindex",
  182. "translate",
  183. "type",
  184. "value",
  185. "vspace",
  186. "width",
  187. "writingsuggestions"
  188. ]);
  189. /**
  190. * Every name `ENUMERATED_KEYWORDS` scopes, whatever the element. One miss here
  191. * rules an attribute out, which is what keeps the enumerated fold off the cost
  192. * of every attribute that enumerates nothing.
  193. * @type {Set<string>}
  194. */
  195. const ENUMERATED_ATTRIBUTE_NAMES = new Set([
  196. "autocapitalize",
  197. "autocomplete",
  198. "contenteditable",
  199. "crossorigin",
  200. "decoding",
  201. "dir",
  202. "draggable",
  203. "enctype",
  204. "enterkeyhint",
  205. "fetchpriority",
  206. "formenctype",
  207. "formmethod",
  208. "hidden",
  209. "inputmode",
  210. "kind",
  211. "loading",
  212. "method",
  213. "popover",
  214. "preload",
  215. "referrerpolicy",
  216. "scope",
  217. "spellcheck",
  218. "translate",
  219. "type",
  220. "writingsuggestions"
  221. ]);
  222. /**
  223. * A void element that belongs in the head: with no attributes it states nothing,
  224. * so `removeEmptyElements` may drop it even though every other void element is
  225. * kept. Derived as the head elements that are also void.
  226. * @type {Set<string>}
  227. */
  228. const EMPTY_METADATA_ELEMENTS = new Set(["base", "link", "meta"]);
  229. /**
  230. * §13.1.2.4: the elements that keep a `<body>` start tag when the body opens
  231. * with one — the parser reads them as head content and would move them out of
  232. * the body once the tag goes.
  233. * @type {Set<string>}
  234. */
  235. const BODY_START_KEPT_BEFORE = new Set([
  236. "link",
  237. "meta",
  238. "noscript",
  239. "script",
  240. "style",
  241. "template"
  242. ]);
  243. /**
  244. * Parents whose own end tag generates implied end tags, so a trailing `</p>`
  245. * inside one is closed by it and can be left out (§13.2.6.4.7). Listed rather
  246. * than excluded: an end tag not named here is "any other end tag", which a
  247. * special element on the stack makes the parser ignore — so anything unknown,
  248. * a custom element included, keeps its `</p>`.
  249. * @type {Set<string>}
  250. */
  251. const P_ENDS_ON_PARENT_END_TAG = new Set([
  252. "address",
  253. "applet",
  254. "article",
  255. "aside",
  256. "blockquote",
  257. "body",
  258. "button",
  259. "caption",
  260. "center",
  261. "colgroup",
  262. "dd",
  263. "details",
  264. "dialog",
  265. "dir",
  266. "div",
  267. "dl",
  268. "dt",
  269. "fieldset",
  270. "figcaption",
  271. "figure",
  272. "footer",
  273. "form",
  274. "h1",
  275. "h2",
  276. "h3",
  277. "h4",
  278. "h5",
  279. "h6",
  280. "head",
  281. "header",
  282. "hgroup",
  283. "html",
  284. "li",
  285. "listing",
  286. "main",
  287. "marquee",
  288. "menu",
  289. "nav",
  290. "object",
  291. "ol",
  292. "pre",
  293. "search",
  294. "section",
  295. "select",
  296. "summary",
  297. "table",
  298. "tbody",
  299. "td",
  300. "template",
  301. "tfoot",
  302. "th",
  303. "thead",
  304. "tr",
  305. "ul"
  306. ]);
  307. /**
  308. * §2.4.2 boolean attributes, mapped to the elements each one is boolean *on*
  309. * (`null` = a global attribute). Elsewhere the same name is an ordinary
  310. * attribute whose value a script may read.
  311. * @type {Map<string, Set<string> | null>}
  312. */
  313. const BOOLEAN_ATTRIBUTES = new Map([
  314. ["allowfullscreen", new Set(["iframe"])],
  315. ["alpha", new Set(["input"])],
  316. ["async", new Set(["script"])],
  317. ["autofocus", null],
  318. ["autoplay", new Set(["audio", "video"])],
  319. ["checked", new Set(["input"])],
  320. ["compact", new Set(["dl", "menu", "ol", "ul"])],
  321. ["controls", new Set(["audio", "img", "video"])],
  322. ["declare", new Set(["object"])],
  323. ["default", new Set(["track"])],
  324. ["defer", new Set(["script"])],
  325. [
  326. "disabled",
  327. new Set([
  328. "button",
  329. "fieldset",
  330. "input",
  331. "link",
  332. "optgroup",
  333. "option",
  334. "select",
  335. "textarea"
  336. ])
  337. ],
  338. ["formnovalidate", new Set(["button", "input"])],
  339. ["headingreset", null],
  340. ["inert", null],
  341. ["ismap", new Set(["img"])],
  342. ["itemscope", null],
  343. ["loop", new Set(["audio", "video"])],
  344. ["multiple", new Set(["input", "select"])],
  345. ["muted", new Set(["audio", "video"])],
  346. ["nohref", new Set(["area"])],
  347. ["nomodule", new Set(["script"])],
  348. ["noshade", new Set(["hr"])],
  349. ["novalidate", new Set(["form"])],
  350. ["nowrap", new Set(["td", "th"])],
  351. ["open", new Set(["details", "dialog"])],
  352. ["playsinline", new Set(["video"])],
  353. ["readonly", new Set(["input", "textarea"])],
  354. ["required", new Set(["input", "select", "textarea"])],
  355. ["reversed", new Set(["ol"])],
  356. ["selected", new Set(["option"])],
  357. ["shadowrootclonable", new Set(["template"])],
  358. ["shadowrootdelegatesfocus", new Set(["template"])],
  359. ["shadowrootserializable", new Set(["template"])]
  360. ]);
  361. /**
  362. * The attributes whose value is a srcset (WHATWG "parse a srcset attribute").
  363. * @type {Set<string>}
  364. */
  365. const SRCSET_ATTRIBUTES = new Set(["srcset", "imagesrcset"]);
  366. /**
  367. * The attributes whose value is an ASCII-whitespace-separated token list, mapped
  368. * to the elements they are one on (`null` = a global attribute), so collapsing
  369. * the separators keeps the set the DOM reads. The element matters: `for` is a
  370. * token list on `<output>` but one id on `<label>`, and an id may contain a
  371. * space; `sizes` is one on `<link>` but a source-size list on `<img>`.
  372. * @type {Map<string, Set<string> | null>}
  373. */
  374. const TOKEN_LIST_ATTRIBUTES = new Map([
  375. ["accesskey", null],
  376. ["blocking", new Set(["link", "script", "style"])],
  377. ["class", null],
  378. ["for", new Set(["output"])],
  379. ["headers", new Set(["td", "th"])],
  380. ["itemprop", null],
  381. ["itemref", null],
  382. ["itemtype", null],
  383. ["part", null],
  384. ["ping", new Set(["a", "area"])],
  385. ["rel", new Set(["a", "area", "form", "link"])],
  386. ["sandbox", new Set(["iframe"])],
  387. ["sizes", new Set(["link"])]
  388. ]);
  389. /**
  390. * The token lists reflected as a `DOMTokenList`, which is an ordered *set* — a
  391. * repeated token was never a second token, so dropping it changes nothing the
  392. * DOM reads. The rest are read back as written, and `ping` sends one request
  393. * per token, so a repeat there is not the printer's to drop.
  394. * @type {Set<string>}
  395. */
  396. const DOM_TOKEN_LIST_ATTRIBUTES = new Set([
  397. "blocking",
  398. "class",
  399. "for",
  400. "itemprop",
  401. "itemref",
  402. "itemtype",
  403. "part",
  404. "rel",
  405. "sandbox",
  406. "sizes"
  407. ]);
  408. /**
  409. * Attributes parsed as a URL, mapped to the elements they are one on. The URL
  410. * parser strips leading and trailing C0 controls and spaces, so trimming the
  411. * ASCII whitespace among them resolves to the same URL.
  412. * @type {Map<string, Set<string> | null>}
  413. */
  414. const URL_ATTRIBUTES = new Map([
  415. ["action", new Set(["form"])],
  416. ["cite", new Set(["blockquote", "del", "ins", "q"])],
  417. ["codebase", new Set(["object"])],
  418. ["data", new Set(["object"])],
  419. ["formaction", new Set(["button", "input"])],
  420. ["href", new Set(["a", "area", "base", "link"])],
  421. ["longdesc", new Set(["iframe", "img"])],
  422. ["lowsrc", new Set(["img"])],
  423. ["manifest", new Set(["html"])],
  424. ["poster", new Set(["video"])],
  425. [
  426. "src",
  427. new Set([
  428. "audio",
  429. "embed",
  430. "iframe",
  431. "img",
  432. "input",
  433. "script",
  434. "source",
  435. "track",
  436. "video"
  437. ])
  438. ]
  439. ]);
  440. /**
  441. * Attributes parsed with the integer rules, mapped to the elements they are one
  442. * on (`null` = a global attribute). Those rules skip leading whitespace and
  443. * stop at the first non-digit, so trimming and dropping leading zeros parse the
  444. * same. `width` / `height` are absent on `<td>` and `<table>`, where the
  445. * legacy dimension grammar also admits a percentage.
  446. * @type {Map<string, Set<string> | null>}
  447. */
  448. const INTEGER_ATTRIBUTES = new Map([
  449. ["cols", new Set(["textarea"])],
  450. ["colspan", new Set(["td", "th"])],
  451. ["headingoffset", null],
  452. [
  453. "height",
  454. new Set([
  455. "canvas",
  456. "embed",
  457. "iframe",
  458. "img",
  459. "input",
  460. "object",
  461. "source",
  462. "video"
  463. ])
  464. ],
  465. ["hspace", new Set(["img", "object"])],
  466. ["maxlength", new Set(["input", "textarea"])],
  467. ["minlength", new Set(["input", "textarea"])],
  468. ["rows", new Set(["textarea"])],
  469. ["rowspan", new Set(["td", "th"])],
  470. ["size", new Set(["input", "select"])],
  471. ["span", new Set(["col", "colgroup"])],
  472. ["start", new Set(["ol"])],
  473. ["tabindex", null],
  474. ["value", new Set(["li"])],
  475. ["vspace", new Set(["img", "object"])],
  476. [
  477. "width",
  478. new Set([
  479. "canvas",
  480. "embed",
  481. "iframe",
  482. "img",
  483. "input",
  484. "object",
  485. "pre",
  486. "source",
  487. "video"
  488. ])
  489. ]
  490. ]);
  491. /**
  492. * The subset of `INTEGER_ATTRIBUTES` parsed with the "rules for parsing
  493. * integers" rather than the non-negative ones — only those accept a `+` or
  494. * `-`, so elsewhere a signed value does not parse at all and has to stand.
  495. * @type {Set<string>}
  496. */
  497. const SIGNED_INTEGER_ATTRIBUTES = new Set(["start", "tabindex", "value"]);
  498. /**
  499. * Attributes whose value is a comma-separated list, so the whitespace around
  500. * each comma and around the ends carries nothing. Whitespace *inside* an item is
  501. * never dropped: it belongs to the token `accept` keeps, separates numbers in
  502. * `coords`, and carries the media condition in `sizes`.
  503. * @type {Set<string>}
  504. */
  505. const COMMA_LIST_ATTRIBUTES = new Set(["accept", "coords", "sizes"]);
  506. /**
  507. * §13.1.2 void elements: no end tag, and no children to close one over.
  508. * @type {Set<string>}
  509. */
  510. const VOID = new Set([
  511. "area",
  512. "base",
  513. "br",
  514. "col",
  515. "embed",
  516. "hr",
  517. "img",
  518. "input",
  519. "keygen",
  520. "link",
  521. "meta",
  522. "param",
  523. "source",
  524. "track",
  525. "wbr"
  526. ]);
  527. /**
  528. * §13.2.4.2's "special" category — the elements the adoption agency and the scope tests treat as barriers.
  529. * @type {Set<string>}
  530. */
  531. const SPECIAL = new Set([
  532. "address",
  533. "applet",
  534. "area",
  535. "article",
  536. "aside",
  537. "base",
  538. "basefont",
  539. "bgsound",
  540. "blockquote",
  541. "body",
  542. "br",
  543. "button",
  544. "caption",
  545. "center",
  546. "col",
  547. "colgroup",
  548. "dd",
  549. "details",
  550. "dir",
  551. "div",
  552. "dl",
  553. "dt",
  554. "embed",
  555. "fieldset",
  556. "figcaption",
  557. "figure",
  558. "footer",
  559. "form",
  560. "frame",
  561. "frameset",
  562. "h1",
  563. "h2",
  564. "h3",
  565. "h4",
  566. "h5",
  567. "h6",
  568. "head",
  569. "header",
  570. "hgroup",
  571. "hr",
  572. "html",
  573. "iframe",
  574. "img",
  575. "input",
  576. "keygen",
  577. "li",
  578. "link",
  579. "listing",
  580. "main",
  581. "marquee",
  582. "menu",
  583. "meta",
  584. "nav",
  585. "noembed",
  586. "noframes",
  587. "noscript",
  588. "object",
  589. "ol",
  590. "p",
  591. "param",
  592. "plaintext",
  593. "pre",
  594. "script",
  595. "search",
  596. "section",
  597. "select",
  598. "source",
  599. "style",
  600. "summary",
  601. "table",
  602. "tbody",
  603. "td",
  604. "template",
  605. "textarea",
  606. "tfoot",
  607. "th",
  608. "thead",
  609. "title",
  610. "tr",
  611. "track",
  612. "ul",
  613. "wbr",
  614. "xmp"
  615. ]);
  616. /**
  617. * §13.2.4.3 formatting elements: the ones reconstructed from the list of active formatting elements.
  618. * @type {Set<string>}
  619. */
  620. const FORMATTING = new Set([
  621. "a",
  622. "b",
  623. "big",
  624. "code",
  625. "em",
  626. "font",
  627. "i",
  628. "nobr",
  629. "s",
  630. "small",
  631. "strike",
  632. "strong",
  633. "tt",
  634. "u"
  635. ]);
  636. /**
  637. * The heading elements, whose start tag closes an open one.
  638. * @type {Set<string>}
  639. */
  640. const HEADING = new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
  641. /**
  642. * The three the parser implies around every document. Their end tags are omissible like any other, but non-browser consumers routinely mis-parse a document missing them, so the printer decides them by policy rather than by what follows — which is why `OPTIONAL_END_TAG_FOLLOWERS` leaves them out.
  643. * @type {Set<string>}
  644. */
  645. const SHELL_ELEMENTS = new Set(["html", "head", "body"]);
  646. /**
  647. * DOM §4.9's valid shadow host names — what `attachShadow()` accepts by name, so what a `<template shadowrootmode>` attaches to. Prose in the DOM spec, which publishes no element dataset, so webref's HTML IDL cannot state it.
  648. * @type {Set<string>}
  649. */
  650. const SHADOW_HOSTS = new Set([
  651. "article",
  652. "aside",
  653. "blockquote",
  654. "body",
  655. "div",
  656. "footer",
  657. "h1",
  658. "h2",
  659. "h3",
  660. "h4",
  661. "h5",
  662. "h6",
  663. "header",
  664. "main",
  665. "nav",
  666. "p",
  667. "section",
  668. "span"
  669. ]);
  670. /**
  671. * §4.13.1's exclusions from a valid custom element name: the hyphenated SVG and MathML names a parser would otherwise read as custom. Prose in the name production, and the SVG names are not among the camel-cased ones §13.2.6.5 adjusts, so nothing here derives them.
  672. * @type {Set<string>}
  673. */
  674. const RESERVED_ELEMENT_NAMES = new Set([
  675. "annotation-xml",
  676. "color-profile",
  677. "font-face",
  678. "font-face-format",
  679. "font-face-name",
  680. "font-face-src",
  681. "font-face-uri",
  682. "missing-glyph"
  683. ]);
  684. /**
  685. * §13.2.6.5 "adjust SVG tag name": lowercased source name -> the camelCased SVG name.
  686. * @type {Record<string, string>}
  687. */
  688. const SVG_TAG_ADJUST = adjusted([
  689. "altGlyph",
  690. "altGlyphDef",
  691. "altGlyphItem",
  692. "animateColor",
  693. "animateMotion",
  694. "animateTransform",
  695. "clipPath",
  696. "feBlend",
  697. "feColorMatrix",
  698. "feComponentTransfer",
  699. "feComposite",
  700. "feConvolveMatrix",
  701. "feDiffuseLighting",
  702. "feDisplacementMap",
  703. "feDistantLight",
  704. "feDropShadow",
  705. "feFlood",
  706. "feFuncA",
  707. "feFuncB",
  708. "feFuncG",
  709. "feFuncR",
  710. "feGaussianBlur",
  711. "feImage",
  712. "feMerge",
  713. "feMergeNode",
  714. "feMorphology",
  715. "feOffset",
  716. "fePointLight",
  717. "feSpecularLighting",
  718. "feSpotLight",
  719. "feTile",
  720. "feTurbulence",
  721. "foreignObject",
  722. "glyphRef",
  723. "linearGradient",
  724. "radialGradient",
  725. "textPath"
  726. ]);
  727. /**
  728. * §13.2.6.1 "adjust SVG attributes": lowercased source name -> the camelCased SVG attribute.
  729. * @type {Record<string, string>}
  730. */
  731. const SVG_ATTR_ADJUST = adjusted([
  732. "attributeName",
  733. "attributeType",
  734. "baseFrequency",
  735. "baseProfile",
  736. "calcMode",
  737. "clipPathUnits",
  738. "diffuseConstant",
  739. "edgeMode",
  740. "filterUnits",
  741. "glyphRef",
  742. "gradientTransform",
  743. "gradientUnits",
  744. "kernelMatrix",
  745. "kernelUnitLength",
  746. "keyPoints",
  747. "keySplines",
  748. "keyTimes",
  749. "lengthAdjust",
  750. "limitingConeAngle",
  751. "markerHeight",
  752. "markerUnits",
  753. "markerWidth",
  754. "maskContentUnits",
  755. "maskUnits",
  756. "numOctaves",
  757. "pathLength",
  758. "patternContentUnits",
  759. "patternTransform",
  760. "patternUnits",
  761. "pointsAtX",
  762. "pointsAtY",
  763. "pointsAtZ",
  764. "preserveAlpha",
  765. "preserveAspectRatio",
  766. "primitiveUnits",
  767. "refX",
  768. "refY",
  769. "repeatCount",
  770. "repeatDur",
  771. "requiredExtensions",
  772. "requiredFeatures",
  773. "specularConstant",
  774. "specularExponent",
  775. "spreadMethod",
  776. "startOffset",
  777. "stdDeviation",
  778. "stitchTiles",
  779. "surfaceScale",
  780. "systemLanguage",
  781. "tableValues",
  782. "targetX",
  783. "targetY",
  784. "textLength",
  785. "viewBox",
  786. "viewTarget",
  787. "xChannelSelector",
  788. "yChannelSelector",
  789. "zoomAndPan"
  790. ]);
  791. /**
  792. * §13.2.6.1 "adjust foreign attributes": the attributes serialized with a namespace prefix.
  793. * @type {Record<string, string>}
  794. */
  795. const FOREIGN_ATTR_NS = Object.assign(Object.create(null), {
  796. "xlink:actuate": "xlink actuate",
  797. "xlink:arcrole": "xlink arcrole",
  798. "xlink:href": "xlink href",
  799. "xlink:role": "xlink role",
  800. "xlink:show": "xlink show",
  801. "xlink:title": "xlink title",
  802. "xlink:type": "xlink type",
  803. "xml:lang": "xml lang",
  804. "xml:space": "xml space",
  805. xmlns: "xmlns",
  806. "xmlns:xlink": "xmlns xlink"
  807. });
  808. /**
  809. * MathML text integration points (§13.2.6.5): HTML content resumes inside them.
  810. * @type {Set<string>}
  811. */
  812. const MATHML_TEXT_INTEGRATION = new Set(["mi", "mo", "mn", "ms", "mtext"]);
  813. /**
  814. * The MathML elements an HTML breakout pops back to.
  815. * @type {Set<string>}
  816. */
  817. const MATHML_SPECIAL = new Set([
  818. "mi",
  819. "mo",
  820. "mn",
  821. "ms",
  822. "mtext",
  823. "annotation-xml"
  824. ]);
  825. /**
  826. * HTML integration points in SVG (§13.2.6.5).
  827. * @type {Set<string>}
  828. */
  829. const SVG_SPECIAL = new Set(["foreignobject", "desc", "title"]);
  830. /**
  831. * §13.2.4.2 "the stack of open elements has an element in scope": the elements that stop the walk.
  832. * @type {Set<string>}
  833. */
  834. const HTML_SCOPE = new Set([
  835. "applet",
  836. "caption",
  837. "html",
  838. "table",
  839. "td",
  840. "th",
  841. "marquee",
  842. "object",
  843. "template"
  844. ]);
  845. /**
  846. * §13.2.6.4.7 "generate implied end tags": the elements popped without their end tag.
  847. * @type {Set<string>}
  848. */
  849. const IMPLIED = new Set([
  850. "dd",
  851. "dt",
  852. "li",
  853. "optgroup",
  854. "option",
  855. "p",
  856. "rb",
  857. "rp",
  858. "rt",
  859. "rtc"
  860. ]);
  861. /**
  862. * "generate all implied end tags thoroughly" — the wider list the table modes use.
  863. * @type {Set<string>}
  864. */
  865. const IMPLIED_THOROUGH = new Set([
  866. "caption",
  867. "colgroup",
  868. "dd",
  869. "dt",
  870. "li",
  871. "optgroup",
  872. "option",
  873. "p",
  874. "rb",
  875. "rp",
  876. "rt",
  877. "rtc",
  878. "tbody",
  879. "td",
  880. "tfoot",
  881. "th",
  882. "thead",
  883. "tr"
  884. ]);
  885. /**
  886. * "clear the stack back to a table context" stops here.
  887. * @type {Set<string>}
  888. */
  889. const CLEAR_TABLE = new Set(["table", "template", "html"]);
  890. /**
  891. * "clear the stack back to a table body context" stops here.
  892. * @type {Set<string>}
  893. */
  894. const CLEAR_TABLE_BODY = new Set([
  895. "tbody",
  896. "tfoot",
  897. "thead",
  898. "template",
  899. "html"
  900. ]);
  901. /**
  902. * "clear the stack back to a table row context" stops here.
  903. * @type {Set<string>}
  904. */
  905. const CLEAR_TABLE_ROW = new Set(["tr", "template", "html"]);
  906. /**
  907. * The table-scope barrier (§13.2.4.2 "has an element in table scope").
  908. * @type {Set<string>}
  909. */
  910. const TABLE_SCOPE_STOP = new Set(["html", "table", "template"]);
  911. /**
  912. * The elements "in table" text is fostered out of.
  913. * @type {Set<string>}
  914. */
  915. const TABLE_CONTEXT = new Set(["table", "tbody", "tfoot", "thead", "tr"]);
  916. /**
  917. * The start tags §13.2.6.4.9 gives a rule of its own, so "in table" inserts them where they stand instead of taking the "anything else" arc that fosters one out. Read by the printer, which may only move a fostered run back inside the table when the table would foster all of it straight out again. Prose rather than a dataset: the IDL says nothing about insertion modes.
  918. * @type {Set<string>}
  919. */
  920. const FOSTER_KEPT = new Set([
  921. "caption",
  922. "col",
  923. "colgroup",
  924. "form",
  925. "input",
  926. "script",
  927. "style",
  928. "td",
  929. "template",
  930. "th"
  931. ]);
  932. /**
  933. * Open elements a start tag of another name ends through a scope check, for the pairs no broader rule already states — not the same name, not one heading behind another, and not two of `IMPLIED` ending each other. §13.2.6.4.7 pops an open `<select>` for an `<input>`, and generates implied end tags for an `<hr>` while a `<select>` is in scope. Prose rather than a dataset, for the same reason as `FOSTER_KEPT`.
  934. * @type {Map<string, Set<string> | null>}
  935. */
  936. const SCOPE_ENDED_BY = new Map([
  937. ["select", new Set(["input"])],
  938. ["dd", new Set(["hr"])],
  939. ["dt", new Set(["hr"])],
  940. ["li", new Set(["hr"])],
  941. ["optgroup", new Set(["hr"])],
  942. ["option", new Set(["hr"])],
  943. ["p", new Set(["hr"])],
  944. ["rb", new Set(["hr"])],
  945. ["rp", new Set(["hr"])],
  946. ["rt", new Set(["hr"])],
  947. ["rtc", new Set(["hr"])]
  948. ]);
  949. /**
  950. * The three row-group elements, interchangeable in the table modes.
  951. * @type {Set<string>}
  952. */
  953. const TBODY_GROUP = new Set(["tbody", "tfoot", "thead"]);
  954. /**
  955. * The two cell elements.
  956. * @type {Set<string>}
  957. */
  958. const TD_TH = new Set(["td", "th"]);
  959. /**
  960. * The cell elements plus their row, closed together.
  961. * @type {Set<string>}
  962. */
  963. const TD_TH_TR = new Set(["td", "th", "tr"]);
  964. /**
  965. * The head elements "in body" re-dispatches to "in head".
  966. * @type {Set<string>}
  967. */
  968. const STYLE_SCRIPT_TEMPLATE = new Set(["style", "script", "template"]);
  969. /**
  970. * The end tags "after head" / "before head" act on rather than ignore.
  971. * @type {Set<string>}
  972. */
  973. const HEAD_BODY_HTML_BR = new Set(["head", "body", "html", "br"]);
  974. /**
  975. * The end tags "after body" acts on rather than ignores.
  976. * @type {Set<string>}
  977. */
  978. const BODY_HTML_BR = new Set(["body", "html", "br"]);
  979. /**
  980. * Void elements "in head" inserts and immediately pops.
  981. * @type {Set<string>}
  982. */
  983. const HEAD_VOID_ELEMENTS = new Set([
  984. "base",
  985. "basefont",
  986. "bgsound",
  987. "link",
  988. "meta"
  989. ]);
  990. /**
  991. * The raw-text elements "in head" tokenizes as such.
  992. * @type {Set<string>}
  993. */
  994. const NOFRAMES_STYLE_NOSCRIPT = new Set(["noframes", "style", "noscript"]);
  995. /**
  996. * "in head noscript" start tags handled by reprocessing in "in head".
  997. * @type {Set<string>}
  998. */
  999. const IN_HEAD_NOSCRIPT_PASSTHROUGH = new Set([
  1000. "basefont",
  1001. "bgsound",
  1002. "link",
  1003. "meta",
  1004. "noframes",
  1005. "style"
  1006. ]);
  1007. /**
  1008. * The elements that belong in `<head>`.
  1009. * @type {Set<string>}
  1010. */
  1011. const HEAD_ELEMENTS = new Set([
  1012. "base",
  1013. "basefont",
  1014. "bgsound",
  1015. "link",
  1016. "meta",
  1017. "noframes",
  1018. "script",
  1019. "style",
  1020. "template",
  1021. "title"
  1022. ]);
  1023. /**
  1024. * Start tags "in body" closes an open `<p>` before inserting.
  1025. * @type {Set<string>}
  1026. */
  1027. const BLOCK_START = new Set([
  1028. "address",
  1029. "article",
  1030. "aside",
  1031. "blockquote",
  1032. "center",
  1033. "details",
  1034. "dialog",
  1035. "dir",
  1036. "div",
  1037. "dl",
  1038. "fieldset",
  1039. "figcaption",
  1040. "figure",
  1041. "footer",
  1042. "header",
  1043. "hgroup",
  1044. "main",
  1045. "menu",
  1046. "nav",
  1047. "ol",
  1048. "p",
  1049. "search",
  1050. "section",
  1051. "summary",
  1052. "ul"
  1053. ]);
  1054. /**
  1055. * End tags "in body" closes a block for — `BLOCK_START` plus the elements with no start-tag clause of their own.
  1056. * @type {Set<string>}
  1057. */
  1058. const BLOCK_END = new Set([
  1059. "address",
  1060. "article",
  1061. "aside",
  1062. "blockquote",
  1063. "button",
  1064. "center",
  1065. "details",
  1066. "dialog",
  1067. "dir",
  1068. "div",
  1069. "dl",
  1070. "fieldset",
  1071. "figcaption",
  1072. "figure",
  1073. "footer",
  1074. "header",
  1075. "hgroup",
  1076. "listing",
  1077. "main",
  1078. "menu",
  1079. "nav",
  1080. "ol",
  1081. "pre",
  1082. "search",
  1083. "section",
  1084. "summary",
  1085. "ul"
  1086. ]);
  1087. /**
  1088. * The three elements `</form>` and the block end tags share a close path with.
  1089. * @type {Set<string>}
  1090. */
  1091. const ADDRESS_DIV_P = new Set(["address", "div", "p"]);
  1092. /**
  1093. * The elements that push a marker onto the list of active formatting elements.
  1094. * @type {Set<string>}
  1095. */
  1096. const APPLET_MARQUEE_OBJECT = new Set(["applet", "marquee", "object"]);
  1097. /**
  1098. * Void start tags "in body" that reconstruct the active formatting elements first.
  1099. * @type {Set<string>}
  1100. */
  1101. const VOID_FORMATTING = new Set([
  1102. "area",
  1103. "br",
  1104. "embed",
  1105. "img",
  1106. "keygen",
  1107. "wbr"
  1108. ]);
  1109. /**
  1110. * Void start tags "in body" that do not reconstruct.
  1111. * @type {Set<string>}
  1112. */
  1113. const PARAM_SOURCE_TRACK = new Set(["param", "source", "track"]);
  1114. /**
  1115. * Table start tags "in body" ignores outside a table.
  1116. * @type {Set<string>}
  1117. */
  1118. const IGNORED_BODY_TABLE_STARTS = new Set([
  1119. "caption",
  1120. "col",
  1121. "colgroup",
  1122. "frame",
  1123. "head",
  1124. "tbody",
  1125. "td",
  1126. "tfoot",
  1127. "th",
  1128. "thead",
  1129. "tr"
  1130. ]);
  1131. /**
  1132. * End tags "in table" ignores.
  1133. * @type {Set<string>}
  1134. */
  1135. const IN_TABLE_IGNORED_ENDS = new Set([
  1136. "body",
  1137. "caption",
  1138. "col",
  1139. "colgroup",
  1140. "html",
  1141. "tbody",
  1142. "td",
  1143. "tfoot",
  1144. "th",
  1145. "thead",
  1146. "tr"
  1147. ]);
  1148. /**
  1149. * Start tags "in caption" closes the caption for.
  1150. * @type {Set<string>}
  1151. */
  1152. const CAPTION_TABLE_STARTS = new Set([
  1153. "caption",
  1154. "col",
  1155. "colgroup",
  1156. "tbody",
  1157. "td",
  1158. "tfoot",
  1159. "th",
  1160. "thead",
  1161. "tr"
  1162. ]);
  1163. /**
  1164. * End tags "in caption" ignores.
  1165. * @type {Set<string>}
  1166. */
  1167. const CAPTION_IGNORED_ENDS = new Set([
  1168. "body",
  1169. "col",
  1170. "colgroup",
  1171. "html",
  1172. "tbody",
  1173. "td",
  1174. "tfoot",
  1175. "th",
  1176. "thead",
  1177. "tr"
  1178. ]);
  1179. /**
  1180. * Start tags "in table body" closes the row group for.
  1181. * @type {Set<string>}
  1182. */
  1183. const TBODY_TRIGGER_STARTS = new Set([
  1184. "caption",
  1185. "col",
  1186. "colgroup",
  1187. "tbody",
  1188. "tfoot",
  1189. "thead"
  1190. ]);
  1191. /**
  1192. * End tags "in table body" ignores.
  1193. * @type {Set<string>}
  1194. */
  1195. const TBODY_IGNORED_ENDS = new Set([
  1196. "body",
  1197. "caption",
  1198. "col",
  1199. "colgroup",
  1200. "html",
  1201. "td",
  1202. "th",
  1203. "tr"
  1204. ]);
  1205. /**
  1206. * Start tags "in row" closes the row for.
  1207. * @type {Set<string>}
  1208. */
  1209. const ROW_TRIGGER_STARTS = new Set([
  1210. "caption",
  1211. "col",
  1212. "colgroup",
  1213. "tbody",
  1214. "tfoot",
  1215. "thead",
  1216. "tr"
  1217. ]);
  1218. /**
  1219. * End tags "in row" ignores.
  1220. * @type {Set<string>}
  1221. */
  1222. const ROW_IGNORED_ENDS = new Set([
  1223. "body",
  1224. "caption",
  1225. "col",
  1226. "colgroup",
  1227. "html",
  1228. "td",
  1229. "th"
  1230. ]);
  1231. /**
  1232. * End tags "in cell" ignores.
  1233. * @type {Set<string>}
  1234. */
  1235. const CELL_IGNORED_ENDS = new Set([
  1236. "body",
  1237. "caption",
  1238. "col",
  1239. "colgroup",
  1240. "html"
  1241. ]);
  1242. /**
  1243. * Elements whose text is tokenized raw, so no character reference in it is decoded.
  1244. * @type {Set<string>}
  1245. */
  1246. const NO_DECODE_TEXT = new Set([
  1247. "script",
  1248. "style",
  1249. "xmp",
  1250. "iframe",
  1251. "noembed",
  1252. "noframes",
  1253. "plaintext"
  1254. ]);
  1255. /**
  1256. * HTML start tags that break out of foreign (SVG/MathML) content.
  1257. * @type {Set<string>}
  1258. */
  1259. const FOREIGN_BREAKOUT = new Set([
  1260. "b",
  1261. "big",
  1262. "blockquote",
  1263. "body",
  1264. "br",
  1265. "center",
  1266. "code",
  1267. "dd",
  1268. "div",
  1269. "dl",
  1270. "dt",
  1271. "em",
  1272. "embed",
  1273. "h1",
  1274. "h2",
  1275. "h3",
  1276. "h4",
  1277. "h5",
  1278. "h6",
  1279. "head",
  1280. "hr",
  1281. "i",
  1282. "img",
  1283. "li",
  1284. "listing",
  1285. "menu",
  1286. "meta",
  1287. "nobr",
  1288. "ol",
  1289. "p",
  1290. "pre",
  1291. "ruby",
  1292. "s",
  1293. "small",
  1294. "span",
  1295. "strong",
  1296. "strike",
  1297. "sub",
  1298. "sup",
  1299. "table",
  1300. "tt",
  1301. "u",
  1302. "ul",
  1303. "var"
  1304. ]);
  1305. /**
  1306. * The `<font>` attributes that make it break out of foreign content.
  1307. * @type {Set<string>}
  1308. */
  1309. const FONT_BREAKOUT_ATTRS = new Set(["color", "face", "size"]);
  1310. /**
  1311. * Raw text / escapable raw text elements (§13.1.2) plus the other RAWTEXT/RCDATA/PLAINTEXT-tokenized ones.
  1312. * @type {Set<string>}
  1313. */
  1314. const RAW_TEXT_ELEMENTS = new Set([
  1315. "script",
  1316. "style",
  1317. "textarea",
  1318. "title",
  1319. "xmp",
  1320. "iframe",
  1321. "noembed",
  1322. "noframes",
  1323. "noscript",
  1324. "plaintext"
  1325. ]);
  1326. /**
  1327. * Public-id prefixes that force quirks mode (the "quirks mode" doctype table).
  1328. * @type {string[]}
  1329. */
  1330. const QUIRKY_PREFIXES = [
  1331. "+//silmaril//dtd html pro v0r11 19970101//",
  1332. "-//as//dtd html 3.0 aswedit + extensions//",
  1333. "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
  1334. "-//ietf//dtd html 2.0 level 1//",
  1335. "-//ietf//dtd html 2.0 level 2//",
  1336. "-//ietf//dtd html 2.0 strict level 1//",
  1337. "-//ietf//dtd html 2.0 strict level 2//",
  1338. "-//ietf//dtd html 2.0 strict//",
  1339. "-//ietf//dtd html 2.0//",
  1340. "-//ietf//dtd html 2.1e//",
  1341. "-//ietf//dtd html 3.0//",
  1342. "-//ietf//dtd html 3.2 final//",
  1343. "-//ietf//dtd html 3.2//",
  1344. "-//ietf//dtd html 3//",
  1345. "-//ietf//dtd html level 0//",
  1346. "-//ietf//dtd html level 1//",
  1347. "-//ietf//dtd html level 2//",
  1348. "-//ietf//dtd html level 3//",
  1349. "-//ietf//dtd html strict level 0//",
  1350. "-//ietf//dtd html strict level 1//",
  1351. "-//ietf//dtd html strict level 2//",
  1352. "-//ietf//dtd html strict level 3//",
  1353. "-//ietf//dtd html strict//",
  1354. "-//ietf//dtd html//",
  1355. "-//metrius//dtd metrius presentational//",
  1356. "-//microsoft//dtd internet explorer 2.0 html strict//",
  1357. "-//microsoft//dtd internet explorer 2.0 html//",
  1358. "-//microsoft//dtd internet explorer 2.0 tables//",
  1359. "-//microsoft//dtd internet explorer 3.0 html strict//",
  1360. "-//microsoft//dtd internet explorer 3.0 html//",
  1361. "-//microsoft//dtd internet explorer 3.0 tables//",
  1362. "-//netscape comm. corp.//dtd html//",
  1363. "-//netscape comm. corp.//dtd strict html//",
  1364. "-//o'reilly and associates//dtd html 2.0//",
  1365. "-//o'reilly and associates//dtd html extended 1.0//",
  1366. "-//o'reilly and associates//dtd html extended relaxed 1.0//",
  1367. "-//sq//dtd html 2.0 hotmetal + extensions//",
  1368. "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
  1369. "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
  1370. "-//spyglass//dtd html 2.0 extended//",
  1371. "-//sun microsystems corp.//dtd hotjava html//",
  1372. "-//sun microsystems corp.//dtd hotjava strict html//",
  1373. "-//w3c//dtd html 3 1995-03-24//",
  1374. "-//w3c//dtd html 3.2 draft//",
  1375. "-//w3c//dtd html 3.2 final//",
  1376. "-//w3c//dtd html 3.2//",
  1377. "-//w3c//dtd html 3.2s draft//",
  1378. "-//w3c//dtd html 4.0 frameset//",
  1379. "-//w3c//dtd html 4.0 transitional//",
  1380. "-//w3c//dtd html experimental 19960712//",
  1381. "-//w3c//dtd html experimental 970421//",
  1382. "-//w3c//dtd w3 html//",
  1383. "-//w3o//dtd w3 html 3.0//",
  1384. "-//webtechs//dtd mozilla html 2.0//",
  1385. "-//webtechs//dtd mozilla html//"
  1386. ];
  1387. /**
  1388. * Public ids that force quirks mode exactly.
  1389. * @type {Set<string>}
  1390. */
  1391. const QUIRKY_EXACT = new Set([
  1392. "-//w3o//dtd w3 html strict 3.0//en//",
  1393. "-/w3c/dtd html 4.0 transitional/en",
  1394. "html"
  1395. ]);
  1396. /**
  1397. * Elements whose text children serialize literally, no escaping. `textarea` / `title` are escapable, so they are not here.
  1398. * @type {Set<string>}
  1399. */
  1400. const LITERAL_TEXT_PARENTS = new Set([
  1401. "script",
  1402. "style",
  1403. "xmp",
  1404. "iframe",
  1405. "noembed",
  1406. "noframes",
  1407. "plaintext"
  1408. ]);
  1409. /**
  1410. * The only elements the printer may leave transparent when they lack a source tag: the parser re-implies them identically. Any other tag-less element (adoption-agency clone, reconstructed formatting element, renamed token) must be materialized or the DOM changes.
  1411. * @type {Set<string>}
  1412. */
  1413. const TRANSPARENT_IMPLIED_ELEMENTS = new Set([
  1414. "html",
  1415. "head",
  1416. "body",
  1417. "colgroup",
  1418. "tbody",
  1419. "tr"
  1420. ]);
  1421. /**
  1422. * Elements the parser strips one leading newline from, so a serialized body that still begins with one needs it re-added.
  1423. * @type {Set<string>}
  1424. */
  1425. const LEADING_NEWLINE_ELEMENTS = new Set(["pre", "textarea", "listing"]);
  1426. /**
  1427. * `<script>` bodies that are JSON: the two dedicated types plus any `+json` subtype (`application/ld+json`).
  1428. * @type {Set<string>}
  1429. */
  1430. const JSON_SCRIPT_TYPES = new Set([
  1431. "application/json",
  1432. "importmap",
  1433. "speculationrules"
  1434. ]);
  1435. /**
  1436. * §13.2.6.4.18 "in template": the start tags that re-dispatch, each to the insertion mode it switches to. Named, not numbered — the numbering is the parser's own, so `syntax.js` binds these names to its constants.
  1437. * @type {Record<string, string>}
  1438. */
  1439. const TEMPLATE_START_TAG_MODES = Object.assign(Object.create(null), {
  1440. caption: "IN_TABLE",
  1441. colgroup: "IN_TABLE",
  1442. tbody: "IN_TABLE",
  1443. tfoot: "IN_TABLE",
  1444. thead: "IN_TABLE",
  1445. col: "IN_COLUMN_GROUP",
  1446. tr: "IN_TABLE_BODY",
  1447. td: "IN_ROW",
  1448. th: "IN_ROW"
  1449. });
  1450. /**
  1451. * Elements §15 gives a non-inline default display. Whitespace against one of their edges renders as nothing, which is what `collapseWhitespace: "smart"` drops. Author CSS can still make one inline, so the mode is opt-in.
  1452. * @type {Set<string>}
  1453. */
  1454. const BLOCK_LEVEL_ELEMENTS = new Set([
  1455. "address",
  1456. "article",
  1457. "aside",
  1458. "blockquote",
  1459. "body",
  1460. "caption",
  1461. "center",
  1462. "col",
  1463. "colgroup",
  1464. "dd",
  1465. "details",
  1466. "dialog",
  1467. "dir",
  1468. "div",
  1469. "dl",
  1470. "dt",
  1471. "fieldset",
  1472. "figcaption",
  1473. "figure",
  1474. "footer",
  1475. "form",
  1476. "frameset",
  1477. "h1",
  1478. "h2",
  1479. "h3",
  1480. "h4",
  1481. "h5",
  1482. "h6",
  1483. "header",
  1484. "hgroup",
  1485. "hr",
  1486. "html",
  1487. "legend",
  1488. "li",
  1489. "listing",
  1490. "main",
  1491. "marquee",
  1492. "menu",
  1493. "nav",
  1494. "ol",
  1495. "optgroup",
  1496. "option",
  1497. "p",
  1498. "plaintext",
  1499. "pre",
  1500. "search",
  1501. "section",
  1502. "summary",
  1503. "table",
  1504. "tbody",
  1505. "td",
  1506. "tfoot",
  1507. "th",
  1508. "thead",
  1509. "tr",
  1510. "ul",
  1511. "xmp"
  1512. ]);
  1513. /**
  1514. * element -> attribute -> the keywords the spec enumerates for it, matched ASCII-case-insensitively. `*` holds the global attributes. Only a value already in the set is folded to lower case, so a spelling the spec does not enumerate keeps its case.
  1515. * @type {Record<string, Record<string, Set<string>>>}
  1516. */
  1517. const ENUMERATED_KEYWORDS = Object.assign(Object.create(null), {
  1518. "*": Object.assign(Object.create(null), {
  1519. autocapitalize: new Set([
  1520. "none",
  1521. "off",
  1522. "on",
  1523. "sentences",
  1524. "words",
  1525. "characters"
  1526. ]),
  1527. contenteditable: new Set(["true", "false", "plaintext-only"]),
  1528. dir: new Set(["ltr", "rtl", "auto"]),
  1529. draggable: new Set(["true", "false"]),
  1530. enterkeyhint: new Set([
  1531. "enter",
  1532. "done",
  1533. "go",
  1534. "next",
  1535. "previous",
  1536. "search",
  1537. "send"
  1538. ]),
  1539. hidden: new Set(["hidden", "until-found"]),
  1540. inputmode: new Set([
  1541. "none",
  1542. "text",
  1543. "tel",
  1544. "url",
  1545. "email",
  1546. "numeric",
  1547. "decimal",
  1548. "search"
  1549. ]),
  1550. popover: new Set(["auto", "manual", "hint"]),
  1551. referrerpolicy: new Set([
  1552. "no-referrer",
  1553. "no-referrer-when-downgrade",
  1554. "same-origin",
  1555. "origin",
  1556. "strict-origin",
  1557. "origin-when-cross-origin",
  1558. "strict-origin-when-cross-origin",
  1559. "unsafe-url"
  1560. ]),
  1561. spellcheck: new Set(["true", "false"]),
  1562. translate: new Set(["yes", "no"]),
  1563. writingsuggestions: new Set(["true", "false"])
  1564. }),
  1565. audio: Object.assign(Object.create(null), {
  1566. crossorigin: new Set(["anonymous", "use-credentials"]),
  1567. preload: new Set(["none", "metadata", "auto"])
  1568. }),
  1569. button: Object.assign(Object.create(null), {
  1570. formenctype: new Set([
  1571. "application/x-www-form-urlencoded",
  1572. "multipart/form-data",
  1573. "text/plain"
  1574. ]),
  1575. formmethod: new Set(["get", "post", "dialog"]),
  1576. type: new Set(["submit", "reset", "button"])
  1577. }),
  1578. form: Object.assign(Object.create(null), {
  1579. autocomplete: new Set(["on", "off"]),
  1580. enctype: new Set([
  1581. "application/x-www-form-urlencoded",
  1582. "multipart/form-data",
  1583. "text/plain"
  1584. ]),
  1585. method: new Set(["get", "post", "dialog"])
  1586. }),
  1587. iframe: Object.assign(Object.create(null), {
  1588. loading: new Set(["lazy", "eager"])
  1589. }),
  1590. img: Object.assign(Object.create(null), {
  1591. crossorigin: new Set(["anonymous", "use-credentials"]),
  1592. decoding: new Set(["sync", "async", "auto"]),
  1593. fetchpriority: new Set(["high", "low", "auto"]),
  1594. loading: new Set(["lazy", "eager"])
  1595. }),
  1596. input: Object.assign(Object.create(null), {
  1597. formenctype: new Set([
  1598. "application/x-www-form-urlencoded",
  1599. "multipart/form-data",
  1600. "text/plain"
  1601. ]),
  1602. formmethod: new Set(["get", "post", "dialog"]),
  1603. type: new Set([
  1604. "hidden",
  1605. "text",
  1606. "search",
  1607. "tel",
  1608. "url",
  1609. "email",
  1610. "password",
  1611. "date",
  1612. "month",
  1613. "week",
  1614. "time",
  1615. "datetime-local",
  1616. "number",
  1617. "range",
  1618. "color",
  1619. "checkbox",
  1620. "radio",
  1621. "file",
  1622. "submit",
  1623. "image",
  1624. "reset",
  1625. "button"
  1626. ])
  1627. }),
  1628. link: Object.assign(Object.create(null), {
  1629. crossorigin: new Set(["anonymous", "use-credentials"]),
  1630. fetchpriority: new Set(["high", "low", "auto"])
  1631. }),
  1632. script: Object.assign(Object.create(null), {
  1633. crossorigin: new Set(["anonymous", "use-credentials"]),
  1634. fetchpriority: new Set(["high", "low", "auto"])
  1635. }),
  1636. td: Object.assign(Object.create(null), {
  1637. scope: new Set(["row", "col", "rowgroup", "colgroup"])
  1638. }),
  1639. th: Object.assign(Object.create(null), {
  1640. scope: new Set(["row", "col", "rowgroup", "colgroup"])
  1641. }),
  1642. track: Object.assign(Object.create(null), {
  1643. kind: new Set([
  1644. "subtitles",
  1645. "captions",
  1646. "descriptions",
  1647. "chapters",
  1648. "metadata"
  1649. ])
  1650. }),
  1651. video: Object.assign(Object.create(null), {
  1652. crossorigin: new Set(["anonymous", "use-credentials"]),
  1653. preload: new Set(["none", "metadata", "auto"])
  1654. })
  1655. });
  1656. /**
  1657. * Elements `removeEmptyElements` never drops: with no children and no attributes each is still doing its job, so an empty one is not a leftover.
  1658. * @type {Set<string>}
  1659. */
  1660. const EMPTY_ELEMENT_KEPT = new Set([
  1661. "canvas",
  1662. "dialog",
  1663. "meter",
  1664. "output",
  1665. "progress",
  1666. "slot",
  1667. "template",
  1668. "textarea",
  1669. "caption",
  1670. "col",
  1671. "colgroup",
  1672. "table",
  1673. "tbody",
  1674. "td",
  1675. "tfoot",
  1676. "th",
  1677. "thead",
  1678. "tr"
  1679. ]);
  1680. /**
  1681. * Attributes `removeEmptyAttributes` may drop when their value is empty or all whitespace, mapped to the elements they mean that on (`null` = a global attribute): the spec gives each the same state empty and absent. Four hand-reasoned globals, plus every token-list attribute (no tokens is what absence gives). The element matters — on any element the spec does not define it for, `rel` or `headers` is an ordinary author attribute a script reads back, so `<x-foo rel="">` keeps it. `sandbox` is the token list held back: its empty list is the most restrictive state an `<iframe>` has. Only a presence selector (`[class]`) or a script reading the attribute back can tell, which is what keeps the option off by default.
  1682. * @type {Map<string, Set<string> | null>}
  1683. */
  1684. const EMPTY_REMOVABLE_ATTRIBUTES = new Map([
  1685. ["accesskey", null],
  1686. ["blocking", new Set(["link", "script", "style"])],
  1687. ["class", null],
  1688. ["dir", null],
  1689. ["for", new Set(["output"])],
  1690. ["headers", new Set(["td", "th"])],
  1691. ["id", null],
  1692. ["itemprop", null],
  1693. ["itemref", null],
  1694. ["itemtype", null],
  1695. ["part", null],
  1696. ["ping", new Set(["a", "area"])],
  1697. ["rel", new Set(["a", "area", "form", "link"])],
  1698. ["sizes", new Set(["link"])],
  1699. ["style", null]
  1700. ]);
  1701. /**
  1702. * element -> attribute -> the value that states the element's own default, for `removeRedundantAttributes: "smart"` (the default). Grouped by element so the printer gates on one lookup for an element no entry names, which is nearly every attribute it prints. Only markers on elements that render nothing, so no rule that styles the page stops applying — unlike `input[type=text]`, which is why that tier is separate. A `querySelector` naming one of these can still tell it went. `media` defaults to `all`, and a `<script charset>` matching the document encoding is obsolete and ignored. Matched ASCII-case-insensitively, unlike `@swc/html`, which lowercases `type` but not `media` / `charset`. `<script type>` is not here — its redundant values are `JAVASCRIPT_SCRIPT_TYPES` minus the empty and `module` spellings, which mean something.
  1703. * @type {Record<string, Record<string, string>>}
  1704. */
  1705. /* eslint-disable unicorn/text-encoding-identifier-case */
  1706. const REDUNDANT_TYPE_ATTRIBUTES = Object.assign(Object.create(null), {
  1707. style: Object.assign(Object.create(null), { type: "text/css" }),
  1708. link: Object.assign(Object.create(null), { type: "text/css", media: "all" }),
  1709. script: Object.assign(Object.create(null), {
  1710. language: "javascript",
  1711. charset: "utf-8"
  1712. })
  1713. });
  1714. /* eslint-enable unicorn/text-encoding-identifier-case */
  1715. /**
  1716. * element -> attribute -> the value the element already defaults to, for `removeRedundantAttributes: "all"`, grouped like `REDUNDANT_TYPE_ATTRIBUTES`. Dropping these is what makes the option unsafe: an attribute selector matches the content attribute, not the reflected default, so `input[type=text]` stops matching. Spec defaults, which the IDL does not state.
  1717. * @type {Record<string, Record<string, string>>}
  1718. */
  1719. const REDUNDANT_DEFAULT_ATTRIBUTES = Object.assign(Object.create(null), {
  1720. input: Object.assign(Object.create(null), { type: "text" }),
  1721. form: Object.assign(Object.create(null), {
  1722. method: "get",
  1723. enctype: "application/x-www-form-urlencoded"
  1724. }),
  1725. button: Object.assign(Object.create(null), { type: "submit" }),
  1726. area: Object.assign(Object.create(null), { shape: "rect" }),
  1727. textarea: Object.assign(Object.create(null), { wrap: "soft" }),
  1728. track: Object.assign(Object.create(null), { kind: "subtitles" }),
  1729. col: Object.assign(Object.create(null), { span: "1" }),
  1730. colgroup: Object.assign(Object.create(null), { span: "1" }),
  1731. td: Object.assign(Object.create(null), { colspan: "1", rowspan: "1" }),
  1732. th: Object.assign(Object.create(null), { colspan: "1", rowspan: "1" })
  1733. });
  1734. /**
  1735. * `<script>` `type` values that make the body executable JavaScript, per the spec's JavaScript MIME type essence list plus the empty and `module` spellings. Anything else is a data block, which must pass through as an asset rather than be bundled as an entry. The IDL says nothing about MIME essences, so this cannot be read out of webref.
  1736. * @type {Set<string>}
  1737. */
  1738. const JAVASCRIPT_SCRIPT_TYPES = new Set([
  1739. "",
  1740. "module",
  1741. "application/ecmascript",
  1742. "application/javascript",
  1743. "application/x-ecmascript",
  1744. "application/x-javascript",
  1745. "text/ecmascript",
  1746. "text/javascript",
  1747. "text/javascript1.0",
  1748. "text/javascript1.1",
  1749. "text/javascript1.2",
  1750. "text/javascript1.3",
  1751. "text/javascript1.4",
  1752. "text/javascript1.5",
  1753. "text/jscript",
  1754. "text/livescript",
  1755. "text/x-ecmascript",
  1756. "text/x-javascript"
  1757. ]);
  1758. module.exports.ADDRESS_DIV_P = ADDRESS_DIV_P;
  1759. module.exports.APPLET_MARQUEE_OBJECT = APPLET_MARQUEE_OBJECT;
  1760. module.exports.BLOCK_END = BLOCK_END;
  1761. module.exports.BLOCK_LEVEL_ELEMENTS = BLOCK_LEVEL_ELEMENTS;
  1762. module.exports.BLOCK_START = BLOCK_START;
  1763. module.exports.BODY_HTML_BR = BODY_HTML_BR;
  1764. module.exports.BODY_START_KEPT_BEFORE = BODY_START_KEPT_BEFORE;
  1765. module.exports.BOOLEAN_ATTRIBUTES = BOOLEAN_ATTRIBUTES;
  1766. module.exports.CAPTION_IGNORED_ENDS = CAPTION_IGNORED_ENDS;
  1767. module.exports.CAPTION_TABLE_STARTS = CAPTION_TABLE_STARTS;
  1768. module.exports.CELL_IGNORED_ENDS = CELL_IGNORED_ENDS;
  1769. module.exports.CLEAR_TABLE = CLEAR_TABLE;
  1770. module.exports.CLEAR_TABLE_BODY = CLEAR_TABLE_BODY;
  1771. module.exports.CLEAR_TABLE_ROW = CLEAR_TABLE_ROW;
  1772. module.exports.COMMA_LIST_ATTRIBUTES = COMMA_LIST_ATTRIBUTES;
  1773. module.exports.DOM_TOKEN_LIST_ATTRIBUTES = DOM_TOKEN_LIST_ATTRIBUTES;
  1774. module.exports.EMPTY_ELEMENT_KEPT = EMPTY_ELEMENT_KEPT;
  1775. module.exports.EMPTY_METADATA_ELEMENTS = EMPTY_METADATA_ELEMENTS;
  1776. module.exports.EMPTY_REMOVABLE_ATTRIBUTES = EMPTY_REMOVABLE_ATTRIBUTES;
  1777. module.exports.ENUMERATED_ATTRIBUTE_NAMES = ENUMERATED_ATTRIBUTE_NAMES;
  1778. module.exports.ENUMERATED_KEYWORDS = ENUMERATED_KEYWORDS;
  1779. module.exports.FONT_BREAKOUT_ATTRS = FONT_BREAKOUT_ATTRS;
  1780. module.exports.FOREIGN_ATTR_NS = FOREIGN_ATTR_NS;
  1781. module.exports.FOREIGN_BREAKOUT = FOREIGN_BREAKOUT;
  1782. module.exports.FORMATTING = FORMATTING;
  1783. module.exports.FOSTER_KEPT = FOSTER_KEPT;
  1784. module.exports.HEADING = HEADING;
  1785. module.exports.HEAD_BODY_HTML_BR = HEAD_BODY_HTML_BR;
  1786. module.exports.HEAD_ELEMENTS = HEAD_ELEMENTS;
  1787. module.exports.HEAD_VOID_ELEMENTS = HEAD_VOID_ELEMENTS;
  1788. module.exports.HTML_SCOPE = HTML_SCOPE;
  1789. module.exports.IGNORED_BODY_TABLE_STARTS = IGNORED_BODY_TABLE_STARTS;
  1790. module.exports.IMPLIED = IMPLIED;
  1791. module.exports.IMPLIED_THOROUGH = IMPLIED_THOROUGH;
  1792. module.exports.INTEGER_ATTRIBUTES = INTEGER_ATTRIBUTES;
  1793. module.exports.IN_HEAD_NOSCRIPT_PASSTHROUGH = IN_HEAD_NOSCRIPT_PASSTHROUGH;
  1794. module.exports.IN_TABLE_IGNORED_ENDS = IN_TABLE_IGNORED_ENDS;
  1795. module.exports.JAVASCRIPT_SCRIPT_TYPES = JAVASCRIPT_SCRIPT_TYPES;
  1796. module.exports.JSON_SCRIPT_TYPES = JSON_SCRIPT_TYPES;
  1797. module.exports.LEADING_NEWLINE_ELEMENTS = LEADING_NEWLINE_ELEMENTS;
  1798. module.exports.LITERAL_TEXT_PARENTS = LITERAL_TEXT_PARENTS;
  1799. module.exports.MATHML_SPECIAL = MATHML_SPECIAL;
  1800. module.exports.MATHML_TEXT_INTEGRATION = MATHML_TEXT_INTEGRATION;
  1801. module.exports.NOFRAMES_STYLE_NOSCRIPT = NOFRAMES_STYLE_NOSCRIPT;
  1802. module.exports.NO_DECODE_TEXT = NO_DECODE_TEXT;
  1803. module.exports.OPTIONAL_END_TAG_AT_END = OPTIONAL_END_TAG_AT_END;
  1804. module.exports.OPTIONAL_END_TAG_FOLLOWERS = OPTIONAL_END_TAG_FOLLOWERS;
  1805. module.exports.OPTIONAL_END_TAG_UNLESS_TRAILING_NODE =
  1806. OPTIONAL_END_TAG_UNLESS_TRAILING_NODE;
  1807. module.exports.PARAM_SOURCE_TRACK = PARAM_SOURCE_TRACK;
  1808. module.exports.P_ENDS_ON_PARENT_END_TAG = P_ENDS_ON_PARENT_END_TAG;
  1809. module.exports.P_FOLLOWED_BY = P_FOLLOWED_BY;
  1810. module.exports.QUIRKY_EXACT = QUIRKY_EXACT;
  1811. module.exports.QUIRKY_PREFIXES = QUIRKY_PREFIXES;
  1812. module.exports.RAW_TEXT_ELEMENTS = RAW_TEXT_ELEMENTS;
  1813. module.exports.REDUNDANT_DEFAULT_ATTRIBUTES = REDUNDANT_DEFAULT_ATTRIBUTES;
  1814. module.exports.REDUNDANT_TYPE_ATTRIBUTES = REDUNDANT_TYPE_ATTRIBUTES;
  1815. module.exports.RESERVED_ELEMENT_NAMES = RESERVED_ELEMENT_NAMES;
  1816. module.exports.REWRITABLE_ATTRIBUTES = REWRITABLE_ATTRIBUTES;
  1817. module.exports.ROW_IGNORED_ENDS = ROW_IGNORED_ENDS;
  1818. module.exports.ROW_TRIGGER_STARTS = ROW_TRIGGER_STARTS;
  1819. module.exports.SCOPE_ENDED_BY = SCOPE_ENDED_BY;
  1820. module.exports.SHADOW_HOSTS = SHADOW_HOSTS;
  1821. module.exports.SHELL_ELEMENTS = SHELL_ELEMENTS;
  1822. module.exports.SIGNED_INTEGER_ATTRIBUTES = SIGNED_INTEGER_ATTRIBUTES;
  1823. module.exports.SPECIAL = SPECIAL;
  1824. module.exports.SRCSET_ATTRIBUTES = SRCSET_ATTRIBUTES;
  1825. module.exports.STYLE_SCRIPT_TEMPLATE = STYLE_SCRIPT_TEMPLATE;
  1826. module.exports.SVG_ATTR_ADJUST = SVG_ATTR_ADJUST;
  1827. module.exports.SVG_SPECIAL = SVG_SPECIAL;
  1828. module.exports.SVG_TAG_ADJUST = SVG_TAG_ADJUST;
  1829. module.exports.TABLE_CONTEXT = TABLE_CONTEXT;
  1830. module.exports.TABLE_SCOPE_STOP = TABLE_SCOPE_STOP;
  1831. module.exports.TBODY_GROUP = TBODY_GROUP;
  1832. module.exports.TBODY_IGNORED_ENDS = TBODY_IGNORED_ENDS;
  1833. module.exports.TBODY_TRIGGER_STARTS = TBODY_TRIGGER_STARTS;
  1834. module.exports.TD_TH = TD_TH;
  1835. module.exports.TD_TH_TR = TD_TH_TR;
  1836. module.exports.TEMPLATE_START_TAG_MODES = TEMPLATE_START_TAG_MODES;
  1837. module.exports.TOKEN_LIST_ATTRIBUTES = TOKEN_LIST_ATTRIBUTES;
  1838. module.exports.TRANSPARENT_IMPLIED_ELEMENTS = TRANSPARENT_IMPLIED_ELEMENTS;
  1839. module.exports.URL_ATTRIBUTES = URL_ATTRIBUTES;
  1840. module.exports.VOID = VOID;
  1841. module.exports.VOID_FORMATTING = VOID_FORMATTING;