source: frontend/node_modules/webpack/lib/html/walkHtmlTokens.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 146.2 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Raj Aryan (based on SWC parser by Alexander Akait)
4*/
5
6"use strict";
7
8// cspell:ignore apos notpre noncharacters DFFF
9
10// #region html entities
11// The contents of this region are auto-generated by
12// `tooling/generate-html-entities.js` from `tooling/html-entities.json`.
13// Do not edit by hand — re-run the generator (via `yarn fix:special`) to refresh.
14//
15// WHATWG named character references. Keys are entity names WITHOUT the
16// leading `&` (some end with `;`, others omit it for legacy entities that
17// match without a closing semicolon). Values are the decoded character
18// strings (1–2 UTF-16 code units).
19// Built on a null prototype so bracket lookups (`HTML_ENTITIES[name]`)
20// can't be poisoned by inherited `Object.prototype` keys like `toString`,
21// `constructor`, or `__proto__` — without this, `&toString;` would falsely
22// look like a matched named character reference.
23// prettier-ignore
24// cspell:disable-next-line
25const HTML_ENTITIES = /** @type {Readonly<Record<string, string>>} */ (Object.freeze(Object.assign(Object.create(null), {"AElig":"Æ","AElig;":"Æ","AMP":"&","AMP;":"&","Aacute":"Á","Aacute;":"Á","Abreve;":"Ă","Acirc":"Â","Acirc;":"Â","Acy;":"А","Afr;":"𝔄","Agrave":"À","Agrave;":"À","Alpha;":"Α","Amacr;":"Ā","And;":"⩓","Aogon;":"Ą","Aopf;":"𝔸","ApplyFunction;":"⁡","Aring":"Å","Aring;":"Å","Ascr;":"𝒜","Assign;":"≔","Atilde":"Ã","Atilde;":"Ã","Auml":"Ä","Auml;":"Ä","Backslash;":"∖","Barv;":"⫧","Barwed;":"⌆","Bcy;":"Б","Because;":"∵","Bernoullis;":"ℬ","Beta;":"Β","Bfr;":"𝔅","Bopf;":"𝔹","Breve;":"˘","Bscr;":"ℬ","Bumpeq;":"≎","CHcy;":"Ч","COPY":"©","COPY;":"©","Cacute;":"Ć","Cap;":"⋒","CapitalDifferentialD;":"ⅅ","Cayleys;":"ℭ","Ccaron;":"Č","Ccedil":"Ç","Ccedil;":"Ç","Ccirc;":"Ĉ","Cconint;":"∰","Cdot;":"Ċ","Cedilla;":"¸","CenterDot;":"·","Cfr;":"ℭ","Chi;":"Χ","CircleDot;":"⊙","CircleMinus;":"⊖","CirclePlus;":"⊕","CircleTimes;":"⊗","ClockwiseContourIntegral;":"∲","CloseCurlyDoubleQuote;":"”","CloseCurlyQuote;":"’","Colon;":"∷","Colone;":"⩴","Congruent;":"≡","Conint;":"∯","ContourIntegral;":"∮","Copf;":"ℂ","Coproduct;":"∐","CounterClockwiseContourIntegral;":"∳","Cross;":"⨯","Cscr;":"𝒞","Cup;":"⋓","CupCap;":"≍","DD;":"ⅅ","DDotrahd;":"⤑","DJcy;":"Ђ","DScy;":"Ѕ","DZcy;":"Џ","Dagger;":"‡","Darr;":"↡","Dashv;":"⫤","Dcaron;":"Ď","Dcy;":"Д","Del;":"∇","Delta;":"Δ","Dfr;":"𝔇","DiacriticalAcute;":"´","DiacriticalDot;":"˙","DiacriticalDoubleAcute;":"˝","DiacriticalGrave;":"`","DiacriticalTilde;":"˜","Diamond;":"⋄","DifferentialD;":"ⅆ","Dopf;":"𝔻","Dot;":"¨","DotDot;":"⃜","DotEqual;":"≐","DoubleContourIntegral;":"∯","DoubleDot;":"¨","DoubleDownArrow;":"⇓","DoubleLeftArrow;":"⇐","DoubleLeftRightArrow;":"⇔","DoubleLeftTee;":"⫤","DoubleLongLeftArrow;":"⟸","DoubleLongLeftRightArrow;":"⟺","DoubleLongRightArrow;":"⟹","DoubleRightArrow;":"⇒","DoubleRightTee;":"⊨","DoubleUpArrow;":"⇑","DoubleUpDownArrow;":"⇕","DoubleVerticalBar;":"∥","DownArrow;":"↓","DownArrowBar;":"⤓","DownArrowUpArrow;":"⇵","DownBreve;":"̑","DownLeftRightVector;":"⥐","DownLeftTeeVector;":"⥞","DownLeftVector;":"↽","DownLeftVectorBar;":"⥖","DownRightTeeVector;":"⥟","DownRightVector;":"⇁","DownRightVectorBar;":"⥗","DownTee;":"⊤","DownTeeArrow;":"↧","Downarrow;":"⇓","Dscr;":"𝒟","Dstrok;":"Đ","ENG;":"Ŋ","ETH":"Ð","ETH;":"Ð","Eacute":"É","Eacute;":"É","Ecaron;":"Ě","Ecirc":"Ê","Ecirc;":"Ê","Ecy;":"Э","Edot;":"Ė","Efr;":"𝔈","Egrave":"È","Egrave;":"È","Element;":"∈","Emacr;":"Ē","EmptySmallSquare;":"◻","EmptyVerySmallSquare;":"▫","Eogon;":"Ę","Eopf;":"𝔼","Epsilon;":"Ε","Equal;":"⩵","EqualTilde;":"≂","Equilibrium;":"⇌","Escr;":"ℰ","Esim;":"⩳","Eta;":"Η","Euml":"Ë","Euml;":"Ë","Exists;":"∃","ExponentialE;":"ⅇ","Fcy;":"Ф","Ffr;":"𝔉","FilledSmallSquare;":"◼","FilledVerySmallSquare;":"▪","Fopf;":"𝔽","ForAll;":"∀","Fouriertrf;":"ℱ","Fscr;":"ℱ","GJcy;":"Ѓ","GT":">","GT;":">","Gamma;":"Γ","Gammad;":"Ϝ","Gbreve;":"Ğ","Gcedil;":"Ģ","Gcirc;":"Ĝ","Gcy;":"Г","Gdot;":"Ġ","Gfr;":"𝔊","Gg;":"⋙","Gopf;":"𝔾","GreaterEqual;":"≥","GreaterEqualLess;":"⋛","GreaterFullEqual;":"≧","GreaterGreater;":"⪢","GreaterLess;":"≷","GreaterSlantEqual;":"⩾","GreaterTilde;":"≳","Gscr;":"𝒢","Gt;":"≫","HARDcy;":"Ъ","Hacek;":"ˇ","Hat;":"^","Hcirc;":"Ĥ","Hfr;":"ℌ","HilbertSpace;":"ℋ","Hopf;":"ℍ","HorizontalLine;":"─","Hscr;":"ℋ","Hstrok;":"Ħ","HumpDownHump;":"≎","HumpEqual;":"≏","IEcy;":"Е","IJlig;":"IJ","IOcy;":"Ё","Iacute":"Í","Iacute;":"Í","Icirc":"Î","Icirc;":"Î","Icy;":"И","Idot;":"İ","Ifr;":"ℑ","Igrave":"Ì","Igrave;":"Ì","Im;":"ℑ","Imacr;":"Ī","ImaginaryI;":"ⅈ","Implies;":"⇒","Int;":"∬","Integral;":"∫","Intersection;":"⋂","InvisibleComma;":"⁣","InvisibleTimes;":"⁢","Iogon;":"Į","Iopf;":"𝕀","Iota;":"Ι","Iscr;":"ℐ","Itilde;":"Ĩ","Iukcy;":"І","Iuml":"Ï","Iuml;":"Ï","Jcirc;":"Ĵ","Jcy;":"Й","Jfr;":"𝔍","Jopf;":"𝕁","Jscr;":"𝒥","Jsercy;":"Ј","Jukcy;":"Є","KHcy;":"Х","KJcy;":"Ќ","Kappa;":"Κ","Kcedil;":"Ķ","Kcy;":"К","Kfr;":"𝔎","Kopf;":"𝕂","Kscr;":"𝒦","LJcy;":"Љ","LT":"<","LT;":"<","Lacute;":"Ĺ","Lambda;":"Λ","Lang;":"⟪","Laplacetrf;":"ℒ","Larr;":"↞","Lcaron;":"Ľ","Lcedil;":"Ļ","Lcy;":"Л","LeftAngleBracket;":"⟨","LeftArrow;":"←","LeftArrowBar;":"⇤","LeftArrowRightArrow;":"⇆","LeftCeiling;":"⌈","LeftDoubleBracket;":"⟦","LeftDownTeeVector;":"⥡","LeftDownVector;":"⇃","LeftDownVectorBar;":"⥙","LeftFloor;":"⌊","LeftRightArrow;":"↔","LeftRightVector;":"⥎","LeftTee;":"⊣","LeftTeeArrow;":"↤","LeftTeeVector;":"⥚","LeftTriangle;":"⊲","LeftTriangleBar;":"⧏","LeftTriangleEqual;":"⊴","LeftUpDownVector;":"⥑","LeftUpTeeVector;":"⥠","LeftUpVector;":"↿","LeftUpVectorBar;":"⥘","LeftVector;":"↼","LeftVectorBar;":"⥒","Leftarrow;":"⇐","Leftrightarrow;":"⇔","LessEqualGreater;":"⋚","LessFullEqual;":"≦","LessGreater;":"≶","LessLess;":"⪡","LessSlantEqual;":"⩽","LessTilde;":"≲","Lfr;":"𝔏","Ll;":"⋘","Lleftarrow;":"⇚","Lmidot;":"Ŀ","LongLeftArrow;":"⟵","LongLeftRightArrow;":"⟷","LongRightArrow;":"⟶","Longleftarrow;":"⟸","Longleftrightarrow;":"⟺","Longrightarrow;":"⟹","Lopf;":"𝕃","LowerLeftArrow;":"↙","LowerRightArrow;":"↘","Lscr;":"ℒ","Lsh;":"↰","Lstrok;":"Ł","Lt;":"≪","Map;":"⤅","Mcy;":"М","MediumSpace;":" ","Mellintrf;":"ℳ","Mfr;":"𝔐","MinusPlus;":"∓","Mopf;":"𝕄","Mscr;":"ℳ","Mu;":"Μ","NJcy;":"Њ","Nacute;":"Ń","Ncaron;":"Ň","Ncedil;":"Ņ","Ncy;":"Н","NegativeMediumSpace;":"​","NegativeThickSpace;":"​","NegativeThinSpace;":"​","NegativeVeryThinSpace;":"​","NestedGreaterGreater;":"≫","NestedLessLess;":"≪","NewLine;":"\n","Nfr;":"𝔑","NoBreak;":"⁠","NonBreakingSpace;":" ","Nopf;":"ℕ","Not;":"⫬","NotCongruent;":"≢","NotCupCap;":"≭","NotDoubleVerticalBar;":"∦","NotElement;":"∉","NotEqual;":"≠","NotEqualTilde;":"≂̸","NotExists;":"∄","NotGreater;":"≯","NotGreaterEqual;":"≱","NotGreaterFullEqual;":"≧̸","NotGreaterGreater;":"≫̸","NotGreaterLess;":"≹","NotGreaterSlantEqual;":"⩾̸","NotGreaterTilde;":"≵","NotHumpDownHump;":"≎̸","NotHumpEqual;":"≏̸","NotLeftTriangle;":"⋪","NotLeftTriangleBar;":"⧏̸","NotLeftTriangleEqual;":"⋬","NotLess;":"≮","NotLessEqual;":"≰","NotLessGreater;":"≸","NotLessLess;":"≪̸","NotLessSlantEqual;":"⩽̸","NotLessTilde;":"≴","NotNestedGreaterGreater;":"⪢̸","NotNestedLessLess;":"⪡̸","NotPrecedes;":"⊀","NotPrecedesEqual;":"⪯̸","NotPrecedesSlantEqual;":"⋠","NotReverseElement;":"∌","NotRightTriangle;":"⋫","NotRightTriangleBar;":"⧐̸","NotRightTriangleEqual;":"⋭","NotSquareSubset;":"⊏̸","NotSquareSubsetEqual;":"⋢","NotSquareSuperset;":"⊐̸","NotSquareSupersetEqual;":"⋣","NotSubset;":"⊂⃒","NotSubsetEqual;":"⊈","NotSucceeds;":"⊁","NotSucceedsEqual;":"⪰̸","NotSucceedsSlantEqual;":"⋡","NotSucceedsTilde;":"≿̸","NotSuperset;":"⊃⃒","NotSupersetEqual;":"⊉","NotTilde;":"≁","NotTildeEqual;":"≄","NotTildeFullEqual;":"≇","NotTildeTilde;":"≉","NotVerticalBar;":"∤","Nscr;":"𝒩","Ntilde":"Ñ","Ntilde;":"Ñ","Nu;":"Ν","OElig;":"Œ","Oacute":"Ó","Oacute;":"Ó","Ocirc":"Ô","Ocirc;":"Ô","Ocy;":"О","Odblac;":"Ő","Ofr;":"𝔒","Ograve":"Ò","Ograve;":"Ò","Omacr;":"Ō","Omega;":"Ω","Omicron;":"Ο","Oopf;":"𝕆","OpenCurlyDoubleQuote;":"“","OpenCurlyQuote;":"‘","Or;":"⩔","Oscr;":"𝒪","Oslash":"Ø","Oslash;":"Ø","Otilde":"Õ","Otilde;":"Õ","Otimes;":"⨷","Ouml":"Ö","Ouml;":"Ö","OverBar;":"‾","OverBrace;":"⏞","OverBracket;":"⎴","OverParenthesis;":"⏜","PartialD;":"∂","Pcy;":"П","Pfr;":"𝔓","Phi;":"Φ","Pi;":"Π","PlusMinus;":"±","Poincareplane;":"ℌ","Popf;":"ℙ","Pr;":"⪻","Precedes;":"≺","PrecedesEqual;":"⪯","PrecedesSlantEqual;":"≼","PrecedesTilde;":"≾","Prime;":"″","Product;":"∏","Proportion;":"∷","Proportional;":"∝","Pscr;":"𝒫","Psi;":"Ψ","QUOT":"\"","QUOT;":"\"","Qfr;":"𝔔","Qopf;":"ℚ","Qscr;":"𝒬","RBarr;":"⤐","REG":"®","REG;":"®","Racute;":"Ŕ","Rang;":"⟫","Rarr;":"↠","Rarrtl;":"⤖","Rcaron;":"Ř","Rcedil;":"Ŗ","Rcy;":"Р","Re;":"ℜ","ReverseElement;":"∋","ReverseEquilibrium;":"⇋","ReverseUpEquilibrium;":"⥯","Rfr;":"ℜ","Rho;":"Ρ","RightAngleBracket;":"⟩","RightArrow;":"→","RightArrowBar;":"⇥","RightArrowLeftArrow;":"⇄","RightCeiling;":"⌉","RightDoubleBracket;":"⟧","RightDownTeeVector;":"⥝","RightDownVector;":"⇂","RightDownVectorBar;":"⥕","RightFloor;":"⌋","RightTee;":"⊢","RightTeeArrow;":"↦","RightTeeVector;":"⥛","RightTriangle;":"⊳","RightTriangleBar;":"⧐","RightTriangleEqual;":"⊵","RightUpDownVector;":"⥏","RightUpTeeVector;":"⥜","RightUpVector;":"↾","RightUpVectorBar;":"⥔","RightVector;":"⇀","RightVectorBar;":"⥓","Rightarrow;":"⇒","Ropf;":"ℝ","RoundImplies;":"⥰","Rrightarrow;":"⇛","Rscr;":"ℛ","Rsh;":"↱","RuleDelayed;":"⧴","SHCHcy;":"Щ","SHcy;":"Ш","SOFTcy;":"Ь","Sacute;":"Ś","Sc;":"⪼","Scaron;":"Š","Scedil;":"Ş","Scirc;":"Ŝ","Scy;":"С","Sfr;":"𝔖","ShortDownArrow;":"↓","ShortLeftArrow;":"←","ShortRightArrow;":"→","ShortUpArrow;":"↑","Sigma;":"Σ","SmallCircle;":"∘","Sopf;":"𝕊","Sqrt;":"√","Square;":"□","SquareIntersection;":"⊓","SquareSubset;":"⊏","SquareSubsetEqual;":"⊑","SquareSuperset;":"⊐","SquareSupersetEqual;":"⊒","SquareUnion;":"⊔","Sscr;":"𝒮","Star;":"⋆","Sub;":"⋐","Subset;":"⋐","SubsetEqual;":"⊆","Succeeds;":"≻","SucceedsEqual;":"⪰","SucceedsSlantEqual;":"≽","SucceedsTilde;":"≿","SuchThat;":"∋","Sum;":"∑","Sup;":"⋑","Superset;":"⊃","SupersetEqual;":"⊇","Supset;":"⋑","THORN":"Þ","THORN;":"Þ","TRADE;":"™","TSHcy;":"Ћ","TScy;":"Ц","Tab;":"\t","Tau;":"Τ","Tcaron;":"Ť","Tcedil;":"Ţ","Tcy;":"Т","Tfr;":"𝔗","Therefore;":"∴","Theta;":"Θ","ThickSpace;":"  ","ThinSpace;":" ","Tilde;":"∼","TildeEqual;":"≃","TildeFullEqual;":"≅","TildeTilde;":"≈","Topf;":"𝕋","TripleDot;":"⃛","Tscr;":"𝒯","Tstrok;":"Ŧ","Uacute":"Ú","Uacute;":"Ú","Uarr;":"↟","Uarrocir;":"⥉","Ubrcy;":"Ў","Ubreve;":"Ŭ","Ucirc":"Û","Ucirc;":"Û","Ucy;":"У","Udblac;":"Ű","Ufr;":"𝔘","Ugrave":"Ù","Ugrave;":"Ù","Umacr;":"Ū","UnderBar;":"_","UnderBrace;":"⏟","UnderBracket;":"⎵","UnderParenthesis;":"⏝","Union;":"⋃","UnionPlus;":"⊎","Uogon;":"Ų","Uopf;":"𝕌","UpArrow;":"↑","UpArrowBar;":"⤒","UpArrowDownArrow;":"⇅","UpDownArrow;":"↕","UpEquilibrium;":"⥮","UpTee;":"⊥","UpTeeArrow;":"↥","Uparrow;":"⇑","Updownarrow;":"⇕","UpperLeftArrow;":"↖","UpperRightArrow;":"↗","Upsi;":"ϒ","Upsilon;":"Υ","Uring;":"Ů","Uscr;":"𝒰","Utilde;":"Ũ","Uuml":"Ü","Uuml;":"Ü","VDash;":"⊫","Vbar;":"⫫","Vcy;":"В","Vdash;":"⊩","Vdashl;":"⫦","Vee;":"⋁","Verbar;":"‖","Vert;":"‖","VerticalBar;":"∣","VerticalLine;":"|","VerticalSeparator;":"❘","VerticalTilde;":"≀","VeryThinSpace;":" ","Vfr;":"𝔙","Vopf;":"𝕍","Vscr;":"𝒱","Vvdash;":"⊪","Wcirc;":"Ŵ","Wedge;":"⋀","Wfr;":"𝔚","Wopf;":"𝕎","Wscr;":"𝒲","Xfr;":"𝔛","Xi;":"Ξ","Xopf;":"𝕏","Xscr;":"𝒳","YAcy;":"Я","YIcy;":"Ї","YUcy;":"Ю","Yacute":"Ý","Yacute;":"Ý","Ycirc;":"Ŷ","Ycy;":"Ы","Yfr;":"𝔜","Yopf;":"𝕐","Yscr;":"𝒴","Yuml;":"Ÿ","ZHcy;":"Ж","Zacute;":"Ź","Zcaron;":"Ž","Zcy;":"З","Zdot;":"Ż","ZeroWidthSpace;":"​","Zeta;":"Ζ","Zfr;":"ℨ","Zopf;":"ℤ","Zscr;":"𝒵","aacute":"á","aacute;":"á","abreve;":"ă","ac;":"∾","acE;":"∾̳","acd;":"∿","acirc":"â","acirc;":"â","acute":"´","acute;":"´","acy;":"а","aelig":"æ","aelig;":"æ","af;":"⁡","afr;":"𝔞","agrave":"à","agrave;":"à","alefsym;":"ℵ","aleph;":"ℵ","alpha;":"α","amacr;":"ā","amalg;":"⨿","amp":"&","amp;":"&","and;":"∧","andand;":"⩕","andd;":"⩜","andslope;":"⩘","andv;":"⩚","ang;":"∠","ange;":"⦤","angle;":"∠","angmsd;":"∡","angmsdaa;":"⦨","angmsdab;":"⦩","angmsdac;":"⦪","angmsdad;":"⦫","angmsdae;":"⦬","angmsdaf;":"⦭","angmsdag;":"⦮","angmsdah;":"⦯","angrt;":"∟","angrtvb;":"⊾","angrtvbd;":"⦝","angsph;":"∢","angst;":"Å","angzarr;":"⍼","aogon;":"ą","aopf;":"𝕒","ap;":"≈","apE;":"⩰","apacir;":"⩯","ape;":"≊","apid;":"≋","apos;":"'","approx;":"≈","approxeq;":"≊","aring":"å","aring;":"å","ascr;":"𝒶","ast;":"*","asymp;":"≈","asympeq;":"≍","atilde":"ã","atilde;":"ã","auml":"ä","auml;":"ä","awconint;":"∳","awint;":"⨑","bNot;":"⫭","backcong;":"≌","backepsilon;":"϶","backprime;":"‵","backsim;":"∽","backsimeq;":"⋍","barvee;":"⊽","barwed;":"⌅","barwedge;":"⌅","bbrk;":"⎵","bbrktbrk;":"⎶","bcong;":"≌","bcy;":"б","bdquo;":"„","becaus;":"∵","because;":"∵","bemptyv;":"⦰","bepsi;":"϶","bernou;":"ℬ","beta;":"β","beth;":"ℶ","between;":"≬","bfr;":"𝔟","bigcap;":"⋂","bigcirc;":"◯","bigcup;":"⋃","bigodot;":"⨀","bigoplus;":"⨁","bigotimes;":"⨂","bigsqcup;":"⨆","bigstar;":"★","bigtriangledown;":"▽","bigtriangleup;":"△","biguplus;":"⨄","bigvee;":"⋁","bigwedge;":"⋀","bkarow;":"⤍","blacklozenge;":"⧫","blacksquare;":"▪","blacktriangle;":"▴","blacktriangledown;":"▾","blacktriangleleft;":"◂","blacktriangleright;":"▸","blank;":"␣","blk12;":"▒","blk14;":"░","blk34;":"▓","block;":"█","bne;":"=⃥","bnequiv;":"≡⃥","bnot;":"⌐","bopf;":"𝕓","bot;":"⊥","bottom;":"⊥","bowtie;":"⋈","boxDL;":"╗","boxDR;":"╔","boxDl;":"╖","boxDr;":"╓","boxH;":"═","boxHD;":"╦","boxHU;":"╩","boxHd;":"╤","boxHu;":"╧","boxUL;":"╝","boxUR;":"╚","boxUl;":"╜","boxUr;":"╙","boxV;":"║","boxVH;":"╬","boxVL;":"╣","boxVR;":"╠","boxVh;":"╫","boxVl;":"╢","boxVr;":"╟","boxbox;":"⧉","boxdL;":"╕","boxdR;":"╒","boxdl;":"┐","boxdr;":"┌","boxh;":"─","boxhD;":"╥","boxhU;":"╨","boxhd;":"┬","boxhu;":"┴","boxminus;":"⊟","boxplus;":"⊞","boxtimes;":"⊠","boxuL;":"╛","boxuR;":"╘","boxul;":"┘","boxur;":"└","boxv;":"│","boxvH;":"╪","boxvL;":"╡","boxvR;":"╞","boxvh;":"┼","boxvl;":"┤","boxvr;":"├","bprime;":"‵","breve;":"˘","brvbar":"¦","brvbar;":"¦","bscr;":"𝒷","bsemi;":"⁏","bsim;":"∽","bsime;":"⋍","bsol;":"\\","bsolb;":"⧅","bsolhsub;":"⟈","bull;":"•","bullet;":"•","bump;":"≎","bumpE;":"⪮","bumpe;":"≏","bumpeq;":"≏","cacute;":"ć","cap;":"∩","capand;":"⩄","capbrcup;":"⩉","capcap;":"⩋","capcup;":"⩇","capdot;":"⩀","caps;":"∩︀","caret;":"⁁","caron;":"ˇ","ccaps;":"⩍","ccaron;":"č","ccedil":"ç","ccedil;":"ç","ccirc;":"ĉ","ccups;":"⩌","ccupssm;":"⩐","cdot;":"ċ","cedil":"¸","cedil;":"¸","cemptyv;":"⦲","cent":"¢","cent;":"¢","centerdot;":"·","cfr;":"𝔠","chcy;":"ч","check;":"✓","checkmark;":"✓","chi;":"χ","cir;":"○","cirE;":"⧃","circ;":"ˆ","circeq;":"≗","circlearrowleft;":"↺","circlearrowright;":"↻","circledR;":"®","circledS;":"Ⓢ","circledast;":"⊛","circledcirc;":"⊚","circleddash;":"⊝","cire;":"≗","cirfnint;":"⨐","cirmid;":"⫯","cirscir;":"⧂","clubs;":"♣","clubsuit;":"♣","colon;":":","colone;":"≔","coloneq;":"≔","comma;":",","commat;":"@","comp;":"∁","compfn;":"∘","complement;":"∁","complexes;":"ℂ","cong;":"≅","congdot;":"⩭","conint;":"∮","copf;":"𝕔","coprod;":"∐","copy":"©","copy;":"©","copysr;":"℗","crarr;":"↵","cross;":"✗","cscr;":"𝒸","csub;":"⫏","csube;":"⫑","csup;":"⫐","csupe;":"⫒","ctdot;":"⋯","cudarrl;":"⤸","cudarrr;":"⤵","cuepr;":"⋞","cuesc;":"⋟","cularr;":"↶","cularrp;":"⤽","cup;":"∪","cupbrcap;":"⩈","cupcap;":"⩆","cupcup;":"⩊","cupdot;":"⊍","cupor;":"⩅","cups;":"∪︀","curarr;":"↷","curarrm;":"⤼","curlyeqprec;":"⋞","curlyeqsucc;":"⋟","curlyvee;":"⋎","curlywedge;":"⋏","curren":"¤","curren;":"¤","curvearrowleft;":"↶","curvearrowright;":"↷","cuvee;":"⋎","cuwed;":"⋏","cwconint;":"∲","cwint;":"∱","cylcty;":"⌭","dArr;":"⇓","dHar;":"⥥","dagger;":"†","daleth;":"ℸ","darr;":"↓","dash;":"‐","dashv;":"⊣","dbkarow;":"⤏","dblac;":"˝","dcaron;":"ď","dcy;":"д","dd;":"ⅆ","ddagger;":"‡","ddarr;":"⇊","ddotseq;":"⩷","deg":"°","deg;":"°","delta;":"δ","demptyv;":"⦱","dfisht;":"⥿","dfr;":"𝔡","dharl;":"⇃","dharr;":"⇂","diam;":"⋄","diamond;":"⋄","diamondsuit;":"♦","diams;":"♦","die;":"¨","digamma;":"ϝ","disin;":"⋲","div;":"÷","divide":"÷","divide;":"÷","divideontimes;":"⋇","divonx;":"⋇","djcy;":"ђ","dlcorn;":"⌞","dlcrop;":"⌍","dollar;":"$","dopf;":"𝕕","dot;":"˙","doteq;":"≐","doteqdot;":"≑","dotminus;":"∸","dotplus;":"∔","dotsquare;":"⊡","doublebarwedge;":"⌆","downarrow;":"↓","downdownarrows;":"⇊","downharpoonleft;":"⇃","downharpoonright;":"⇂","drbkarow;":"⤐","drcorn;":"⌟","drcrop;":"⌌","dscr;":"𝒹","dscy;":"ѕ","dsol;":"⧶","dstrok;":"đ","dtdot;":"⋱","dtri;":"▿","dtrif;":"▾","duarr;":"⇵","duhar;":"⥯","dwangle;":"⦦","dzcy;":"џ","dzigrarr;":"⟿","eDDot;":"⩷","eDot;":"≑","eacute":"é","eacute;":"é","easter;":"⩮","ecaron;":"ě","ecir;":"≖","ecirc":"ê","ecirc;":"ê","ecolon;":"≕","ecy;":"э","edot;":"ė","ee;":"ⅇ","efDot;":"≒","efr;":"𝔢","eg;":"⪚","egrave":"è","egrave;":"è","egs;":"⪖","egsdot;":"⪘","el;":"⪙","elinters;":"⏧","ell;":"ℓ","els;":"⪕","elsdot;":"⪗","emacr;":"ē","empty;":"∅","emptyset;":"∅","emptyv;":"∅","emsp13;":" ","emsp14;":" ","emsp;":" ","eng;":"ŋ","ensp;":" ","eogon;":"ę","eopf;":"𝕖","epar;":"⋕","eparsl;":"⧣","eplus;":"⩱","epsi;":"ε","epsilon;":"ε","epsiv;":"ϵ","eqcirc;":"≖","eqcolon;":"≕","eqsim;":"≂","eqslantgtr;":"⪖","eqslantless;":"⪕","equals;":"=","equest;":"≟","equiv;":"≡","equivDD;":"⩸","eqvparsl;":"⧥","erDot;":"≓","erarr;":"⥱","escr;":"ℯ","esdot;":"≐","esim;":"≂","eta;":"η","eth":"ð","eth;":"ð","euml":"ë","euml;":"ë","euro;":"€","excl;":"!","exist;":"∃","expectation;":"ℰ","exponentiale;":"ⅇ","fallingdotseq;":"≒","fcy;":"ф","female;":"♀","ffilig;":"ffi","fflig;":"ff","ffllig;":"ffl","ffr;":"𝔣","filig;":"fi","fjlig;":"fj","flat;":"♭","fllig;":"fl","fltns;":"▱","fnof;":"ƒ","fopf;":"𝕗","forall;":"∀","fork;":"⋔","forkv;":"⫙","fpartint;":"⨍","frac12":"½","frac12;":"½","frac13;":"⅓","frac14":"¼","frac14;":"¼","frac15;":"⅕","frac16;":"⅙","frac18;":"⅛","frac23;":"⅔","frac25;":"⅖","frac34":"¾","frac34;":"¾","frac35;":"⅗","frac38;":"⅜","frac45;":"⅘","frac56;":"⅚","frac58;":"⅝","frac78;":"⅞","frasl;":"⁄","frown;":"⌢","fscr;":"𝒻","gE;":"≧","gEl;":"⪌","gacute;":"ǵ","gamma;":"γ","gammad;":"ϝ","gap;":"⪆","gbreve;":"ğ","gcirc;":"ĝ","gcy;":"г","gdot;":"ġ","ge;":"≥","gel;":"⋛","geq;":"≥","geqq;":"≧","geqslant;":"⩾","ges;":"⩾","gescc;":"⪩","gesdot;":"⪀","gesdoto;":"⪂","gesdotol;":"⪄","gesl;":"⋛︀","gesles;":"⪔","gfr;":"𝔤","gg;":"≫","ggg;":"⋙","gimel;":"ℷ","gjcy;":"ѓ","gl;":"≷","glE;":"⪒","gla;":"⪥","glj;":"⪤","gnE;":"≩","gnap;":"⪊","gnapprox;":"⪊","gne;":"⪈","gneq;":"⪈","gneqq;":"≩","gnsim;":"⋧","gopf;":"𝕘","grave;":"`","gscr;":"ℊ","gsim;":"≳","gsime;":"⪎","gsiml;":"⪐","gt":">","gt;":">","gtcc;":"⪧","gtcir;":"⩺","gtdot;":"⋗","gtlPar;":"⦕","gtquest;":"⩼","gtrapprox;":"⪆","gtrarr;":"⥸","gtrdot;":"⋗","gtreqless;":"⋛","gtreqqless;":"⪌","gtrless;":"≷","gtrsim;":"≳","gvertneqq;":"≩︀","gvnE;":"≩︀","hArr;":"⇔","hairsp;":" ","half;":"½","hamilt;":"ℋ","hardcy;":"ъ","harr;":"↔","harrcir;":"⥈","harrw;":"↭","hbar;":"ℏ","hcirc;":"ĥ","hearts;":"♥","heartsuit;":"♥","hellip;":"…","hercon;":"⊹","hfr;":"𝔥","hksearow;":"⤥","hkswarow;":"⤦","hoarr;":"⇿","homtht;":"∻","hookleftarrow;":"↩","hookrightarrow;":"↪","hopf;":"𝕙","horbar;":"―","hscr;":"𝒽","hslash;":"ℏ","hstrok;":"ħ","hybull;":"⁃","hyphen;":"‐","iacute":"í","iacute;":"í","ic;":"⁣","icirc":"î","icirc;":"î","icy;":"и","iecy;":"е","iexcl":"¡","iexcl;":"¡","iff;":"⇔","ifr;":"𝔦","igrave":"ì","igrave;":"ì","ii;":"ⅈ","iiiint;":"⨌","iiint;":"∭","iinfin;":"⧜","iiota;":"℩","ijlig;":"ij","imacr;":"ī","image;":"ℑ","imagline;":"ℐ","imagpart;":"ℑ","imath;":"ı","imof;":"⊷","imped;":"Ƶ","in;":"∈","incare;":"℅","infin;":"∞","infintie;":"⧝","inodot;":"ı","int;":"∫","intcal;":"⊺","integers;":"ℤ","intercal;":"⊺","intlarhk;":"⨗","intprod;":"⨼","iocy;":"ё","iogon;":"į","iopf;":"𝕚","iota;":"ι","iprod;":"⨼","iquest":"¿","iquest;":"¿","iscr;":"𝒾","isin;":"∈","isinE;":"⋹","isindot;":"⋵","isins;":"⋴","isinsv;":"⋳","isinv;":"∈","it;":"⁢","itilde;":"ĩ","iukcy;":"і","iuml":"ï","iuml;":"ï","jcirc;":"ĵ","jcy;":"й","jfr;":"𝔧","jmath;":"ȷ","jopf;":"𝕛","jscr;":"𝒿","jsercy;":"ј","jukcy;":"є","kappa;":"κ","kappav;":"ϰ","kcedil;":"ķ","kcy;":"к","kfr;":"𝔨","kgreen;":"ĸ","khcy;":"х","kjcy;":"ќ","kopf;":"𝕜","kscr;":"𝓀","lAarr;":"⇚","lArr;":"⇐","lAtail;":"⤛","lBarr;":"⤎","lE;":"≦","lEg;":"⪋","lHar;":"⥢","lacute;":"ĺ","laemptyv;":"⦴","lagran;":"ℒ","lambda;":"λ","lang;":"⟨","langd;":"⦑","langle;":"⟨","lap;":"⪅","laquo":"«","laquo;":"«","larr;":"←","larrb;":"⇤","larrbfs;":"⤟","larrfs;":"⤝","larrhk;":"↩","larrlp;":"↫","larrpl;":"⤹","larrsim;":"⥳","larrtl;":"↢","lat;":"⪫","latail;":"⤙","late;":"⪭","lates;":"⪭︀","lbarr;":"⤌","lbbrk;":"❲","lbrace;":"{","lbrack;":"[","lbrke;":"⦋","lbrksld;":"⦏","lbrkslu;":"⦍","lcaron;":"ľ","lcedil;":"ļ","lceil;":"⌈","lcub;":"{","lcy;":"л","ldca;":"⤶","ldquo;":"“","ldquor;":"„","ldrdhar;":"⥧","ldrushar;":"⥋","ldsh;":"↲","le;":"≤","leftarrow;":"←","leftarrowtail;":"↢","leftharpoondown;":"↽","leftharpoonup;":"↼","leftleftarrows;":"⇇","leftrightarrow;":"↔","leftrightarrows;":"⇆","leftrightharpoons;":"⇋","leftrightsquigarrow;":"↭","leftthreetimes;":"⋋","leg;":"⋚","leq;":"≤","leqq;":"≦","leqslant;":"⩽","les;":"⩽","lescc;":"⪨","lesdot;":"⩿","lesdoto;":"⪁","lesdotor;":"⪃","lesg;":"⋚︀","lesges;":"⪓","lessapprox;":"⪅","lessdot;":"⋖","lesseqgtr;":"⋚","lesseqqgtr;":"⪋","lessgtr;":"≶","lesssim;":"≲","lfisht;":"⥼","lfloor;":"⌊","lfr;":"𝔩","lg;":"≶","lgE;":"⪑","lhard;":"↽","lharu;":"↼","lharul;":"⥪","lhblk;":"▄","ljcy;":"љ","ll;":"≪","llarr;":"⇇","llcorner;":"⌞","llhard;":"⥫","lltri;":"◺","lmidot;":"ŀ","lmoust;":"⎰","lmoustache;":"⎰","lnE;":"≨","lnap;":"⪉","lnapprox;":"⪉","lne;":"⪇","lneq;":"⪇","lneqq;":"≨","lnsim;":"⋦","loang;":"⟬","loarr;":"⇽","lobrk;":"⟦","longleftarrow;":"⟵","longleftrightarrow;":"⟷","longmapsto;":"⟼","longrightarrow;":"⟶","looparrowleft;":"↫","looparrowright;":"↬","lopar;":"⦅","lopf;":"𝕝","loplus;":"⨭","lotimes;":"⨴","lowast;":"∗","lowbar;":"_","loz;":"◊","lozenge;":"◊","lozf;":"⧫","lpar;":"(","lparlt;":"⦓","lrarr;":"⇆","lrcorner;":"⌟","lrhar;":"⇋","lrhard;":"⥭","lrm;":"‎","lrtri;":"⊿","lsaquo;":"‹","lscr;":"𝓁","lsh;":"↰","lsim;":"≲","lsime;":"⪍","lsimg;":"⪏","lsqb;":"[","lsquo;":"‘","lsquor;":"‚","lstrok;":"ł","lt":"<","lt;":"<","ltcc;":"⪦","ltcir;":"⩹","ltdot;":"⋖","lthree;":"⋋","ltimes;":"⋉","ltlarr;":"⥶","ltquest;":"⩻","ltrPar;":"⦖","ltri;":"◃","ltrie;":"⊴","ltrif;":"◂","lurdshar;":"⥊","luruhar;":"⥦","lvertneqq;":"≨︀","lvnE;":"≨︀","mDDot;":"∺","macr":"¯","macr;":"¯","male;":"♂","malt;":"✠","maltese;":"✠","map;":"↦","mapsto;":"↦","mapstodown;":"↧","mapstoleft;":"↤","mapstoup;":"↥","marker;":"▮","mcomma;":"⨩","mcy;":"м","mdash;":"—","measuredangle;":"∡","mfr;":"𝔪","mho;":"℧","micro":"µ","micro;":"µ","mid;":"∣","midast;":"*","midcir;":"⫰","middot":"·","middot;":"·","minus;":"−","minusb;":"⊟","minusd;":"∸","minusdu;":"⨪","mlcp;":"⫛","mldr;":"…","mnplus;":"∓","models;":"⊧","mopf;":"𝕞","mp;":"∓","mscr;":"𝓂","mstpos;":"∾","mu;":"μ","multimap;":"⊸","mumap;":"⊸","nGg;":"⋙̸","nGt;":"≫⃒","nGtv;":"≫̸","nLeftarrow;":"⇍","nLeftrightarrow;":"⇎","nLl;":"⋘̸","nLt;":"≪⃒","nLtv;":"≪̸","nRightarrow;":"⇏","nVDash;":"⊯","nVdash;":"⊮","nabla;":"∇","nacute;":"ń","nang;":"∠⃒","nap;":"≉","napE;":"⩰̸","napid;":"≋̸","napos;":"ʼn","napprox;":"≉","natur;":"♮","natural;":"♮","naturals;":"ℕ","nbsp":" ","nbsp;":" ","nbump;":"≎̸","nbumpe;":"≏̸","ncap;":"⩃","ncaron;":"ň","ncedil;":"ņ","ncong;":"≇","ncongdot;":"⩭̸","ncup;":"⩂","ncy;":"н","ndash;":"–","ne;":"≠","neArr;":"⇗","nearhk;":"⤤","nearr;":"↗","nearrow;":"↗","nedot;":"≐̸","nequiv;":"≢","nesear;":"⤨","nesim;":"≂̸","nexist;":"∄","nexists;":"∄","nfr;":"𝔫","ngE;":"≧̸","nge;":"≱","ngeq;":"≱","ngeqq;":"≧̸","ngeqslant;":"⩾̸","nges;":"⩾̸","ngsim;":"≵","ngt;":"≯","ngtr;":"≯","nhArr;":"⇎","nharr;":"↮","nhpar;":"⫲","ni;":"∋","nis;":"⋼","nisd;":"⋺","niv;":"∋","njcy;":"њ","nlArr;":"⇍","nlE;":"≦̸","nlarr;":"↚","nldr;":"‥","nle;":"≰","nleftarrow;":"↚","nleftrightarrow;":"↮","nleq;":"≰","nleqq;":"≦̸","nleqslant;":"⩽̸","nles;":"⩽̸","nless;":"≮","nlsim;":"≴","nlt;":"≮","nltri;":"⋪","nltrie;":"⋬","nmid;":"∤","nopf;":"𝕟","not":"¬","not;":"¬","notin;":"∉","notinE;":"⋹̸","notindot;":"⋵̸","notinva;":"∉","notinvb;":"⋷","notinvc;":"⋶","notni;":"∌","notniva;":"∌","notnivb;":"⋾","notnivc;":"⋽","npar;":"∦","nparallel;":"∦","nparsl;":"⫽⃥","npart;":"∂̸","npolint;":"⨔","npr;":"⊀","nprcue;":"⋠","npre;":"⪯̸","nprec;":"⊀","npreceq;":"⪯̸","nrArr;":"⇏","nrarr;":"↛","nrarrc;":"⤳̸","nrarrw;":"↝̸","nrightarrow;":"↛","nrtri;":"⋫","nrtrie;":"⋭","nsc;":"⊁","nsccue;":"⋡","nsce;":"⪰̸","nscr;":"𝓃","nshortmid;":"∤","nshortparallel;":"∦","nsim;":"≁","nsime;":"≄","nsimeq;":"≄","nsmid;":"∤","nspar;":"∦","nsqsube;":"⋢","nsqsupe;":"⋣","nsub;":"⊄","nsubE;":"⫅̸","nsube;":"⊈","nsubset;":"⊂⃒","nsubseteq;":"⊈","nsubseteqq;":"⫅̸","nsucc;":"⊁","nsucceq;":"⪰̸","nsup;":"⊅","nsupE;":"⫆̸","nsupe;":"⊉","nsupset;":"⊃⃒","nsupseteq;":"⊉","nsupseteqq;":"⫆̸","ntgl;":"≹","ntilde":"ñ","ntilde;":"ñ","ntlg;":"≸","ntriangleleft;":"⋪","ntrianglelefteq;":"⋬","ntriangleright;":"⋫","ntrianglerighteq;":"⋭","nu;":"ν","num;":"#","numero;":"№","numsp;":" ","nvDash;":"⊭","nvHarr;":"⤄","nvap;":"≍⃒","nvdash;":"⊬","nvge;":"≥⃒","nvgt;":">⃒","nvinfin;":"⧞","nvlArr;":"⤂","nvle;":"≤⃒","nvlt;":"<⃒","nvltrie;":"⊴⃒","nvrArr;":"⤃","nvrtrie;":"⊵⃒","nvsim;":"∼⃒","nwArr;":"⇖","nwarhk;":"⤣","nwarr;":"↖","nwarrow;":"↖","nwnear;":"⤧","oS;":"Ⓢ","oacute":"ó","oacute;":"ó","oast;":"⊛","ocir;":"⊚","ocirc":"ô","ocirc;":"ô","ocy;":"о","odash;":"⊝","odblac;":"ő","odiv;":"⨸","odot;":"⊙","odsold;":"⦼","oelig;":"œ","ofcir;":"⦿","ofr;":"𝔬","ogon;":"˛","ograve":"ò","ograve;":"ò","ogt;":"⧁","ohbar;":"⦵","ohm;":"Ω","oint;":"∮","olarr;":"↺","olcir;":"⦾","olcross;":"⦻","oline;":"‾","olt;":"⧀","omacr;":"ō","omega;":"ω","omicron;":"ο","omid;":"⦶","ominus;":"⊖","oopf;":"𝕠","opar;":"⦷","operp;":"⦹","oplus;":"⊕","or;":"∨","orarr;":"↻","ord;":"⩝","order;":"ℴ","orderof;":"ℴ","ordf":"ª","ordf;":"ª","ordm":"º","ordm;":"º","origof;":"⊶","oror;":"⩖","orslope;":"⩗","orv;":"⩛","oscr;":"ℴ","oslash":"ø","oslash;":"ø","osol;":"⊘","otilde":"õ","otilde;":"õ","otimes;":"⊗","otimesas;":"⨶","ouml":"ö","ouml;":"ö","ovbar;":"⌽","par;":"∥","para":"¶","para;":"¶","parallel;":"∥","parsim;":"⫳","parsl;":"⫽","part;":"∂","pcy;":"п","percnt;":"%","period;":".","permil;":"‰","perp;":"⊥","pertenk;":"‱","pfr;":"𝔭","phi;":"φ","phiv;":"ϕ","phmmat;":"ℳ","phone;":"☎","pi;":"π","pitchfork;":"⋔","piv;":"ϖ","planck;":"ℏ","planckh;":"ℎ","plankv;":"ℏ","plus;":"+","plusacir;":"⨣","plusb;":"⊞","pluscir;":"⨢","plusdo;":"∔","plusdu;":"⨥","pluse;":"⩲","plusmn":"±","plusmn;":"±","plussim;":"⨦","plustwo;":"⨧","pm;":"±","pointint;":"⨕","popf;":"𝕡","pound":"£","pound;":"£","pr;":"≺","prE;":"⪳","prap;":"⪷","prcue;":"≼","pre;":"⪯","prec;":"≺","precapprox;":"⪷","preccurlyeq;":"≼","preceq;":"⪯","precnapprox;":"⪹","precneqq;":"⪵","precnsim;":"⋨","precsim;":"≾","prime;":"′","primes;":"ℙ","prnE;":"⪵","prnap;":"⪹","prnsim;":"⋨","prod;":"∏","profalar;":"⌮","profline;":"⌒","profsurf;":"⌓","prop;":"∝","propto;":"∝","prsim;":"≾","prurel;":"⊰","pscr;":"𝓅","psi;":"ψ","puncsp;":" ","qfr;":"𝔮","qint;":"⨌","qopf;":"𝕢","qprime;":"⁗","qscr;":"𝓆","quaternions;":"ℍ","quatint;":"⨖","quest;":"?","questeq;":"≟","quot":"\"","quot;":"\"","rAarr;":"⇛","rArr;":"⇒","rAtail;":"⤜","rBarr;":"⤏","rHar;":"⥤","race;":"∽̱","racute;":"ŕ","radic;":"√","raemptyv;":"⦳","rang;":"⟩","rangd;":"⦒","range;":"⦥","rangle;":"⟩","raquo":"»","raquo;":"»","rarr;":"→","rarrap;":"⥵","rarrb;":"⇥","rarrbfs;":"⤠","rarrc;":"⤳","rarrfs;":"⤞","rarrhk;":"↪","rarrlp;":"↬","rarrpl;":"⥅","rarrsim;":"⥴","rarrtl;":"↣","rarrw;":"↝","ratail;":"⤚","ratio;":"∶","rationals;":"ℚ","rbarr;":"⤍","rbbrk;":"❳","rbrace;":"}","rbrack;":"]","rbrke;":"⦌","rbrksld;":"⦎","rbrkslu;":"⦐","rcaron;":"ř","rcedil;":"ŗ","rceil;":"⌉","rcub;":"}","rcy;":"р","rdca;":"⤷","rdldhar;":"⥩","rdquo;":"”","rdquor;":"”","rdsh;":"↳","real;":"ℜ","realine;":"ℛ","realpart;":"ℜ","reals;":"ℝ","rect;":"▭","reg":"®","reg;":"®","rfisht;":"⥽","rfloor;":"⌋","rfr;":"𝔯","rhard;":"⇁","rharu;":"⇀","rharul;":"⥬","rho;":"ρ","rhov;":"ϱ","rightarrow;":"→","rightarrowtail;":"↣","rightharpoondown;":"⇁","rightharpoonup;":"⇀","rightleftarrows;":"⇄","rightleftharpoons;":"⇌","rightrightarrows;":"⇉","rightsquigarrow;":"↝","rightthreetimes;":"⋌","ring;":"˚","risingdotseq;":"≓","rlarr;":"⇄","rlhar;":"⇌","rlm;":"‏","rmoust;":"⎱","rmoustache;":"⎱","rnmid;":"⫮","roang;":"⟭","roarr;":"⇾","robrk;":"⟧","ropar;":"⦆","ropf;":"𝕣","roplus;":"⨮","rotimes;":"⨵","rpar;":")","rpargt;":"⦔","rppolint;":"⨒","rrarr;":"⇉","rsaquo;":"›","rscr;":"𝓇","rsh;":"↱","rsqb;":"]","rsquo;":"’","rsquor;":"’","rthree;":"⋌","rtimes;":"⋊","rtri;":"▹","rtrie;":"⊵","rtrif;":"▸","rtriltri;":"⧎","ruluhar;":"⥨","rx;":"℞","sacute;":"ś","sbquo;":"‚","sc;":"≻","scE;":"⪴","scap;":"⪸","scaron;":"š","sccue;":"≽","sce;":"⪰","scedil;":"ş","scirc;":"ŝ","scnE;":"⪶","scnap;":"⪺","scnsim;":"⋩","scpolint;":"⨓","scsim;":"≿","scy;":"с","sdot;":"⋅","sdotb;":"⊡","sdote;":"⩦","seArr;":"⇘","searhk;":"⤥","searr;":"↘","searrow;":"↘","sect":"§","sect;":"§","semi;":";","seswar;":"⤩","setminus;":"∖","setmn;":"∖","sext;":"✶","sfr;":"𝔰","sfrown;":"⌢","sharp;":"♯","shchcy;":"щ","shcy;":"ш","shortmid;":"∣","shortparallel;":"∥","shy":"­","shy;":"­","sigma;":"σ","sigmaf;":"ς","sigmav;":"ς","sim;":"∼","simdot;":"⩪","sime;":"≃","simeq;":"≃","simg;":"⪞","simgE;":"⪠","siml;":"⪝","simlE;":"⪟","simne;":"≆","simplus;":"⨤","simrarr;":"⥲","slarr;":"←","smallsetminus;":"∖","smashp;":"⨳","smeparsl;":"⧤","smid;":"∣","smile;":"⌣","smt;":"⪪","smte;":"⪬","smtes;":"⪬︀","softcy;":"ь","sol;":"/","solb;":"⧄","solbar;":"⌿","sopf;":"𝕤","spades;":"♠","spadesuit;":"♠","spar;":"∥","sqcap;":"⊓","sqcaps;":"⊓︀","sqcup;":"⊔","sqcups;":"⊔︀","sqsub;":"⊏","sqsube;":"⊑","sqsubset;":"⊏","sqsubseteq;":"⊑","sqsup;":"⊐","sqsupe;":"⊒","sqsupset;":"⊐","sqsupseteq;":"⊒","squ;":"□","square;":"□","squarf;":"▪","squf;":"▪","srarr;":"→","sscr;":"𝓈","ssetmn;":"∖","ssmile;":"⌣","sstarf;":"⋆","star;":"☆","starf;":"★","straightepsilon;":"ϵ","straightphi;":"ϕ","strns;":"¯","sub;":"⊂","subE;":"⫅","subdot;":"⪽","sube;":"⊆","subedot;":"⫃","submult;":"⫁","subnE;":"⫋","subne;":"⊊","subplus;":"⪿","subrarr;":"⥹","subset;":"⊂","subseteq;":"⊆","subseteqq;":"⫅","subsetneq;":"⊊","subsetneqq;":"⫋","subsim;":"⫇","subsub;":"⫕","subsup;":"⫓","succ;":"≻","succapprox;":"⪸","succcurlyeq;":"≽","succeq;":"⪰","succnapprox;":"⪺","succneqq;":"⪶","succnsim;":"⋩","succsim;":"≿","sum;":"∑","sung;":"♪","sup1":"¹","sup1;":"¹","sup2":"²","sup2;":"²","sup3":"³","sup3;":"³","sup;":"⊃","supE;":"⫆","supdot;":"⪾","supdsub;":"⫘","supe;":"⊇","supedot;":"⫄","suphsol;":"⟉","suphsub;":"⫗","suplarr;":"⥻","supmult;":"⫂","supnE;":"⫌","supne;":"⊋","supplus;":"⫀","supset;":"⊃","supseteq;":"⊇","supseteqq;":"⫆","supsetneq;":"⊋","supsetneqq;":"⫌","supsim;":"⫈","supsub;":"⫔","supsup;":"⫖","swArr;":"⇙","swarhk;":"⤦","swarr;":"↙","swarrow;":"↙","swnwar;":"⤪","szlig":"ß","szlig;":"ß","target;":"⌖","tau;":"τ","tbrk;":"⎴","tcaron;":"ť","tcedil;":"ţ","tcy;":"т","tdot;":"⃛","telrec;":"⌕","tfr;":"𝔱","there4;":"∴","therefore;":"∴","theta;":"θ","thetasym;":"ϑ","thetav;":"ϑ","thickapprox;":"≈","thicksim;":"∼","thinsp;":" ","thkap;":"≈","thksim;":"∼","thorn":"þ","thorn;":"þ","tilde;":"˜","times":"×","times;":"×","timesb;":"⊠","timesbar;":"⨱","timesd;":"⨰","tint;":"∭","toea;":"⤨","top;":"⊤","topbot;":"⌶","topcir;":"⫱","topf;":"𝕥","topfork;":"⫚","tosa;":"⤩","tprime;":"‴","trade;":"™","triangle;":"▵","triangledown;":"▿","triangleleft;":"◃","trianglelefteq;":"⊴","triangleq;":"≜","triangleright;":"▹","trianglerighteq;":"⊵","tridot;":"◬","trie;":"≜","triminus;":"⨺","triplus;":"⨹","trisb;":"⧍","tritime;":"⨻","trpezium;":"⏢","tscr;":"𝓉","tscy;":"ц","tshcy;":"ћ","tstrok;":"ŧ","twixt;":"≬","twoheadleftarrow;":"↞","twoheadrightarrow;":"↠","uArr;":"⇑","uHar;":"⥣","uacute":"ú","uacute;":"ú","uarr;":"↑","ubrcy;":"ў","ubreve;":"ŭ","ucirc":"û","ucirc;":"û","ucy;":"у","udarr;":"⇅","udblac;":"ű","udhar;":"⥮","ufisht;":"⥾","ufr;":"𝔲","ugrave":"ù","ugrave;":"ù","uharl;":"↿","uharr;":"↾","uhblk;":"▀","ulcorn;":"⌜","ulcorner;":"⌜","ulcrop;":"⌏","ultri;":"◸","umacr;":"ū","uml":"¨","uml;":"¨","uogon;":"ų","uopf;":"𝕦","uparrow;":"↑","updownarrow;":"↕","upharpoonleft;":"↿","upharpoonright;":"↾","uplus;":"⊎","upsi;":"υ","upsih;":"ϒ","upsilon;":"υ","upuparrows;":"⇈","urcorn;":"⌝","urcorner;":"⌝","urcrop;":"⌎","uring;":"ů","urtri;":"◹","uscr;":"𝓊","utdot;":"⋰","utilde;":"ũ","utri;":"▵","utrif;":"▴","uuarr;":"⇈","uuml":"ü","uuml;":"ü","uwangle;":"⦧","vArr;":"⇕","vBar;":"⫨","vBarv;":"⫩","vDash;":"⊨","vangrt;":"⦜","varepsilon;":"ϵ","varkappa;":"ϰ","varnothing;":"∅","varphi;":"ϕ","varpi;":"ϖ","varpropto;":"∝","varr;":"↕","varrho;":"ϱ","varsigma;":"ς","varsubsetneq;":"⊊︀","varsubsetneqq;":"⫋︀","varsupsetneq;":"⊋︀","varsupsetneqq;":"⫌︀","vartheta;":"ϑ","vartriangleleft;":"⊲","vartriangleright;":"⊳","vcy;":"в","vdash;":"⊢","vee;":"∨","veebar;":"⊻","veeeq;":"≚","vellip;":"⋮","verbar;":"|","vert;":"|","vfr;":"𝔳","vltri;":"⊲","vnsub;":"⊂⃒","vnsup;":"⊃⃒","vopf;":"𝕧","vprop;":"∝","vrtri;":"⊳","vscr;":"𝓋","vsubnE;":"⫋︀","vsubne;":"⊊︀","vsupnE;":"⫌︀","vsupne;":"⊋︀","vzigzag;":"⦚","wcirc;":"ŵ","wedbar;":"⩟","wedge;":"∧","wedgeq;":"≙","weierp;":"℘","wfr;":"𝔴","wopf;":"𝕨","wp;":"℘","wr;":"≀","wreath;":"≀","wscr;":"𝓌","xcap;":"⋂","xcirc;":"◯","xcup;":"⋃","xdtri;":"▽","xfr;":"𝔵","xhArr;":"⟺","xharr;":"⟷","xi;":"ξ","xlArr;":"⟸","xlarr;":"⟵","xmap;":"⟼","xnis;":"⋻","xodot;":"⨀","xopf;":"𝕩","xoplus;":"⨁","xotime;":"⨂","xrArr;":"⟹","xrarr;":"⟶","xscr;":"𝓍","xsqcup;":"⨆","xuplus;":"⨄","xutri;":"△","xvee;":"⋁","xwedge;":"⋀","yacute":"ý","yacute;":"ý","yacy;":"я","ycirc;":"ŷ","ycy;":"ы","yen":"¥","yen;":"¥","yfr;":"𝔶","yicy;":"ї","yopf;":"𝕪","yscr;":"𝓎","yucy;":"ю","yuml":"ÿ","yuml;":"ÿ","zacute;":"ź","zcaron;":"ž","zcy;":"з","zdot;":"ż","zeetrf;":"ℨ","zeta;":"ζ","zfr;":"𝔷","zhcy;":"ж","zigrarr;":"⇝","zopf;":"𝕫","zscr;":"𝓏","zwj;":"‍","zwnj;":"‌"})));
26// #endregion
27
28const STATE_DATA = 0;
29const STATE_TAG_OPEN = 1;
30const STATE_END_TAG_OPEN = 2;
31const STATE_TAG_NAME = 3;
32const STATE_BEFORE_ATTRIBUTE_NAME = 4;
33const STATE_ATTRIBUTE_NAME = 5;
34const STATE_AFTER_ATTRIBUTE_NAME = 6;
35const STATE_BEFORE_ATTRIBUTE_VALUE = 7;
36const STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED = 8;
37const STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED = 9;
38const STATE_ATTRIBUTE_VALUE_UNQUOTED = 10;
39const STATE_AFTER_ATTRIBUTE_VALUE_QUOTED = 11;
40const STATE_SELF_CLOSING_START_TAG = 12;
41
42const STATE_MARKUP_DECLARATION_OPEN = 13;
43const STATE_COMMENT_START = 14;
44const STATE_COMMENT_START_DASH = 15;
45const STATE_COMMENT = 16;
46const STATE_COMMENT_END_DASH = 17;
47const STATE_COMMENT_END = 18;
48const STATE_COMMENT_END_BANG = 19;
49const STATE_BOGUS_COMMENT = 20;
50
51const STATE_COMMENT_LESS_THAN_SIGN = 21;
52const STATE_COMMENT_LESS_THAN_SIGN_BANG = 22;
53const STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH = 23;
54const STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH = 24;
55
56const STATE_DOCTYPE = 25;
57const STATE_BEFORE_DOCTYPE_NAME = 26;
58const STATE_DOCTYPE_NAME = 27;
59const STATE_AFTER_DOCTYPE_NAME = 28;
60const STATE_AFTER_DOCTYPE_PUBLIC_KEYWORD = 29;
61const STATE_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER = 30;
62const STATE_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED = 31;
63const STATE_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED = 32;
64const STATE_AFTER_DOCTYPE_PUBLIC_IDENTIFIER = 33;
65const STATE_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS = 34;
66const STATE_AFTER_DOCTYPE_SYSTEM_KEYWORD = 35;
67const STATE_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER = 36;
68const STATE_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED = 37;
69const STATE_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED = 38;
70const STATE_AFTER_DOCTYPE_SYSTEM_IDENTIFIER = 39;
71const STATE_BOGUS_DOCTYPE = 40;
72
73const STATE_CDATA_SECTION = 41;
74const STATE_CDATA_SECTION_BRACKET = 42;
75const STATE_CDATA_SECTION_END = 43;
76
77const STATE_RCDATA = 44;
78const STATE_RCDATA_LESS_THAN_SIGN = 45;
79const STATE_RCDATA_END_TAG_OPEN = 46;
80const STATE_RCDATA_END_TAG_NAME = 47;
81
82const STATE_RAWTEXT = 48;
83const STATE_RAWTEXT_LESS_THAN_SIGN = 49;
84const STATE_RAWTEXT_END_TAG_OPEN = 50;
85const STATE_RAWTEXT_END_TAG_NAME = 51;
86
87const STATE_SCRIPT_DATA = 52;
88const STATE_SCRIPT_DATA_LESS_THAN_SIGN = 53;
89const STATE_SCRIPT_DATA_END_TAG_OPEN = 54;
90const STATE_SCRIPT_DATA_END_TAG_NAME = 55;
91const STATE_SCRIPT_DATA_ESCAPE_START = 56;
92const STATE_SCRIPT_DATA_ESCAPE_START_DASH = 57;
93const STATE_SCRIPT_DATA_ESCAPED = 58;
94const STATE_SCRIPT_DATA_ESCAPED_DASH = 59;
95const STATE_SCRIPT_DATA_ESCAPED_DASH_DASH = 60;
96const STATE_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN = 61;
97const STATE_SCRIPT_DATA_ESCAPED_END_TAG_OPEN = 62;
98const STATE_SCRIPT_DATA_ESCAPED_END_TAG_NAME = 63;
99const STATE_SCRIPT_DATA_DOUBLE_ESCAPE_START = 64;
100const STATE_SCRIPT_DATA_DOUBLE_ESCAPED = 65;
101const STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH = 66;
102const STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH = 67;
103const STATE_SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN = 68;
104const STATE_SCRIPT_DATA_DOUBLE_ESCAPE_END = 69;
105
106const STATE_PLAINTEXT = 70;
107
108// https://html.spec.whatwg.org/multipage/parsing.html#character-reference-state
109const STATE_CHARACTER_REFERENCE = 71;
110// https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
111const STATE_NAMED_CHARACTER_REFERENCE = 72;
112// https://html.spec.whatwg.org/multipage/parsing.html#ambiguous-ampersand-state
113const STATE_AMBIGUOUS_AMPERSAND = 73;
114// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-state
115const STATE_NUMERIC_CHARACTER_REFERENCE = 74;
116// https://html.spec.whatwg.org/multipage/parsing.html#hexadecimal-character-reference-start-state
117const STATE_HEXADECIMAL_CHARACTER_REFERENCE_START = 75;
118// https://html.spec.whatwg.org/multipage/parsing.html#decimal-character-reference-start-state
119const STATE_DECIMAL_CHARACTER_REFERENCE_START = 76;
120// https://html.spec.whatwg.org/multipage/parsing.html#hexadecimal-character-reference-state
121const STATE_HEXADECIMAL_CHARACTER_REFERENCE = 77;
122// https://html.spec.whatwg.org/multipage/parsing.html#decimal-character-reference-state
123const STATE_DECIMAL_CHARACTER_REFERENCE = 78;
124// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
125const STATE_NUMERIC_CHARACTER_REFERENCE_END = 79;
126
127const CC_TAB = 0x09;
128const CC_LF = 0x0a;
129const CC_FF = 0x0c;
130const CC_SPACE = 0x20;
131const CC_EXCLAMATION_MARK = 0x21;
132const CC_QUOTATION_MARK = 0x22;
133const CC_NUMBER_SIGN = 0x23;
134const CC_AMPERSAND = 0x26;
135const CC_APOSTROPHE = 0x27;
136const CC_HYPHEN_MINUS = 0x2d;
137const CC_SOLIDUS = 0x2f;
138const CC_SEMICOLON = 0x3b;
139const CC_LESS_THAN = 0x3c;
140const CC_EQUALS = 0x3d;
141const CC_GREATER_THAN = 0x3e;
142const CC_QUESTION_MARK = 0x3f;
143const CC_LEFT_SQUARE_BRACKET = 0x5b;
144const CC_RIGHT_SQUARE_BRACKET = 0x5d;
145
146const QUOTE_DOUBLE = 1;
147const QUOTE_SINGLE = 2;
148const QUOTE_NONE = 0;
149
150// Longest WHATWG named entity name *including* the trailing `;` is 32 chars
151// (`CounterClockwiseContourIntegral;`); without the trailing `;` it's 31.
152// Used to cap both the tokenizer's named-character-reference run length and
153// the decoder's longest-prefix backtrack so pathological inputs (e.g. `&`
154// followed by thousands of alphanumerics) stay linear-time.
155const MAX_ENTITY_NAME_LEN = 32;
156
157/**
158 * @param {number} cc character code
159 * @returns {boolean} is ascii alpha
160 */
161const isAsciiAlpha = (cc) =>
162 (cc >= 0x41 && cc <= 0x5a) || (cc >= 0x61 && cc <= 0x7a);
163
164/**
165 * @param {number} cc character code
166 * @returns {boolean} is ascii alphanumeric
167 */
168const isAsciiAlphanumeric = (cc) =>
169 isAsciiAlpha(cc) || (cc >= 0x30 && cc <= 0x39);
170
171/**
172 * @param {number} cc character code
173 * @returns {boolean} is ascii digit
174 */
175const isAsciiDigit = (cc) => cc >= 0x30 && cc <= 0x39;
176
177/**
178 * @param {number} cc character code
179 * @returns {boolean} is ascii hex digit
180 */
181const isAsciiHexDigit = (cc) =>
182 (cc >= 0x30 && cc <= 0x39) ||
183 (cc >= 0x41 && cc <= 0x46) ||
184 (cc >= 0x61 && cc <= 0x66);
185
186/**
187 * @param {number} cc character code
188 * @returns {boolean} is space
189 */
190const isSpace = (cc) =>
191 cc === CC_TAB || cc === CC_LF || cc === CC_FF || cc === CC_SPACE;
192
193/**
194 * Severity of a tokenizer-detected parse error. `"warning"` is recoverable
195 * (the tokenizer continued and the emitted token is still well-formed, e.g.
196 * missing-attribute-value); `"error"` means the emitted token's offset
197 * range is incomplete or does not match what the spec would produce, e.g.
198 * eof-in-tag.
199 *
200 * Token offsets are JS string indices (UTF-16 code-unit offsets into
201 * `input`), not byte offsets — relevant for inputs containing non-BMP
202 * code points where one code point spans two indices.
203 * @typedef {"warning" | "error"} ParseErrorSeverity
204 */
205
206/**
207 * @typedef {object} HtmlTokenCallbacks
208 * @property {(input: string, start: number, end: number, nameStart: number, nameEnd: number, selfClosing: boolean) => number=} openTag
209 * @property {(input: string, start: number, end: number, nameStart: number, nameEnd: number) => number=} closeTag
210 * @property {(input: string, start: number, end: number) => number=} text
211 * @property {(input: string, nameStart: number, nameEnd: number, valueStart: number, valueEnd: number, quoteType: number) => number=} attribute
212 * @property {(input: string, start: number, end: number) => number=} comment
213 * @property {(input: string, start: number, end: number) => number=} doctype
214 * @property {(input: string, code: string, start: number, end: number, severity: ParseErrorSeverity) => void=} parseError
215 */
216
217/**
218 * @param {string} input input string
219 * @param {number} pos current position
220 * @param {HtmlTokenCallbacks} callbacks callbacks
221 * @returns {number} final position
222 */
223const walkHtmlTokens = (input, pos = 0, callbacks = {}) => {
224 const len = input.length;
225 let state = STATE_DATA;
226 let returnState = STATE_DATA;
227
228 let textStart = pos;
229 let tagStart = pos;
230 let tagNameStart = -1;
231 let tagNameEnd = -1;
232 let attrNameStart = -1;
233 let attrNameEnd = -1;
234 let attrValueStart = -1;
235 let attrQuoteType = QUOTE_NONE;
236 let commentStart = pos;
237 let lastOpenTagName = "";
238 // Counter used by SCRIPT_DATA_DOUBLE_ESCAPE_{START,END} to detect whether
239 // the ASCII-alpha run after `<` / `</` spells exactly `"script"`. Values
240 // 0..6 = number of chars matched so far; 7 = no longer matches (sentinel).
241 // Avoids growing a buffer for pathological inputs with long alpha runs.
242 let scriptMatch = 0;
243 let namedEntityConsumed = 0;
244 // Tracks whether the current tag has parsed any attributes — used to
245 // fire the `end-tag-with-attributes` parse error when an end tag emits.
246 let tagHasAttributes = false;
247
248 /**
249 * Reports a tokenizer parse error to the consumer. The offset range and
250 * severity follow the WHATWG spec naming. Severity is `"error"` for
251 * cases where the emitted token is incomplete (EOF inside a tag or
252 * comment); everything else is a `"warning"`. Offsets are JS string
253 * indices (UTF-16 code-unit offsets into `input`).
254 * @param {string} code WHATWG parse-error code (kebab-case)
255 * @param {number} start string offset where the error starts
256 * @param {number} end string offset where the error ends
257 * @param {ParseErrorSeverity} severity error severity
258 */
259 const reportError = (code, start, end, severity) => {
260 if (callbacks.parseError !== undefined) {
261 callbacks.parseError(input, code, start, end, severity);
262 }
263 };
264
265 /**
266 * @param {number} cc character code
267 * @returns {boolean} is ascii lower alpha
268 */
269 const isAsciiLowerAlpha = (cc) => cc >= 0x61 && cc <= 0x7a;
270
271 /**
272 * @param {number} cc character code
273 * @returns {boolean} is ascii upper alpha
274 */
275 const isAsciiUpperAlpha = (cc) => cc >= 0x41 && cc <= 0x5a;
276
277 /**
278 * @param {string} name tag name (lowercase)
279 * @returns {number} content mode state for this tag, or STATE_DATA
280 */
281 const getContentModeForTag = (name) => {
282 switch (name) {
283 case "textarea":
284 case "title":
285 return STATE_RCDATA;
286 case "style":
287 case "xmp":
288 case "iframe":
289 case "noembed":
290 case "noframes":
291 return STATE_RAWTEXT;
292 case "script":
293 return STATE_SCRIPT_DATA;
294 case "plaintext":
295 return STATE_PLAINTEXT;
296 default:
297 return STATE_DATA;
298 }
299 };
300
301 /**
302 * @param {number} endPos end position
303 */
304 const flushText = (endPos) => {
305 if (textStart < endPos) {
306 if (callbacks.text !== undefined) {
307 callbacks.text(input, textStart, endPos);
308 }
309 // Advance `textStart` so a second `flushText` for the same span
310 // (e.g. from the EOF handler after a tag-open transition already
311 // flushed the pending text) is a no-op rather than a duplicate
312 // emit. emitOpenTag / emitCloseTag overwrite `textStart` with
313 // their own `nextPos` anyway, so this doesn't shift their start.
314 textStart = endPos;
315 }
316 };
317
318 /**
319 * @param {number} endPos end position
320 * @returns {number} next position
321 */
322 const emitAttribute = (endPos) => {
323 // Default `nextPos` advances past the closing quote (if any) so the
324 // state machine can continue when no `attribute` callback is provided.
325 // When a callback IS provided, its return value overrides the default —
326 // the callback is expected to do the same advance based on the
327 // reported `quoteType`.
328 let nextPos = attrQuoteType === QUOTE_NONE ? endPos : endPos + 1;
329 if (callbacks.attribute !== undefined && attrNameStart !== -1) {
330 nextPos = callbacks.attribute(
331 input,
332 attrNameStart,
333 attrNameEnd,
334 attrValueStart,
335 attrValueStart === -1 ? -1 : endPos,
336 attrQuoteType
337 );
338 }
339 if (attrNameStart !== -1) tagHasAttributes = true;
340 attrNameStart = -1;
341 attrValueStart = -1;
342 attrQuoteType = QUOTE_NONE;
343 return nextPos;
344 };
345
346 /**
347 * @param {number} endPos end position
348 * @param {boolean} selfClosing is self closing
349 * @returns {number} next position
350 */
351 const emitOpenTag = (endPos, selfClosing) => {
352 let nextPos = endPos;
353 if (callbacks.openTag !== undefined) {
354 nextPos = callbacks.openTag(
355 input,
356 tagStart,
357 endPos,
358 tagNameStart,
359 tagNameEnd,
360 selfClosing
361 );
362 }
363 if (!selfClosing) {
364 lastOpenTagName = input.slice(tagNameStart, tagNameEnd).toLowerCase();
365 }
366 tagHasAttributes = false;
367 textStart = nextPos;
368 return nextPos;
369 };
370
371 /**
372 * @param {number} endPos end position
373 * @returns {number} next position
374 */
375 const emitCloseTag = (endPos) => {
376 // Per WHATWG: an end tag emitted with attributes is a parse error.
377 if (tagHasAttributes) {
378 reportError("end-tag-with-attributes", tagStart, endPos, "warning");
379 }
380 let nextPos = endPos;
381 if (callbacks.closeTag !== undefined) {
382 nextPos = callbacks.closeTag(
383 input,
384 tagStart,
385 endPos,
386 tagNameStart,
387 tagNameEnd
388 );
389 }
390 tagHasAttributes = false;
391 textStart = nextPos;
392 return nextPos;
393 };
394
395 while (pos < len) {
396 const cc = input.charCodeAt(pos);
397
398 // TODO: We don't handle all states here yet. In the future we will need to handle
399 // all of them, and when we move all the tokenizer we will remove it.
400 switch (state) {
401 // https://html.spec.whatwg.org/multipage/parsing.html#data-state
402 case STATE_DATA:
403 // Consume the next input character:
404 // U+003C LESS-THAN SIGN (<)
405 // Set the return state to the data state. Switch to the tag open state.
406 if (cc === CC_LESS_THAN) {
407 tagStart = pos;
408 state = STATE_TAG_OPEN;
409 pos++;
410 } else if (cc === CC_AMPERSAND) {
411 // U+0026 AMPERSAND (&)
412 // Set the return state to the data state. Switch to the
413 // character reference state.
414 returnState = STATE_DATA;
415 state = STATE_CHARACTER_REFERENCE;
416 pos++;
417 } else {
418 pos++;
419 }
420 break;
421
422 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
423 case STATE_TAG_OPEN:
424 // Consume the next input character:
425 // U+002F SOLIDUS (/)
426 // Switch to the end tag open state.
427 if (cc === CC_SOLIDUS) {
428 state = STATE_END_TAG_OPEN;
429 pos++;
430 } else if (cc === CC_EXCLAMATION_MARK) {
431 // U+0021 EXCLAMATION MARK (!)
432 // Switch to the markup declaration open state.
433 flushText(tagStart);
434 commentStart = tagStart;
435 state = STATE_MARKUP_DECLARATION_OPEN;
436 pos++;
437 } else if (isAsciiAlpha(cc)) {
438 // ASCII alpha
439 // Create a new start tag token, set its tag name to the empty string.
440 // Reconsume in the tag name state.
441 flushText(tagStart);
442 tagNameStart = pos;
443 state = STATE_TAG_NAME;
444 // Reconsume
445 } else if (cc === CC_QUESTION_MARK) {
446 // U+003F QUESTION MARK (?)
447 // This is an unexpected-question-mark-instead-of-tag-name parse error.
448 // Create a comment token whose data is the empty string. Reconsume in the
449 // bogus comment state.
450 reportError(
451 "unexpected-question-mark-instead-of-tag-name",
452 pos,
453 pos + 1,
454 "warning"
455 );
456 flushText(tagStart);
457 commentStart = tagStart;
458 state = STATE_BOGUS_COMMENT;
459 // Reconsume — let the bogus-comment state consume the `?`
460 // itself, matching the spec.
461 } else {
462 // Anything else
463 // This is an invalid-first-character-of-tag-name parse error. Emit a U+003C
464 // LESS-THAN SIGN character token. Reconsume in the data state.
465 reportError(
466 "invalid-first-character-of-tag-name",
467 pos,
468 pos + 1,
469 "warning"
470 );
471 state = STATE_DATA;
472 // Reconsume
473 }
474 break;
475
476 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state
477 case STATE_END_TAG_OPEN:
478 // Consume the next input character:
479 // ASCII alpha
480 // Create a new end tag token, set its tag name to the empty string.
481 // Reconsume in the tag name state.
482 if (isAsciiAlpha(cc)) {
483 flushText(tagStart);
484 tagNameStart = pos;
485 state = STATE_TAG_NAME;
486 // Reconsume
487 } else if (cc === CC_GREATER_THAN) {
488 // U+003E GREATER-THAN SIGN (>)
489 // This is a missing-end-tag-name parse error. Switch to the data state.
490 reportError("missing-end-tag-name", pos, pos + 1, "warning");
491 state = STATE_DATA;
492 pos++;
493 } else {
494 // Anything else
495 // This is an invalid-first-character-of-tag-name parse error. Create a
496 // comment token whose data is the empty string. Reconsume in the bogus
497 // comment state.
498 reportError(
499 "invalid-first-character-of-tag-name",
500 pos,
501 pos + 1,
502 "warning"
503 );
504 flushText(tagStart);
505 commentStart = tagStart;
506 state = STATE_BOGUS_COMMENT;
507 // Reconsume — let bogus-comment consume this char itself.
508 }
509 break;
510
511 // https://html.spec.whatwg.org/multipage/parsing.html#tag-name-state
512 case STATE_TAG_NAME:
513 // Consume the next input character:
514 // U+0009 CHARACTER TABULATION (tab)
515 // U+000A LINE FEED (LF)
516 // U+000C FORM FEED (FF)
517 // U+0020 SPACE
518 // Switch to the before attribute name state.
519 if (isSpace(cc)) {
520 tagNameEnd = pos;
521 state = STATE_BEFORE_ATTRIBUTE_NAME;
522 pos++;
523 } else if (cc === CC_SOLIDUS) {
524 // U+002F SOLIDUS (/)
525 // Switch to the self-closing start tag state.
526 tagNameEnd = pos;
527 state = STATE_SELF_CLOSING_START_TAG;
528 pos++;
529 } else if (cc === CC_GREATER_THAN) {
530 // U+003E GREATER-THAN SIGN (>)
531 // Switch to the data state. Emit the current tag token.
532 tagNameEnd = pos;
533 if (input.charCodeAt(tagStart + 1) === CC_SOLIDUS) {
534 state = STATE_DATA;
535 pos = emitCloseTag(pos + 1);
536 } else {
537 const nextPos = emitOpenTag(pos + 1, false);
538 state =
539 nextPos > pos + 1
540 ? STATE_DATA
541 : getContentModeForTag(lastOpenTagName);
542 pos = nextPos;
543 }
544 } else {
545 pos++;
546 }
547 break;
548
549 // https://html.spec.whatwg.org/multipage/parsing.html#before-attribute-name-state
550 case STATE_BEFORE_ATTRIBUTE_NAME:
551 // Consume the next input character:
552 // U+0009 CHARACTER TABULATION (tab)
553 // U+000A LINE FEED (LF)
554 // U+000C FORM FEED (FF)
555 // U+0020 SPACE
556 // Ignore the character.
557 // Reconsume so space is handled in BEFORE_ATTRIBUTE_NAME
558 if (isSpace(cc)) {
559 pos++;
560 } else if (cc === CC_SOLIDUS || cc === CC_GREATER_THAN) {
561 // U+002F SOLIDUS (/)
562 // U+003E GREATER-THAN SIGN (>)
563 // EOF
564 // Reconsume in the after attribute name state.
565 state = STATE_AFTER_ATTRIBUTE_NAME;
566 // Reconsume
567 } else if (cc === CC_EQUALS) {
568 // U+003D EQUALS SIGN (=)
569 // This is an unexpected-equals-sign-before-attribute-name parse
570 // error. Start a new attribute. Switch to the attribute name state.
571 reportError(
572 "unexpected-equals-sign-before-attribute-name",
573 pos,
574 pos + 1,
575 "warning"
576 );
577 attrNameStart = pos;
578 state = STATE_ATTRIBUTE_NAME;
579 pos++;
580 } else {
581 // Anything else
582 // Start a new attribute in the current tag token. Set that attribute name
583 // and value to the empty string. Reconsume in the attribute name state.
584 attrNameStart = pos;
585 state = STATE_ATTRIBUTE_NAME;
586 // Reconsume
587 }
588 break;
589
590 // https://html.spec.whatwg.org/multipage/parsing.html#attribute-name-state
591 case STATE_ATTRIBUTE_NAME:
592 // Consume the next input character:
593 // U+0009 CHARACTER TABULATION (tab)
594 // U+000A LINE FEED (LF)
595 // U+000C FORM FEED (FF)
596 // U+0020 SPACE
597 // U+002F SOLIDUS (/)
598 // U+003E GREATER-THAN SIGN (>)
599 // EOF
600 // Reconsume in the after attribute name state.
601 if (isSpace(cc) || cc === CC_SOLIDUS || cc === CC_GREATER_THAN) {
602 attrNameEnd = pos;
603 state = STATE_AFTER_ATTRIBUTE_NAME;
604 // Reconsume
605 } else if (cc === CC_EQUALS) {
606 attrNameEnd = pos;
607 state = STATE_BEFORE_ATTRIBUTE_VALUE;
608 pos++;
609 } else {
610 pos++;
611 }
612 break;
613
614 // https://html.spec.whatwg.org/multipage/parsing.html#after-attribute-name-state
615 case STATE_AFTER_ATTRIBUTE_NAME:
616 // Consume the next input character:
617 // U+0009 CHARACTER TABULATION (tab)
618 // U+000A LINE FEED (LF)
619 // U+000C FORM FEED (FF)
620 // U+0020 SPACE
621 // Ignore the character.
622 if (isSpace(cc)) {
623 pos++;
624 } else if (cc === CC_SOLIDUS) {
625 // U+002F SOLIDUS (/)
626 // Switch to the self-closing start tag state.
627 emitAttribute(pos);
628 state = STATE_SELF_CLOSING_START_TAG;
629 pos++;
630 } else if (cc === CC_EQUALS) {
631 // U+003D EQUALS SIGN (=)
632 // Switch to the before attribute value state.
633 state = STATE_BEFORE_ATTRIBUTE_VALUE;
634 pos++;
635 } else if (cc === CC_GREATER_THAN) {
636 // U+003E GREATER-THAN SIGN (>)
637 // Switch to the data state. Emit the current tag token.
638 emitAttribute(pos);
639 if (input.charCodeAt(tagStart + 1) === CC_SOLIDUS) {
640 state = STATE_DATA;
641 pos = emitCloseTag(pos + 1);
642 } else {
643 const nextPos = emitOpenTag(pos + 1, false);
644 state =
645 nextPos > pos + 1
646 ? STATE_DATA
647 : getContentModeForTag(lastOpenTagName);
648 pos = nextPos;
649 }
650 } else {
651 // Anything else
652 // Start a new attribute in the current tag token.
653 emitAttribute(pos);
654 attrNameStart = pos;
655 state = STATE_ATTRIBUTE_NAME;
656 // Reconsume
657 }
658 break;
659
660 // https://html.spec.whatwg.org/multipage/parsing.html#before-attribute-value-state
661 case STATE_BEFORE_ATTRIBUTE_VALUE:
662 // Consume the next input character:
663 // U+0009 CHARACTER TABULATION (tab)
664 // U+000A LINE FEED (LF)
665 // U+000C FORM FEED (FF)
666 // U+0020 SPACE
667 // Ignore the character.
668 if (isSpace(cc)) {
669 pos++;
670 } else if (cc === CC_QUOTATION_MARK) {
671 // U+0022 QUOTATION MARK (")
672 // Switch to the attribute value (double-quoted) state.
673 attrValueStart = pos + 1;
674 attrQuoteType = QUOTE_DOUBLE;
675 state = STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
676 pos++;
677 } else if (cc === CC_APOSTROPHE) {
678 // U+0027 APOSTROPHE (')
679 // Switch to the attribute value (single-quoted) state.
680 attrValueStart = pos + 1;
681 attrQuoteType = QUOTE_SINGLE;
682 state = STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED;
683 pos++;
684 } else if (cc === CC_GREATER_THAN) {
685 // U+003E GREATER-THAN SIGN (>)
686 // This is a missing-attribute-value parse error. Switch to the data
687 // state. Emit the current tag token. The attribute is reported with
688 // an empty value range pointing at the `>` so the open-tag offset range
689 // still includes the `>`.
690 reportError("missing-attribute-value", pos, pos + 1, "warning");
691 attrValueStart = pos;
692 attrQuoteType = QUOTE_NONE;
693 pos = emitAttribute(pos);
694 if (input.charCodeAt(tagStart + 1) === CC_SOLIDUS) {
695 state = STATE_DATA;
696 pos = emitCloseTag(pos + 1);
697 } else {
698 const nextPos = emitOpenTag(pos + 1, false);
699 state =
700 nextPos > pos + 1
701 ? STATE_DATA
702 : getContentModeForTag(lastOpenTagName);
703 pos = nextPos;
704 }
705 } else {
706 // Anything else
707 // Reconsume in the attribute value (unquoted) state.
708 attrValueStart = pos;
709 attrQuoteType = QUOTE_NONE;
710 state = STATE_ATTRIBUTE_VALUE_UNQUOTED;
711 // Reconsume
712 }
713 break;
714
715 // https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-(double-quoted)-state
716 case STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
717 // Consume the next input character:
718 // U+0022 QUOTATION MARK (")
719 // Switch to the after attribute value (quoted) state.
720 if (cc === CC_QUOTATION_MARK) {
721 pos = emitAttribute(pos);
722 state = STATE_AFTER_ATTRIBUTE_VALUE_QUOTED;
723 } else if (cc === CC_AMPERSAND) {
724 // U+0026 AMPERSAND (&)
725 // Set the return state to the attribute value (double-quoted)
726 // state. Switch to the character reference state.
727 returnState = STATE_ATTRIBUTE_VALUE_DOUBLE_QUOTED;
728 state = STATE_CHARACTER_REFERENCE;
729 pos++;
730 } else {
731 pos++;
732 }
733 break;
734
735 // https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-(single-quoted)-state
736 case STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED:
737 // Consume the next input character:
738 // U+0027 APOSTROPHE (')
739 // Switch to the after attribute value (quoted) state.
740 if (cc === CC_APOSTROPHE) {
741 pos = emitAttribute(pos);
742 state = STATE_AFTER_ATTRIBUTE_VALUE_QUOTED;
743 } else if (cc === CC_AMPERSAND) {
744 // U+0026 AMPERSAND (&)
745 // Set the return state to the attribute value (single-quoted)
746 // state. Switch to the character reference state.
747 returnState = STATE_ATTRIBUTE_VALUE_SINGLE_QUOTED;
748 state = STATE_CHARACTER_REFERENCE;
749 pos++;
750 } else {
751 pos++;
752 }
753 break;
754
755 // https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-(unquoted)-state
756 case STATE_ATTRIBUTE_VALUE_UNQUOTED:
757 if (isSpace(cc)) {
758 pos = emitAttribute(pos);
759 state = STATE_BEFORE_ATTRIBUTE_NAME;
760 // Reconsume so space is handled in BEFORE_ATTRIBUTE_NAME
761 } else if (cc === CC_GREATER_THAN) {
762 // U+003E GREATER-THAN SIGN (>)
763 // This is a missing-attribute-value parse error. Switch to the data state.
764 // Emit the current tag token.
765 pos = emitAttribute(pos);
766 if (input.charCodeAt(tagStart + 1) === CC_SOLIDUS) {
767 state = STATE_DATA;
768 pos = emitCloseTag(pos + 1);
769 } else {
770 const nextPos = emitOpenTag(pos + 1, false);
771 state =
772 nextPos > pos + 1
773 ? STATE_DATA
774 : getContentModeForTag(lastOpenTagName);
775 pos = nextPos;
776 }
777 } else if (cc === CC_AMPERSAND) {
778 // U+0026 AMPERSAND (&)
779 // Set the return state to the attribute value (unquoted)
780 // state. Switch to the character reference state.
781 returnState = STATE_ATTRIBUTE_VALUE_UNQUOTED;
782 state = STATE_CHARACTER_REFERENCE;
783 pos++;
784 } else {
785 pos++;
786 }
787 break;
788
789 // https://html.spec.whatwg.org/multipage/parsing.html#after-attribute-value-(quoted)-state
790 case STATE_AFTER_ATTRIBUTE_VALUE_QUOTED:
791 // Consume the next input character:
792 // U+0009 CHARACTER TABULATION (tab)
793 // U+000A LINE FEED (LF)
794 // U+000C FORM FEED (FF)
795 // U+0020 SPACE
796 // Switch to the before attribute name state.
797 if (isSpace(cc)) {
798 state = STATE_BEFORE_ATTRIBUTE_NAME;
799 pos++;
800 } else if (cc === CC_SOLIDUS) {
801 // U+002F SOLIDUS (/)
802 // Switch to the self-closing start tag state.
803 state = STATE_SELF_CLOSING_START_TAG;
804 pos++;
805 } else if (cc === CC_GREATER_THAN) {
806 if (input.charCodeAt(tagStart + 1) === CC_SOLIDUS) {
807 state = STATE_DATA;
808 pos = emitCloseTag(pos + 1);
809 } else {
810 const nextPos = emitOpenTag(pos + 1, false);
811 state =
812 nextPos > pos + 1
813 ? STATE_DATA
814 : getContentModeForTag(lastOpenTagName);
815 pos = nextPos;
816 }
817 } else {
818 // Anything else
819 // This is a missing-whitespace-between-attributes parse error. Reconsume in
820 // the before attribute name state.
821 reportError(
822 "missing-whitespace-between-attributes",
823 pos,
824 pos + 1,
825 "warning"
826 );
827 state = STATE_BEFORE_ATTRIBUTE_NAME;
828 // Reconsume
829 }
830 break;
831
832 // https://html.spec.whatwg.org/multipage/parsing.html#self-closing-start-tag-state
833 case STATE_SELF_CLOSING_START_TAG:
834 // Consume the next input character:
835 // U+003E GREATER-THAN SIGN (>)
836 // Set the self-closing flag of the current tag token. Switch to the data
837 // state. Emit the current tag token.
838 if (cc === CC_GREATER_THAN) {
839 if (input.charCodeAt(tagStart + 1) === CC_SOLIDUS) {
840 state = STATE_DATA;
841 pos = emitCloseTag(pos + 1);
842 } else {
843 pos = emitOpenTag(pos + 1, true);
844 state = STATE_DATA;
845 }
846 } else {
847 // Anything else
848 // This is an unexpected-solidus-in-tag parse error. Reconsume in the before
849 // attribute name state.
850 reportError("unexpected-solidus-in-tag", pos, pos + 1, "warning");
851 state = STATE_BEFORE_ATTRIBUTE_NAME;
852 // Reconsume
853 }
854 break;
855
856 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state
857 case STATE_MARKUP_DECLARATION_OPEN:
858 // If the next few characters are:
859 // Two U+002D HYPHEN-MINUS characters (-)
860 // Consume those two characters, create a comment token whose data
861 // is the empty string, and switch to the comment start state.
862 if (
863 cc === CC_HYPHEN_MINUS &&
864 input.charCodeAt(pos + 1) === CC_HYPHEN_MINUS
865 ) {
866 pos += 2;
867 commentStart = tagStart;
868 state = STATE_COMMENT_START;
869 } else if (
870 // ASCII case-insensitive match for the word "DOCTYPE"
871 // Consume those characters and switch to the DOCTYPE state.
872 (cc === 0x44 || cc === 0x64) /* D or d */ &&
873 (input.charCodeAt(pos + 1) | 0x20) === 0x6f /* o */ &&
874 (input.charCodeAt(pos + 2) | 0x20) === 0x63 /* c */ &&
875 (input.charCodeAt(pos + 3) | 0x20) === 0x74 /* t */ &&
876 (input.charCodeAt(pos + 4) | 0x20) === 0x79 /* y */ &&
877 (input.charCodeAt(pos + 5) | 0x20) === 0x70 /* p */ &&
878 (input.charCodeAt(pos + 6) | 0x20) === 0x65 /* e */
879 ) {
880 pos += 7;
881 commentStart = tagStart;
882 state = STATE_DOCTYPE;
883 } else if (
884 // The string "[CDATA[" (the five uppercase letters "CDATA" with a
885 // U+005B LEFT SQUARE BRACKET character before and after)
886 // Consume those characters and switch to the CDATA section state.
887 cc === CC_LEFT_SQUARE_BRACKET &&
888 input.charCodeAt(pos + 1) === 0x43 /* C */ &&
889 input.charCodeAt(pos + 2) === 0x44 /* D */ &&
890 input.charCodeAt(pos + 3) === 0x41 /* A */ &&
891 input.charCodeAt(pos + 4) === 0x54 /* T */ &&
892 input.charCodeAt(pos + 5) === 0x41 /* A */ &&
893 input.charCodeAt(pos + 6) === CC_LEFT_SQUARE_BRACKET
894 ) {
895 pos += 7;
896 commentStart = tagStart;
897 state = STATE_CDATA_SECTION;
898 } else {
899 // Anything else
900 // This is an incorrectly-opened-comment parse error. Create a comment token
901 // whose data is the empty string. Switch to the bogus comment state (don't
902 // consume anything in the current state).
903 reportError("incorrectly-opened-comment", tagStart, pos, "warning");
904 commentStart = tagStart;
905 state = STATE_BOGUS_COMMENT;
906 // Reconsume
907 }
908 break;
909
910 // https://html.spec.whatwg.org/multipage/parsing.html#comment-start-state
911 case STATE_COMMENT_START:
912 // Consume the next input character:
913 // U+002D HYPHEN-MINUS (-)
914 // Switch to the comment start dash state.
915 if (cc === CC_HYPHEN_MINUS) {
916 state = STATE_COMMENT_START_DASH;
917 pos++;
918 } else if (cc === CC_GREATER_THAN) {
919 // U+003E GREATER-THAN SIGN (>)
920 // This is an abrupt-closing-of-empty-comment parse error. Switch to the
921 // data state. Emit the current comment token.
922 reportError(
923 "abrupt-closing-of-empty-comment",
924 pos,
925 pos + 1,
926 "warning"
927 );
928 let nextPos = pos + 1;
929 if (callbacks.comment !== undefined) {
930 nextPos = callbacks.comment(input, commentStart, pos + 1);
931 }
932 state = STATE_DATA;
933 textStart = nextPos;
934 pos = nextPos;
935 } else {
936 // Anything else
937 // Reconsume in the comment state.
938 state = STATE_COMMENT;
939 // Reconsume
940 }
941 break;
942
943 // https://html.spec.whatwg.org/multipage/parsing.html#comment-start-dash-state
944 case STATE_COMMENT_START_DASH:
945 // Consume the next input character:
946 // U+002D HYPHEN-MINUS (-)
947 // Switch to the comment end state.
948 if (cc === CC_HYPHEN_MINUS) {
949 state = STATE_COMMENT_END;
950 pos++;
951 } else if (cc === CC_GREATER_THAN) {
952 // U+003E GREATER-THAN SIGN (>)
953 // This is an abrupt-closing-of-empty-comment parse error. Switch to the
954 // data state. Emit the current comment token.
955 reportError(
956 "abrupt-closing-of-empty-comment",
957 pos,
958 pos + 1,
959 "warning"
960 );
961 let nextPos = pos + 1;
962 if (callbacks.comment !== undefined) {
963 nextPos = callbacks.comment(input, commentStart, pos + 1);
964 }
965 state = STATE_DATA;
966 textStart = nextPos;
967 pos = nextPos;
968 } else {
969 // Anything else
970 // Append a U+002D HYPHEN-MINUS character (-) to the comment token's data.
971 // Reconsume in the comment state.
972 state = STATE_COMMENT;
973 // Reconsume
974 }
975 break;
976
977 // https://html.spec.whatwg.org/multipage/parsing.html#comment-state
978 case STATE_COMMENT:
979 // Consume the next input character:
980 // U+003C LESS-THAN SIGN (<)
981 // Append a U+003C LESS-THAN SIGN character to the comment token's data. Switch to the comment less-than sign state.
982 if (cc === CC_LESS_THAN) {
983 state = STATE_COMMENT_LESS_THAN_SIGN;
984 pos++;
985 } else if (cc === CC_HYPHEN_MINUS) {
986 // Consume the next input character:
987 // U+002D HYPHEN-MINUS (-)
988 // Switch to the comment end dash state.
989 state = STATE_COMMENT_END_DASH;
990 pos++;
991 } else {
992 pos++;
993 }
994 break;
995
996 // https://html.spec.whatwg.org/multipage/parsing.html#comment-end-dash-state
997 case STATE_COMMENT_END_DASH:
998 // Consume the next input character:
999 // U+002D HYPHEN-MINUS (-)
1000 // Switch to the comment end state.
1001 if (cc === CC_HYPHEN_MINUS) {
1002 state = STATE_COMMENT_END;
1003 pos++;
1004 } else {
1005 // Anything else
1006 // Append a U+002D HYPHEN-MINUS character (-) to the comment token's data.
1007 // Reconsume in the comment state.
1008 state = STATE_COMMENT;
1009 pos++;
1010 }
1011 break;
1012
1013 // https://html.spec.whatwg.org/multipage/parsing.html#comment-end-state
1014 case STATE_COMMENT_END:
1015 // Consume the next input character:
1016 // U+003E GREATER-THAN SIGN (>)
1017 // Switch to the data state. Emit the current comment token.
1018 if (cc === CC_GREATER_THAN) {
1019 let nextPos = pos + 1;
1020 if (callbacks.comment !== undefined) {
1021 nextPos = callbacks.comment(input, commentStart, pos + 1);
1022 }
1023 state = STATE_DATA;
1024 textStart = nextPos;
1025 pos = nextPos;
1026 } else if (cc === CC_EXCLAMATION_MARK) {
1027 // U+0021 EXCLAMATION MARK (!)
1028 // Switch to the comment end bang state.
1029 state = STATE_COMMENT_END_BANG;
1030 pos++;
1031 } else if (cc === CC_HYPHEN_MINUS) {
1032 pos++;
1033 } else {
1034 // Anything else
1035 // Append two U+002D HYPHEN-MINUS characters (-) to the comment token's
1036 // data. Reconsume in the comment state.
1037 state = STATE_COMMENT;
1038 pos++;
1039 }
1040 break;
1041
1042 // https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state
1043 case STATE_COMMENT_END_BANG:
1044 // Consume the next input character:
1045 // U+002D HYPHEN-MINUS (-)
1046 // Append two U+002D HYPHEN-MINUS characters (-) and a U+0021 EXCLAMATION
1047 // MARK character (!) to the comment token's data. Switch to the comment end
1048 // dash state.
1049 if (cc === CC_HYPHEN_MINUS) {
1050 state = STATE_COMMENT_END_DASH;
1051 pos++;
1052 } else if (cc === CC_GREATER_THAN) {
1053 // U+003E GREATER-THAN SIGN (>)
1054 // This is an incorrectly-closed-comment parse error. Switch to the data
1055 // state. Emit the current comment token.
1056 reportError("incorrectly-closed-comment", pos, pos + 1, "warning");
1057 let nextPos = pos + 1;
1058 if (callbacks.comment !== undefined) {
1059 nextPos = callbacks.comment(input, commentStart, pos + 1);
1060 }
1061 state = STATE_DATA;
1062 textStart = nextPos;
1063 pos = nextPos;
1064 } else {
1065 // Anything else
1066 // Append two U+002D HYPHEN-MINUS characters (-) and a U+0021 EXCLAMATION
1067 // MARK character (!) to the comment token's data. Reconsume in the comment
1068 // state.
1069 state = STATE_COMMENT;
1070 pos++;
1071 }
1072 break;
1073
1074 // https://html.spec.whatwg.org/multipage/parsing.html#bogus-comment-state
1075 case STATE_BOGUS_COMMENT:
1076 // Consume the next input character:
1077 // U+003E GREATER-THAN SIGN (>)
1078 // Switch to the data state. Emit the current comment token.
1079 if (cc === CC_GREATER_THAN) {
1080 let nextPos = pos + 1;
1081 if (callbacks.comment !== undefined) {
1082 nextPos = callbacks.comment(input, commentStart, pos + 1);
1083 }
1084 state = STATE_DATA;
1085 textStart = nextPos;
1086 pos = nextPos;
1087 } else {
1088 pos++;
1089 }
1090 break;
1091
1092 // https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-state
1093 case STATE_COMMENT_LESS_THAN_SIGN:
1094 // Consume the next input character:
1095 // U+0021 EXCLAMATION MARK (!)
1096 // Append the current input character to the comment token's data. Switch to
1097 // the comment less-than sign bang state.
1098 if (cc === CC_EXCLAMATION_MARK) {
1099 state = STATE_COMMENT_LESS_THAN_SIGN_BANG;
1100 pos++;
1101 } else if (cc === CC_LESS_THAN) {
1102 // U+003C LESS-THAN SIGN (<)
1103 // Append the current input character to the comment token's data.
1104 pos++;
1105 } else {
1106 // Anything else
1107 // Reconsume in the comment state.
1108 state = STATE_COMMENT;
1109 // Reconsume
1110 }
1111 break;
1112
1113 // https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-bang-state
1114 case STATE_COMMENT_LESS_THAN_SIGN_BANG:
1115 // Consume the next input character:
1116 // U+002D HYPHEN-MINUS (-)
1117 // Switch to the comment less-than sign bang dash state.
1118 if (cc === CC_HYPHEN_MINUS) {
1119 state = STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH;
1120 pos++;
1121 } else {
1122 // Anything else
1123 // Reconsume in the comment state.
1124 state = STATE_COMMENT;
1125 // Reconsume
1126 }
1127 break;
1128
1129 // https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-bang-dash-state
1130 case STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH:
1131 // Consume the next input character:
1132 // U+002D HYPHEN-MINUS (-)
1133 // Switch to the comment less-than sign bang dash dash state.
1134 if (cc === CC_HYPHEN_MINUS) {
1135 state = STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH;
1136 pos++;
1137 } else {
1138 // Anything else
1139 // Reconsume in the comment end dash state.
1140 state = STATE_COMMENT_END_DASH;
1141 // Reconsume
1142 }
1143 break;
1144
1145 // https://html.spec.whatwg.org/multipage/parsing.html#comment-less-than-sign-bang-dash-dash-state
1146 case STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH:
1147 // Consume the next input character:
1148 // U+003E GREATER-THAN SIGN (>)
1149 // EOF
1150 // Reconsume in the comment end state.
1151 // Anything else
1152 // This is a nested-comment parse error. Reconsume in the comment end state.
1153 if (cc !== CC_GREATER_THAN) {
1154 reportError("nested-comment", pos, pos + 1, "warning");
1155 }
1156 state = STATE_COMMENT_END;
1157 // Reconsume
1158 break;
1159
1160 // https://html.spec.whatwg.org/multipage/parsing.html#doctype-state
1161 case STATE_DOCTYPE:
1162 // Consume the next input character:
1163 // U+0009 CHARACTER TABULATION (tab)
1164 // U+000A LINE FEED (LF)
1165 // U+000C FORM FEED (FF)
1166 // U+0020 SPACE
1167 // Switch to the before DOCTYPE name state.
1168 if (isSpace(cc)) {
1169 state = STATE_BEFORE_DOCTYPE_NAME;
1170 pos++;
1171 } else if (cc === CC_GREATER_THAN) {
1172 // U+003E GREATER-THAN SIGN (>)
1173 // Reconsume in the before DOCTYPE name state.
1174 state = STATE_BEFORE_DOCTYPE_NAME;
1175 } else {
1176 // Anything else
1177 // This is a missing-whitespace-before-doctype-name parse error. Reconsume
1178 // in the before DOCTYPE name state.
1179 reportError(
1180 "missing-whitespace-before-doctype-name",
1181 pos,
1182 pos + 1,
1183 "warning"
1184 );
1185 state = STATE_BEFORE_DOCTYPE_NAME;
1186 }
1187 break;
1188
1189 // https://html.spec.whatwg.org/multipage/parsing.html#before-doctype-name-state
1190 case STATE_BEFORE_DOCTYPE_NAME:
1191 // Consume the next input character:
1192 // U+0009 CHARACTER TABULATION (tab)
1193 // U+000A LINE FEED (LF)
1194 // U+000C FORM FEED (FF)
1195 // U+0020 SPACE
1196 // Ignore the character.
1197 if (isSpace(cc)) {
1198 pos++;
1199 } else if (cc === 0x00) {
1200 // U+0000 NULL
1201 // This is an unexpected-null-character parse error. Create a new DOCTYPE
1202 // token. Set the token's name to a U+FFFD REPLACEMENT CHARACTER character.
1203 // Switch to the DOCTYPE name state.
1204 state = STATE_DOCTYPE_NAME;
1205 pos++;
1206 } else if (cc === CC_GREATER_THAN) {
1207 // U+003E GREATER-THAN SIGN (>)
1208 // This is a missing-doctype-name parse error. Create a new DOCTYPE token.
1209 // Set its force-quirks flag to on. Switch to the data state. Emit the
1210 // current token.
1211 reportError("missing-doctype-name", pos, pos + 1, "warning");
1212 let nextPos = pos + 1;
1213 if (callbacks.doctype !== undefined) {
1214 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1215 }
1216 state = STATE_DATA;
1217 textStart = nextPos;
1218 pos = nextPos;
1219 } else {
1220 // ASCII upper alpha
1221 // Create a new DOCTYPE token. Set the token's name to the lowercase version
1222 // of the current input character (add 0x0020 to the character's code
1223 // point). Switch to the DOCTYPE name state.
1224 // Anything else
1225 // Create a new DOCTYPE token. Set the token's name to the current input
1226 // character. Switch to the DOCTYPE name state.
1227 state = STATE_DOCTYPE_NAME;
1228 pos++;
1229 }
1230 break;
1231
1232 // https://html.spec.whatwg.org/multipage/parsing.html#doctype-name-state
1233 case STATE_DOCTYPE_NAME:
1234 // Consume the next input character:
1235 // U+0009 CHARACTER TABULATION (tab)
1236 // U+000A LINE FEED (LF)
1237 // U+000C FORM FEED (FF)
1238 // U+0020 SPACE
1239 // Switch to the after DOCTYPE name state.
1240 if (isSpace(cc)) {
1241 state = STATE_AFTER_DOCTYPE_NAME;
1242 pos++;
1243 } else if (cc === CC_GREATER_THAN) {
1244 // U+003E GREATER-THAN SIGN (>)
1245 // Switch to the data state. Emit the current DOCTYPE token.
1246 let nextPos = pos + 1;
1247 if (callbacks.doctype !== undefined) {
1248 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1249 }
1250 state = STATE_DATA;
1251 textStart = nextPos;
1252 pos = nextPos;
1253 } else if (cc === 0x00) {
1254 // U+0000 NULL
1255 // This is an unexpected-null-character parse error. Append a U+FFFD
1256 // REPLACEMENT CHARACTER character to the current DOCTYPE token's name.
1257 pos++;
1258 } else {
1259 // ASCII upper alpha
1260 // Append the lowercase version of the current input character (add 0x0020
1261 // to the character's code point) to the current DOCTYPE token's name.
1262 // Anything else
1263 // Append the current input character to the current DOCTYPE token's name.
1264 pos++;
1265 }
1266 break;
1267
1268 // https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-name-state
1269 case STATE_AFTER_DOCTYPE_NAME:
1270 // Consume the next input character:
1271 if (isSpace(cc)) {
1272 // U+0009 CHARACTER TABULATION (tab)
1273 // U+000A LINE FEED (LF)
1274 // U+000C FORM FEED (FF)
1275 // U+0020 SPACE
1276 // Ignore the character.
1277 pos++;
1278 } else if (cc === CC_GREATER_THAN) {
1279 // U+003E GREATER-THAN SIGN (>)
1280 // Switch to the data state. Emit the current DOCTYPE token.
1281 let nextPos = pos + 1;
1282 if (callbacks.doctype !== undefined) {
1283 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1284 }
1285 state = STATE_DATA;
1286 textStart = nextPos;
1287 pos = nextPos;
1288 } else if (
1289 pos + 5 < len &&
1290 (cc === 0x50 || cc === 0x70) /* P or p */ &&
1291 (input.charCodeAt(pos + 1) | 0x20) === 0x75 /* u */ &&
1292 (input.charCodeAt(pos + 2) | 0x20) === 0x62 /* b */ &&
1293 (input.charCodeAt(pos + 3) | 0x20) === 0x6c /* l */ &&
1294 (input.charCodeAt(pos + 4) | 0x20) === 0x69 /* i */ &&
1295 (input.charCodeAt(pos + 5) | 0x20) === 0x63 /* c */
1296 ) {
1297 // ASCII case-insensitive match for the word "PUBLIC"
1298 pos += 6;
1299 state = STATE_AFTER_DOCTYPE_PUBLIC_KEYWORD;
1300 } else if (
1301 pos + 5 < len &&
1302 (cc === 0x53 || cc === 0x73) /* S or s */ &&
1303 (input.charCodeAt(pos + 1) | 0x20) === 0x79 /* y */ &&
1304 (input.charCodeAt(pos + 2) | 0x20) === 0x73 /* s */ &&
1305 (input.charCodeAt(pos + 3) | 0x20) === 0x74 /* t */ &&
1306 (input.charCodeAt(pos + 4) | 0x20) === 0x65 /* e */ &&
1307 (input.charCodeAt(pos + 5) | 0x20) === 0x6d /* m */
1308 ) {
1309 // ASCII case-insensitive match for the word "SYSTEM"
1310 pos += 6;
1311 state = STATE_AFTER_DOCTYPE_SYSTEM_KEYWORD;
1312 } else {
1313 // Anything else
1314 // This is an invalid-character-sequence-after-doctype-name parse error. Set
1315 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1316 // bogus DOCTYPE state.
1317 reportError(
1318 "invalid-character-sequence-after-doctype-name",
1319 pos,
1320 pos + 1,
1321 "warning"
1322 );
1323 state = STATE_BOGUS_DOCTYPE;
1324 }
1325 break;
1326
1327 // https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-public-keyword-state
1328 case STATE_AFTER_DOCTYPE_PUBLIC_KEYWORD:
1329 // Consume the next input character:
1330 if (isSpace(cc)) {
1331 // U+0009 CHARACTER TABULATION (tab)
1332 // U+000A LINE FEED (LF)
1333 // U+000C FORM FEED (FF)
1334 // U+0020 SPACE
1335 // Switch to the before DOCTYPE public identifier state.
1336 state = STATE_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER;
1337 pos++;
1338 } else if (cc === CC_QUOTATION_MARK) {
1339 // U+0022 QUOTATION MARK (")
1340 // This is a missing-whitespace-after-doctype-public-keyword parse error.
1341 // Set the current DOCTYPE token's public identifier to the empty string
1342 // (not missing), then switch to the DOCTYPE public identifier
1343 // (double-quoted) state.
1344 reportError(
1345 "missing-whitespace-after-doctype-public-keyword",
1346 pos,
1347 pos + 1,
1348 "warning"
1349 );
1350 state = STATE_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
1351 pos++;
1352 } else if (cc === CC_APOSTROPHE) {
1353 // U+0027 APOSTROPHE (')
1354 // This is a missing-whitespace-after-doctype-public-keyword parse error.
1355 // Set the current DOCTYPE token's public identifier to the empty string
1356 // (not missing), then switch to the DOCTYPE public identifier
1357 // (single-quoted) state.
1358 reportError(
1359 "missing-whitespace-after-doctype-public-keyword",
1360 pos,
1361 pos + 1,
1362 "warning"
1363 );
1364 state = STATE_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
1365 pos++;
1366 } else if (cc === CC_GREATER_THAN) {
1367 // U+003E GREATER-THAN SIGN (>)
1368 // This is a missing-doctype-public-identifier parse error. Set the current
1369 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1370 // the current DOCTYPE token.
1371 reportError(
1372 "missing-doctype-public-identifier",
1373 pos,
1374 pos + 1,
1375 "warning"
1376 );
1377 let nextPos = pos + 1;
1378 if (callbacks.doctype !== undefined) {
1379 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1380 }
1381 state = STATE_DATA;
1382 textStart = nextPos;
1383 pos = nextPos;
1384 } else {
1385 // Anything else
1386 // This is a missing-quote-before-doctype-public-identifier parse error. Set
1387 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1388 // bogus DOCTYPE state.
1389 reportError(
1390 "missing-quote-before-doctype-public-identifier",
1391 pos,
1392 pos + 1,
1393 "warning"
1394 );
1395 state = STATE_BOGUS_DOCTYPE;
1396 }
1397 break;
1398
1399 // https://html.spec.whatwg.org/multipage/parsing.html#before-doctype-public-identifier-state
1400 case STATE_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER:
1401 // Consume the next input character:
1402 if (isSpace(cc)) {
1403 // U+0009 CHARACTER TABULATION (tab)
1404 // U+000A LINE FEED (LF)
1405 // U+000C FORM FEED (FF)
1406 // U+0020 SPACE
1407 // Ignore the character.
1408 pos++;
1409 } else if (cc === CC_QUOTATION_MARK) {
1410 // U+0022 QUOTATION MARK (")
1411 // Set the current DOCTYPE token's public identifier to the empty string
1412 // (not missing), then switch to the DOCTYPE public identifier
1413 // (double-quoted) state.
1414 state = STATE_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
1415 pos++;
1416 } else if (cc === CC_APOSTROPHE) {
1417 // U+0027 APOSTROPHE (')
1418 // Set the current DOCTYPE token's public identifier to the empty string
1419 // (not missing), then switch to the DOCTYPE public identifier
1420 // (single-quoted) state.
1421 state = STATE_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
1422 pos++;
1423 } else if (cc === CC_GREATER_THAN) {
1424 // U+003E GREATER-THAN SIGN (>)
1425 // This is a missing-doctype-public-identifier parse error. Set the current
1426 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1427 // the current DOCTYPE token.
1428 reportError(
1429 "missing-doctype-public-identifier",
1430 pos,
1431 pos + 1,
1432 "warning"
1433 );
1434 let nextPos = pos + 1;
1435 if (callbacks.doctype !== undefined) {
1436 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1437 }
1438 state = STATE_DATA;
1439 textStart = nextPos;
1440 pos = nextPos;
1441 } else {
1442 // Anything else
1443 // This is a missing-quote-before-doctype-public-identifier parse error. Set
1444 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1445 // bogus DOCTYPE state.
1446 reportError(
1447 "missing-quote-before-doctype-public-identifier",
1448 pos,
1449 pos + 1,
1450 "warning"
1451 );
1452 state = STATE_BOGUS_DOCTYPE;
1453 }
1454 break;
1455
1456 // https://html.spec.whatwg.org/multipage/parsing.html#doctype-public-identifier-(double-quoted)-state
1457 case STATE_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED:
1458 // Consume the next input character:
1459 if (cc === CC_QUOTATION_MARK) {
1460 // U+0022 QUOTATION MARK (")
1461 // Switch to the after DOCTYPE public identifier state.
1462 state = STATE_AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
1463 pos++;
1464 } else if (cc === 0x00) {
1465 // U+0000 NULL
1466 // This is an unexpected-null-character parse error. Append a U+FFFD
1467 // REPLACEMENT CHARACTER character to the current DOCTYPE token's public
1468 // identifier.
1469 pos++;
1470 } else if (cc === CC_GREATER_THAN) {
1471 // U+003E GREATER-THAN SIGN (>)
1472 // This is an abrupt-doctype-public-identifier parse error. Set the current
1473 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1474 // the current DOCTYPE token.
1475 reportError(
1476 "abrupt-doctype-public-identifier",
1477 pos,
1478 pos + 1,
1479 "warning"
1480 );
1481 let nextPos = pos + 1;
1482 if (callbacks.doctype !== undefined) {
1483 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1484 }
1485 state = STATE_DATA;
1486 textStart = nextPos;
1487 pos = nextPos;
1488 } else {
1489 // Anything else
1490 // Append the current input character to the current DOCTYPE token's public
1491 // identifier.
1492 pos++;
1493 }
1494 break;
1495
1496 // https://html.spec.whatwg.org/multipage/parsing.html#doctype-public-identifier-(single-quoted)-state
1497 case STATE_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED:
1498 // Consume the next input character:
1499 if (cc === CC_APOSTROPHE) {
1500 // U+0027 APOSTROPHE (')
1501 // Switch to the after DOCTYPE public identifier state.
1502 state = STATE_AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
1503 pos++;
1504 } else if (cc === 0x00) {
1505 // U+0000 NULL
1506 // This is an unexpected-null-character parse error. Append a U+FFFD
1507 // REPLACEMENT CHARACTER character to the current DOCTYPE token's public
1508 // identifier.
1509 pos++;
1510 } else if (cc === CC_GREATER_THAN) {
1511 // U+003E GREATER-THAN SIGN (>)
1512 // This is an abrupt-doctype-public-identifier parse error. Set the current
1513 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1514 // the current DOCTYPE token.
1515 reportError(
1516 "abrupt-doctype-public-identifier",
1517 pos,
1518 pos + 1,
1519 "warning"
1520 );
1521 let nextPos = pos + 1;
1522 if (callbacks.doctype !== undefined) {
1523 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1524 }
1525 state = STATE_DATA;
1526 textStart = nextPos;
1527 pos = nextPos;
1528 } else {
1529 // Anything else
1530 // Append the current input character to the current DOCTYPE token's public
1531 // identifier.
1532 pos++;
1533 }
1534 break;
1535
1536 // https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-public-identifier-state
1537 case STATE_AFTER_DOCTYPE_PUBLIC_IDENTIFIER:
1538 // Consume the next input character:
1539 if (isSpace(cc)) {
1540 // U+0009 CHARACTER TABULATION (tab)
1541 // U+000A LINE FEED (LF)
1542 // U+000C FORM FEED (FF)
1543 // U+0020 SPACE
1544 // Switch to the between DOCTYPE public and system identifiers state.
1545 state = STATE_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS;
1546 pos++;
1547 } else if (cc === CC_GREATER_THAN) {
1548 // U+003E GREATER-THAN SIGN (>)
1549 // Switch to the data state. Emit the current DOCTYPE token.
1550 let nextPos = pos + 1;
1551 if (callbacks.doctype !== undefined) {
1552 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1553 }
1554 state = STATE_DATA;
1555 textStart = nextPos;
1556 pos = nextPos;
1557 } else if (cc === CC_QUOTATION_MARK) {
1558 // U+0022 QUOTATION MARK (")
1559 // This is a missing-whitespace-between-doctype-public-and-system-identifiers
1560 // parse error. Set the current DOCTYPE token's system
1561 // identifier to the empty string (not missing), then switch
1562 // to the DOCTYPE system identifier (double-quoted) state.
1563 reportError(
1564 "missing-whitespace-between-doctype-public-and-system-identifiers",
1565 pos,
1566 pos + 1,
1567 "warning"
1568 );
1569 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
1570 pos++;
1571 } else if (cc === CC_APOSTROPHE) {
1572 // U+0027 APOSTROPHE (')
1573 // This is a missing-whitespace-between-doctype-public-and-system-identifiers
1574 // parse error. Set the current DOCTYPE token's system
1575 // identifier to the empty string (not missing), then switch
1576 // to the DOCTYPE system identifier (single-quoted) state.
1577 reportError(
1578 "missing-whitespace-between-doctype-public-and-system-identifiers",
1579 pos,
1580 pos + 1,
1581 "warning"
1582 );
1583 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
1584 pos++;
1585 } else {
1586 // Anything else
1587 // This is a missing-quote-before-doctype-system-identifier parse error. Set
1588 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1589 // bogus DOCTYPE state.
1590 reportError(
1591 "missing-quote-before-doctype-system-identifier",
1592 pos,
1593 pos + 1,
1594 "warning"
1595 );
1596 state = STATE_BOGUS_DOCTYPE;
1597 }
1598 break;
1599
1600 // https://html.spec.whatwg.org/multipage/parsing.html#between-doctype-public-and-system-identifiers-state
1601 case STATE_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS:
1602 // Consume the next input character:
1603 if (isSpace(cc)) {
1604 // U+0009 CHARACTER TABULATION (tab)
1605 // U+000A LINE FEED (LF)
1606 // U+000C FORM FEED (FF)
1607 // U+0020 SPACE
1608 // Ignore the character.
1609 pos++;
1610 } else if (cc === CC_GREATER_THAN) {
1611 // U+003E GREATER-THAN SIGN (>)
1612 // Switch to the data state. Emit the current DOCTYPE token.
1613 let nextPos = pos + 1;
1614 if (callbacks.doctype !== undefined) {
1615 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1616 }
1617 state = STATE_DATA;
1618 textStart = nextPos;
1619 pos = nextPos;
1620 } else if (cc === CC_QUOTATION_MARK) {
1621 // U+0022 QUOTATION MARK (")
1622 // Set the current DOCTYPE token's system identifier to the empty string
1623 // (not missing), then switch to the DOCTYPE system identifier
1624 // (double-quoted) state.
1625 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
1626 pos++;
1627 } else if (cc === CC_APOSTROPHE) {
1628 // U+0027 APOSTROPHE (')
1629 // Set the current DOCTYPE token's system identifier to the empty string
1630 // (not missing), then switch to the DOCTYPE system identifier
1631 // (single-quoted) state.
1632 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
1633 pos++;
1634 } else {
1635 // Anything else
1636 // This is a missing-quote-before-doctype-system-identifier parse error. Set
1637 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1638 // bogus DOCTYPE state.
1639 reportError(
1640 "missing-quote-before-doctype-system-identifier",
1641 pos,
1642 pos + 1,
1643 "warning"
1644 );
1645 state = STATE_BOGUS_DOCTYPE;
1646 }
1647 break;
1648
1649 // https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-system-keyword-state
1650 case STATE_AFTER_DOCTYPE_SYSTEM_KEYWORD:
1651 // Consume the next input character:
1652 if (isSpace(cc)) {
1653 // U+0009 CHARACTER TABULATION (tab)
1654 // U+000A LINE FEED (LF)
1655 // U+000C FORM FEED (FF)
1656 // U+0020 SPACE
1657 // Switch to the before DOCTYPE system identifier state.
1658 state = STATE_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER;
1659 pos++;
1660 } else if (cc === CC_QUOTATION_MARK) {
1661 // U+0022 QUOTATION MARK (")
1662 // This is a missing-whitespace-after-doctype-system-keyword parse error.
1663 // Set the current DOCTYPE token's system identifier to the empty string
1664 // (not missing), then switch to the DOCTYPE system identifier
1665 // (double-quoted) state.
1666 reportError(
1667 "missing-whitespace-after-doctype-system-keyword",
1668 pos,
1669 pos + 1,
1670 "warning"
1671 );
1672 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
1673 pos++;
1674 } else if (cc === CC_APOSTROPHE) {
1675 // U+0027 APOSTROPHE (')
1676 // This is a missing-whitespace-after-doctype-system-keyword parse error.
1677 // Set the current DOCTYPE token's system identifier to the empty string
1678 // (not missing), then switch to the DOCTYPE system identifier
1679 // (single-quoted) state.
1680 reportError(
1681 "missing-whitespace-after-doctype-system-keyword",
1682 pos,
1683 pos + 1,
1684 "warning"
1685 );
1686 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
1687 pos++;
1688 } else if (cc === CC_GREATER_THAN) {
1689 // U+003E GREATER-THAN SIGN (>)
1690 // This is a missing-doctype-system-identifier parse error. Set the current
1691 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1692 // the current DOCTYPE token.
1693 reportError(
1694 "missing-doctype-system-identifier",
1695 pos,
1696 pos + 1,
1697 "warning"
1698 );
1699 let nextPos = pos + 1;
1700 if (callbacks.doctype !== undefined) {
1701 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1702 }
1703 state = STATE_DATA;
1704 textStart = nextPos;
1705 pos = nextPos;
1706 } else {
1707 // Anything else
1708 // This is a missing-quote-before-doctype-system-identifier parse error. Set
1709 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1710 // bogus DOCTYPE state.
1711 reportError(
1712 "missing-quote-before-doctype-system-identifier",
1713 pos,
1714 pos + 1,
1715 "warning"
1716 );
1717 state = STATE_BOGUS_DOCTYPE;
1718 }
1719 break;
1720
1721 // https://html.spec.whatwg.org/multipage/parsing.html#before-doctype-system-identifier-state
1722 case STATE_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER:
1723 // Consume the next input character:
1724 if (isSpace(cc)) {
1725 // U+0009 CHARACTER TABULATION (tab)
1726 // U+000A LINE FEED (LF)
1727 // U+000C FORM FEED (FF)
1728 // U+0020 SPACE
1729 // Ignore the character.
1730 pos++;
1731 } else if (cc === CC_QUOTATION_MARK) {
1732 // U+0022 QUOTATION MARK (")
1733 // Set the current DOCTYPE token's system identifier to the empty string
1734 // (not missing), then switch to the DOCTYPE system identifier
1735 // (double-quoted) state.
1736 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
1737 pos++;
1738 } else if (cc === CC_APOSTROPHE) {
1739 // U+0027 APOSTROPHE (')
1740 // Set the current DOCTYPE token's system identifier to the empty string
1741 // (not missing), then switch to the DOCTYPE system identifier
1742 // (single-quoted) state.
1743 state = STATE_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
1744 pos++;
1745 } else if (cc === CC_GREATER_THAN) {
1746 // U+003E GREATER-THAN SIGN (>)
1747 // This is a missing-doctype-system-identifier parse error. Set the current
1748 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1749 // the current DOCTYPE token.
1750 reportError(
1751 "missing-doctype-system-identifier",
1752 pos,
1753 pos + 1,
1754 "warning"
1755 );
1756 let nextPos = pos + 1;
1757 if (callbacks.doctype !== undefined) {
1758 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1759 }
1760 state = STATE_DATA;
1761 textStart = nextPos;
1762 pos = nextPos;
1763 } else {
1764 // Anything else
1765 // This is a missing-quote-before-doctype-system-identifier parse error. Set
1766 // the current DOCTYPE token's force-quirks flag to on. Reconsume in the
1767 // bogus DOCTYPE state.
1768 reportError(
1769 "missing-quote-before-doctype-system-identifier",
1770 pos,
1771 pos + 1,
1772 "warning"
1773 );
1774 state = STATE_BOGUS_DOCTYPE;
1775 }
1776 break;
1777
1778 // https://html.spec.whatwg.org/multipage/parsing.html#doctype-system-identifier-(double-quoted)-state
1779 case STATE_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED:
1780 // Consume the next input character:
1781 if (cc === CC_QUOTATION_MARK) {
1782 // U+0022 QUOTATION MARK (")
1783 // Switch to the after DOCTYPE system identifier state.
1784 state = STATE_AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
1785 pos++;
1786 } else if (cc === 0x00) {
1787 // U+0000 NULL
1788 // This is an unexpected-null-character parse error. Append a U+FFFD
1789 // REPLACEMENT CHARACTER character to the current DOCTYPE token's system
1790 // identifier.
1791 pos++;
1792 } else if (cc === CC_GREATER_THAN) {
1793 // U+003E GREATER-THAN SIGN (>)
1794 // This is an abrupt-doctype-system-identifier parse error. Set the current
1795 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1796 // the current DOCTYPE token.
1797 reportError(
1798 "abrupt-doctype-system-identifier",
1799 pos,
1800 pos + 1,
1801 "warning"
1802 );
1803 let nextPos = pos + 1;
1804 if (callbacks.doctype !== undefined) {
1805 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1806 }
1807 state = STATE_DATA;
1808 textStart = nextPos;
1809 pos = nextPos;
1810 } else {
1811 // Anything else
1812 // Append the current input character to the current DOCTYPE token's system
1813 // identifier.
1814 pos++;
1815 }
1816 break;
1817
1818 // https://html.spec.whatwg.org/multipage/parsing.html#doctype-system-identifier-(single-quoted)-state
1819 case STATE_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED:
1820 // Consume the next input character:
1821 if (cc === CC_APOSTROPHE) {
1822 // U+0027 APOSTROPHE (')
1823 // Switch to the after DOCTYPE system identifier state.
1824 state = STATE_AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
1825 pos++;
1826 } else if (cc === 0x00) {
1827 // U+0000 NULL
1828 // This is an unexpected-null-character parse error. Append a U+FFFD
1829 // REPLACEMENT CHARACTER character to the current DOCTYPE token's system
1830 // identifier.
1831 pos++;
1832 } else if (cc === CC_GREATER_THAN) {
1833 // U+003E GREATER-THAN SIGN (>)
1834 // This is an abrupt-doctype-system-identifier parse error. Set the current
1835 // DOCTYPE token's force-quirks flag to on. Switch to the data state. Emit
1836 // the current DOCTYPE token.
1837 reportError(
1838 "abrupt-doctype-system-identifier",
1839 pos,
1840 pos + 1,
1841 "warning"
1842 );
1843 let nextPos = pos + 1;
1844 if (callbacks.doctype !== undefined) {
1845 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1846 }
1847 state = STATE_DATA;
1848 textStart = nextPos;
1849 pos = nextPos;
1850 } else {
1851 // Anything else
1852 // Append the current input character to the current DOCTYPE token's system
1853 // identifier.
1854 pos++;
1855 }
1856 break;
1857
1858 // https://html.spec.whatwg.org/multipage/parsing.html#after-doctype-system-identifier-state
1859 case STATE_AFTER_DOCTYPE_SYSTEM_IDENTIFIER:
1860 // Consume the next input character:
1861 if (isSpace(cc)) {
1862 // U+0009 CHARACTER TABULATION (tab)
1863 // U+000A LINE FEED (LF)
1864 // U+000C FORM FEED (FF)
1865 // U+0020 SPACE
1866 // Ignore the character.
1867 pos++;
1868 } else if (cc === CC_GREATER_THAN) {
1869 // U+003E GREATER-THAN SIGN (>)
1870 // Switch to the data state. Emit the current DOCTYPE token.
1871 let nextPos = pos + 1;
1872 if (callbacks.doctype !== undefined) {
1873 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1874 }
1875 state = STATE_DATA;
1876 textStart = nextPos;
1877 pos = nextPos;
1878 } else {
1879 // Anything else
1880 // This is an unexpected-character-after-doctype-system-identifier parse
1881 // error. Reconsume in the bogus DOCTYPE state. (This does not set the
1882 // current DOCTYPE token's force-quirks flag to on.)
1883 reportError(
1884 "unexpected-character-after-doctype-system-identifier",
1885 pos,
1886 pos + 1,
1887 "warning"
1888 );
1889 state = STATE_BOGUS_DOCTYPE;
1890 }
1891 break;
1892
1893 // https://html.spec.whatwg.org/multipage/parsing.html#bogus-doctype-state
1894 case STATE_BOGUS_DOCTYPE:
1895 // Consume the next input character:
1896 if (cc === CC_GREATER_THAN) {
1897 // U+003E GREATER-THAN SIGN (>)
1898 // Switch to the data state. Emit the DOCTYPE token.
1899 let nextPos = pos + 1;
1900 if (callbacks.doctype !== undefined) {
1901 nextPos = callbacks.doctype(input, commentStart, pos + 1);
1902 }
1903 state = STATE_DATA;
1904 textStart = nextPos;
1905 pos = nextPos;
1906 } else if (cc === 0x00) {
1907 // U+0000 NULL
1908 // This is an unexpected-null-character parse error. Ignore the character.
1909 pos++;
1910 } else {
1911 // Anything else
1912 // Ignore the character.
1913 pos++;
1914 }
1915 break;
1916
1917 // https://html.spec.whatwg.org/multipage/parsing.html#cdata-section-state
1918 case STATE_CDATA_SECTION:
1919 // Consume the next input character:
1920 // U+005D RIGHT SQUARE BRACKET (])
1921 // Switch to the CDATA section bracket state.
1922 if (cc === CC_RIGHT_SQUARE_BRACKET) {
1923 state = STATE_CDATA_SECTION_BRACKET;
1924 pos++;
1925 } else {
1926 // Anything else
1927 // Emit the current input character as a character token.
1928 pos++;
1929 }
1930 break;
1931
1932 // https://html.spec.whatwg.org/multipage/parsing.html#cdata-section-bracket-state
1933 case STATE_CDATA_SECTION_BRACKET:
1934 // Consume the next input character:
1935 // U+005D RIGHT SQUARE BRACKET (])
1936 // Switch to the CDATA section end state.
1937 if (cc === CC_RIGHT_SQUARE_BRACKET) {
1938 state = STATE_CDATA_SECTION_END;
1939 pos++;
1940 } else {
1941 // Anything else
1942 // Emit a U+005D RIGHT SQUARE BRACKET character token. Reconsume in the
1943 // CDATA section state.
1944 state = STATE_CDATA_SECTION;
1945 // Reconsume
1946 }
1947 break;
1948
1949 // https://html.spec.whatwg.org/multipage/parsing.html#cdata-section-end-state
1950 case STATE_CDATA_SECTION_END:
1951 // Consume the next input character:
1952 // U+005D RIGHT SQUARE BRACKET (])
1953 // Emit a U+005D RIGHT SQUARE BRACKET character token.
1954 if (cc === CC_RIGHT_SQUARE_BRACKET) {
1955 pos++;
1956 } else if (cc === CC_GREATER_THAN) {
1957 // U+003E GREATER-THAN SIGN (>)
1958 // Switch to the data state.
1959 let nextPos = pos + 1;
1960 if (callbacks.comment !== undefined) {
1961 nextPos = callbacks.comment(input, commentStart, pos + 1);
1962 }
1963 state = STATE_DATA;
1964 textStart = nextPos;
1965 pos = nextPos;
1966 } else {
1967 // Anything else
1968 // Emit two U+005D RIGHT SQUARE BRACKET character tokens. Reconsume in the
1969 // CDATA section state.
1970 state = STATE_CDATA_SECTION;
1971 // Reconsume
1972 }
1973 break;
1974
1975 // https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state
1976 case STATE_RCDATA:
1977 // Consume the next input character:
1978 // U+003C LESS-THAN SIGN (<)
1979 // Switch to the RCDATA less-than sign state.
1980 if (cc === CC_LESS_THAN) {
1981 tagStart = pos;
1982 state = STATE_RCDATA_LESS_THAN_SIGN;
1983 pos++;
1984 } else {
1985 // Anything else
1986 // Emit the current input character as a character token.
1987 pos++;
1988 }
1989 break;
1990
1991 // https://html.spec.whatwg.org/multipage/parsing.html#rcdata-less-than-sign-state
1992 case STATE_RCDATA_LESS_THAN_SIGN:
1993 // Consume the next input character:
1994 // U+002F SOLIDUS (/)
1995 // Switch to the RCDATA end tag open state. (Spec sets a
1996 // temporary buffer here; we track the would-be content via
1997 // offset ranges instead.)
1998 if (cc === CC_SOLIDUS) {
1999 state = STATE_RCDATA_END_TAG_OPEN;
2000 pos++;
2001 } else {
2002 // Anything else
2003 // Emit a U+003C LESS-THAN SIGN character token. Reconsume in the RCDATA
2004 // state.
2005 state = STATE_RCDATA;
2006 // Reconsume
2007 }
2008 break;
2009
2010 // https://html.spec.whatwg.org/multipage/parsing.html#rcdata-end-tag-open-state
2011 case STATE_RCDATA_END_TAG_OPEN:
2012 // Consume the next input character:
2013 // ASCII alpha
2014 // Create a new end tag token, set its tag name to the empty string.
2015 // Reconsume in the RCDATA end tag name state.
2016 if (isAsciiAlpha(cc)) {
2017 tagNameStart = pos;
2018 state = STATE_RCDATA_END_TAG_NAME;
2019 // Reconsume
2020 } else {
2021 // Anything else
2022 // Emit a U+003C LESS-THAN SIGN character token and a U+002F SOLIDUS
2023 // character token. Reconsume in the RCDATA state.
2024 state = STATE_RCDATA;
2025 // Reconsume
2026 }
2027 break;
2028
2029 // https://html.spec.whatwg.org/multipage/parsing.html#rcdata-end-tag-name-state
2030 case STATE_RCDATA_END_TAG_NAME:
2031 // Consume the next input character:
2032 // U+0009 CHARACTER TABULATION (tab)
2033 // U+000A LINE FEED (LF)
2034 // U+000C FORM FEED (FF)
2035 // U+0020 SPACE
2036 // If the current end tag token is an appropriate end tag token, then switch
2037 // to the before attribute name state. Otherwise, treat it as per the
2038 // "anything else" entry below.
2039 if (isSpace(cc)) {
2040 tagNameEnd = pos;
2041 if (
2042 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2043 lastOpenTagName
2044 ) {
2045 flushText(tagStart);
2046 state = STATE_BEFORE_ATTRIBUTE_NAME;
2047 pos++;
2048 } else {
2049 state = STATE_RCDATA;
2050 // Reconsume
2051 }
2052 } else if (cc === CC_SOLIDUS) {
2053 // U+002F SOLIDUS (/)
2054 // If the current end tag token is an appropriate end tag token, then switch
2055 // to the self-closing start tag state. Otherwise, treat it as per the
2056 // "anything else" entry below.
2057 tagNameEnd = pos;
2058 if (
2059 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2060 lastOpenTagName
2061 ) {
2062 flushText(tagStart);
2063 state = STATE_SELF_CLOSING_START_TAG;
2064 pos++;
2065 } else {
2066 state = STATE_RCDATA;
2067 // Reconsume
2068 }
2069 } else if (cc === CC_GREATER_THAN) {
2070 // U+003E GREATER-THAN SIGN (>)
2071 // If the current end tag token is an appropriate end tag token, then switch
2072 // to the data state and emit the current tag token. Otherwise, treat it as
2073 // per the "anything else" entry below.
2074 tagNameEnd = pos;
2075 if (
2076 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2077 lastOpenTagName
2078 ) {
2079 flushText(tagStart);
2080 state = STATE_DATA;
2081 pos = emitCloseTag(pos + 1);
2082 } else {
2083 state = STATE_RCDATA;
2084 // Reconsume
2085 }
2086 } else if (isAsciiAlpha(cc)) {
2087 // ASCII upper alpha / ASCII lower alpha
2088 // Append the lowercase version of the current input character to the
2089 // current tag token's tag name. Append the current input character to
2090 // the temporary buffer.
2091 pos++;
2092 } else {
2093 // Anything else
2094 // Emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character
2095 // token, and a character token for each of the characters in the temporary
2096 // buffer (in the order they were added to the buffer). Reconsume in the
2097 // RCDATA state.
2098 state = STATE_RCDATA;
2099 // Reconsume
2100 }
2101 break;
2102
2103 // https://html.spec.whatwg.org/multipage/parsing.html#rawtext-state
2104 case STATE_RAWTEXT:
2105 // Consume the next input character:
2106 // U+003C LESS-THAN SIGN (<)
2107 // Switch to the RAWTEXT less-than sign state.
2108 if (cc === CC_LESS_THAN) {
2109 tagStart = pos;
2110 state = STATE_RAWTEXT_LESS_THAN_SIGN;
2111 pos++;
2112 } else {
2113 pos++;
2114 }
2115 break;
2116
2117 // https://html.spec.whatwg.org/multipage/parsing.html#rawtext-less-than-sign-state
2118 case STATE_RAWTEXT_LESS_THAN_SIGN:
2119 // Consume the next input character:
2120 // U+002F SOLIDUS (/)
2121 // Switch to the RAWTEXT end tag open state. (Spec sets a
2122 // temporary buffer here; we track via offset ranges instead.)
2123 if (cc === CC_SOLIDUS) {
2124 state = STATE_RAWTEXT_END_TAG_OPEN;
2125 pos++;
2126 } else {
2127 // Anything else
2128 // Emit a U+003C LESS-THAN SIGN character token. Reconsume in the RAWTEXT
2129 // state.
2130 state = STATE_RAWTEXT;
2131 // Reconsume
2132 }
2133 break;
2134
2135 // https://html.spec.whatwg.org/multipage/parsing.html#rawtext-end-tag-open-state
2136 case STATE_RAWTEXT_END_TAG_OPEN:
2137 // Consume the next input character:
2138 // ASCII alpha
2139 // Create a new end tag token, set its tag name to the empty string.
2140 // Reconsume in the RAWTEXT end tag name state.
2141 if (isAsciiAlpha(cc)) {
2142 tagNameStart = pos;
2143 state = STATE_RAWTEXT_END_TAG_NAME;
2144 // Reconsume
2145 } else {
2146 // Anything else
2147 // Emit a U+003C LESS-THAN SIGN character token and a U+002F SOLIDUS
2148 // character token. Reconsume in the RAWTEXT state.
2149 state = STATE_RAWTEXT;
2150 // Reconsume
2151 }
2152 break;
2153
2154 // https://html.spec.whatwg.org/multipage/parsing.html#rawtext-end-tag-name-state
2155 case STATE_RAWTEXT_END_TAG_NAME:
2156 // Consume the next input character:
2157 // U+0009 CHARACTER TABULATION (tab)
2158 // U+000A LINE FEED (LF)
2159 // U+000C FORM FEED (FF)
2160 // U+0020 SPACE
2161 // If the current end tag token is an appropriate end tag token, then switch
2162 // to the before attribute name state. Otherwise, treat it as per the
2163 // "anything else" entry below.
2164 if (isSpace(cc)) {
2165 tagNameEnd = pos;
2166 if (
2167 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2168 lastOpenTagName
2169 ) {
2170 flushText(tagStart);
2171 state = STATE_BEFORE_ATTRIBUTE_NAME;
2172 pos++;
2173 } else {
2174 state = STATE_RAWTEXT;
2175 }
2176 } else if (cc === CC_SOLIDUS) {
2177 // U+002F SOLIDUS (/)
2178 // If the current end tag token is an appropriate end tag token, then switch
2179 // to the self-closing start tag state. Otherwise, treat it as per the
2180 // "anything else" entry below.
2181 tagNameEnd = pos;
2182 if (
2183 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2184 lastOpenTagName
2185 ) {
2186 flushText(tagStart);
2187 state = STATE_SELF_CLOSING_START_TAG;
2188 pos++;
2189 } else {
2190 state = STATE_RAWTEXT;
2191 }
2192 } else if (cc === CC_GREATER_THAN) {
2193 // U+003E GREATER-THAN SIGN (>)
2194 // If the current end tag token is an appropriate end tag token, then switch
2195 // to the data state and emit the current tag token. Otherwise, treat it as
2196 // per the "anything else" entry below.
2197 tagNameEnd = pos;
2198 if (
2199 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2200 lastOpenTagName
2201 ) {
2202 flushText(tagStart);
2203 state = STATE_DATA;
2204 pos = emitCloseTag(pos + 1);
2205 } else {
2206 state = STATE_RAWTEXT;
2207 }
2208 } else if (isAsciiAlpha(cc)) {
2209 // ASCII upper alpha / ASCII lower alpha
2210 // Append the lowercase version of the current input character to the
2211 // current tag token's tag name. Append the current input character to
2212 // the temporary buffer.
2213 pos++;
2214 } else {
2215 // Anything else
2216 // Emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character
2217 // token, and a character token for each of the characters in the temporary
2218 // buffer (in the order they were added to the buffer). Reconsume in the
2219 // RAWTEXT state.
2220 state = STATE_RAWTEXT;
2221 // Reconsume
2222 }
2223 break;
2224
2225 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-state
2226 case STATE_SCRIPT_DATA:
2227 // Consume the next input character:
2228 // U+003C LESS-THAN SIGN (<)
2229 // Switch to the script data less-than sign state.
2230 if (cc === CC_LESS_THAN) {
2231 tagStart = pos;
2232 state = STATE_SCRIPT_DATA_LESS_THAN_SIGN;
2233 pos++;
2234 } else {
2235 pos++;
2236 }
2237 break;
2238
2239 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-less-than-sign-state
2240 case STATE_SCRIPT_DATA_LESS_THAN_SIGN:
2241 // Consume the next input character:
2242 // U+002F SOLIDUS (/)
2243 // Switch to the script data end tag open state. (Spec sets a
2244 // temporary buffer here; we track via offset ranges instead.)
2245 if (cc === CC_SOLIDUS) {
2246 state = STATE_SCRIPT_DATA_END_TAG_OPEN;
2247 pos++;
2248 } else if (cc === CC_EXCLAMATION_MARK) {
2249 // U+0021 EXCLAMATION MARK (!)
2250 // Switch to the script data escape start state. Emit a U+003C LESS-THAN
2251 // SIGN character token and a U+0021 EXCLAMATION MARK character token.
2252 state = STATE_SCRIPT_DATA_ESCAPE_START;
2253 pos++;
2254 } else {
2255 // Anything else
2256 // Emit a U+003C LESS-THAN SIGN character token. Reconsume in the script
2257 // data state.
2258 state = STATE_SCRIPT_DATA;
2259 // Reconsume
2260 }
2261 break;
2262
2263 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-end-tag-open-state
2264 case STATE_SCRIPT_DATA_END_TAG_OPEN:
2265 // Consume the next input character:
2266 // ASCII alpha
2267 // Create a new end tag token, set its tag name to the empty string.
2268 // Reconsume in the script data end tag name state.
2269 if (isAsciiAlpha(cc)) {
2270 tagNameStart = pos;
2271 state = STATE_SCRIPT_DATA_END_TAG_NAME;
2272 // Reconsume
2273 } else {
2274 // Anything else
2275 // Emit a U+003C LESS-THAN SIGN character token and a U+002F SOLIDUS
2276 // character token. Reconsume in the script data state.
2277 state = STATE_SCRIPT_DATA;
2278 // Reconsume
2279 }
2280 break;
2281
2282 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-end-tag-name-state
2283 case STATE_SCRIPT_DATA_END_TAG_NAME:
2284 // Consume the next input character:
2285 // U+0009 CHARACTER TABULATION (tab)
2286 // U+000A LINE FEED (LF)
2287 // U+000C FORM FEED (FF)
2288 // U+0020 SPACE
2289 // If the current end tag token is an appropriate end tag token, then switch
2290 // to the before attribute name state. Otherwise, treat it as per the
2291 // "anything else" entry below.
2292 if (isSpace(cc)) {
2293 tagNameEnd = pos;
2294 if (
2295 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2296 lastOpenTagName
2297 ) {
2298 flushText(tagStart);
2299 state = STATE_BEFORE_ATTRIBUTE_NAME;
2300 pos++;
2301 } else {
2302 state = STATE_SCRIPT_DATA;
2303 }
2304 } else if (cc === CC_SOLIDUS) {
2305 // U+002F SOLIDUS (/)
2306 // If the current end tag token is an appropriate end tag token, then switch
2307 // to the self-closing start tag state. Otherwise, treat it as per the
2308 // "anything else" entry below.
2309 tagNameEnd = pos;
2310 if (
2311 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2312 lastOpenTagName
2313 ) {
2314 flushText(tagStart);
2315 state = STATE_SELF_CLOSING_START_TAG;
2316 pos++;
2317 } else {
2318 state = STATE_SCRIPT_DATA;
2319 }
2320 } else if (cc === CC_GREATER_THAN) {
2321 // U+003E GREATER-THAN SIGN (>)
2322 // If the current end tag token is an appropriate end tag token, then switch
2323 // to the data state and emit the current tag token. Otherwise, treat it as
2324 // per the "anything else" entry below.
2325 tagNameEnd = pos;
2326 if (
2327 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2328 lastOpenTagName
2329 ) {
2330 flushText(tagStart);
2331 state = STATE_DATA;
2332 pos = emitCloseTag(pos + 1);
2333 } else {
2334 state = STATE_SCRIPT_DATA;
2335 }
2336 } else if (isAsciiAlpha(cc)) {
2337 // ASCII upper alpha / ASCII lower alpha
2338 pos++;
2339 } else {
2340 // Anything else
2341 // Emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character
2342 // token, and a character token for each of the characters in the temporary
2343 // buffer (in the order they were added to the buffer). Reconsume in the
2344 // script data state.
2345 state = STATE_SCRIPT_DATA;
2346 // Reconsume
2347 }
2348 break;
2349
2350 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escape-start-state
2351 case STATE_SCRIPT_DATA_ESCAPE_START:
2352 // Consume the next input character:
2353 // U+002D HYPHEN-MINUS (-)
2354 // Switch to the script data escape start dash state. Emit a U+002D
2355 // HYPHEN-MINUS character token.
2356 if (cc === CC_HYPHEN_MINUS) {
2357 state = STATE_SCRIPT_DATA_ESCAPE_START_DASH;
2358 pos++;
2359 } else {
2360 // Anything else
2361 // Reconsume in the script data state.
2362 state = STATE_SCRIPT_DATA;
2363 // Reconsume
2364 }
2365 break;
2366
2367 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escape-start-dash-state
2368 case STATE_SCRIPT_DATA_ESCAPE_START_DASH:
2369 // Consume the next input character:
2370 // U+002D HYPHEN-MINUS (-)
2371 // Switch to the script data escaped dash dash state. Emit a U+002D
2372 // HYPHEN-MINUS character token.
2373 if (cc === CC_HYPHEN_MINUS) {
2374 state = STATE_SCRIPT_DATA_ESCAPED_DASH_DASH;
2375 pos++;
2376 } else {
2377 // Anything else
2378 // Reconsume in the script data state.
2379 state = STATE_SCRIPT_DATA;
2380 // Reconsume
2381 }
2382 break;
2383
2384 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-state
2385 case STATE_SCRIPT_DATA_ESCAPED:
2386 // Consume the next input character:
2387 // U+002D HYPHEN-MINUS (-)
2388 // Switch to the script data escaped dash state. Emit a U+002D HYPHEN-MINUS
2389 // character token.
2390 if (cc === CC_HYPHEN_MINUS) {
2391 state = STATE_SCRIPT_DATA_ESCAPED_DASH;
2392 pos++;
2393 } else if (cc === CC_LESS_THAN) {
2394 // U+003C LESS-THAN SIGN (<)
2395 // Switch to the script data escaped less-than sign state.
2396 tagStart = pos;
2397 state = STATE_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
2398 pos++;
2399 } else {
2400 // Anything else
2401 // Emit the current input character as a character token.
2402 pos++;
2403 }
2404 break;
2405
2406 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-dash-state
2407 case STATE_SCRIPT_DATA_ESCAPED_DASH:
2408 // Consume the next input character:
2409 // U+002D HYPHEN-MINUS (-)
2410 // Switch to the script data escaped dash dash state. Emit a U+002D
2411 // HYPHEN-MINUS character token.
2412 if (cc === CC_HYPHEN_MINUS) {
2413 state = STATE_SCRIPT_DATA_ESCAPED_DASH_DASH;
2414 pos++;
2415 } else if (cc === CC_LESS_THAN) {
2416 // U+003C LESS-THAN SIGN (<)
2417 // Switch to the script data escaped less-than sign state.
2418 tagStart = pos;
2419 state = STATE_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
2420 pos++;
2421 } else {
2422 // Anything else
2423 // Switch to the script data escaped state. Emit the current input character
2424 // as a character token.
2425 state = STATE_SCRIPT_DATA_ESCAPED;
2426 pos++;
2427 }
2428 break;
2429
2430 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-dash-dash-state
2431 case STATE_SCRIPT_DATA_ESCAPED_DASH_DASH:
2432 // Consume the next input character:
2433 // U+002D HYPHEN-MINUS (-)
2434 // Emit a U+002D HYPHEN-MINUS character token.
2435 if (cc === CC_HYPHEN_MINUS) {
2436 pos++;
2437 } else if (cc === CC_LESS_THAN) {
2438 // U+003C LESS-THAN SIGN (<)
2439 // Switch to the script data escaped less-than sign state.
2440 tagStart = pos;
2441 state = STATE_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
2442 pos++;
2443 } else if (cc === CC_GREATER_THAN) {
2444 // U+003E GREATER-THAN SIGN (>)
2445 // Switch to the script data state. Emit a U+003E GREATER-THAN SIGN
2446 // character token.
2447 state = STATE_SCRIPT_DATA;
2448 pos++;
2449 } else {
2450 // Anything else
2451 // Switch to the script data escaped state. Emit the current input character
2452 // as a character token.
2453 state = STATE_SCRIPT_DATA_ESCAPED;
2454 pos++;
2455 }
2456 break;
2457
2458 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-less-than-sign-state
2459 case STATE_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN:
2460 // Consume the next input character:
2461 // U+002F SOLIDUS (/)
2462 // Switch to the script data escaped end tag open state.
2463 // (Spec sets a temporary buffer; we track via offset ranges.)
2464 if (cc === CC_SOLIDUS) {
2465 state = STATE_SCRIPT_DATA_ESCAPED_END_TAG_OPEN;
2466 pos++;
2467 } else if (isAsciiAlpha(cc)) {
2468 // ASCII alpha
2469 // Set the temporary buffer to the empty string. Emit a U+003C LESS-THAN
2470 // SIGN character token. Reconsume in the script data double escape start
2471 // state.
2472 scriptMatch = 0;
2473 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPE_START;
2474 // Reconsume
2475 } else {
2476 // Anything else
2477 // Emit a U+003C LESS-THAN SIGN character token. Reconsume in the script
2478 // data escaped state.
2479 state = STATE_SCRIPT_DATA_ESCAPED;
2480 // Reconsume
2481 }
2482 break;
2483
2484 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-end-tag-open-state
2485 case STATE_SCRIPT_DATA_ESCAPED_END_TAG_OPEN:
2486 // Consume the next input character:
2487 // ASCII alpha
2488 // Create a new end tag token, set its tag name to the empty string.
2489 // Reconsume in the script data escaped end tag name state.
2490 if (isAsciiAlpha(cc)) {
2491 tagNameStart = pos;
2492 state = STATE_SCRIPT_DATA_ESCAPED_END_TAG_NAME;
2493 // Reconsume
2494 } else {
2495 // Anything else
2496 // Emit a U+003C LESS-THAN SIGN character token and a U+002F SOLIDUS
2497 // character token. Reconsume in the script data escaped state.
2498 state = STATE_SCRIPT_DATA_ESCAPED;
2499 // Reconsume
2500 }
2501 break;
2502
2503 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-escaped-end-tag-name-state
2504 case STATE_SCRIPT_DATA_ESCAPED_END_TAG_NAME:
2505 // Consume the next input character:
2506 // U+0009 CHARACTER TABULATION (tab)
2507 // U+000A LINE FEED (LF)
2508 // U+000C FORM FEED (FF)
2509 // U+0020 SPACE
2510 // If the current end tag token is an appropriate end tag token, then switch
2511 // to the before attribute name state. Otherwise, treat it as per the
2512 // "anything else" entry below.
2513 if (isSpace(cc)) {
2514 tagNameEnd = pos;
2515 if (
2516 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2517 lastOpenTagName
2518 ) {
2519 flushText(tagStart);
2520 state = STATE_BEFORE_ATTRIBUTE_NAME;
2521 pos++;
2522 } else {
2523 state = STATE_SCRIPT_DATA_ESCAPED;
2524 }
2525 } else if (cc === CC_SOLIDUS) {
2526 // U+002F SOLIDUS (/)
2527 // If the current end tag token is an appropriate end tag token, then switch
2528 // to the self-closing start tag state. Otherwise, treat it as per the
2529 // "anything else" entry below.
2530 tagNameEnd = pos;
2531 if (
2532 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2533 lastOpenTagName
2534 ) {
2535 flushText(tagStart);
2536 state = STATE_SELF_CLOSING_START_TAG;
2537 pos++;
2538 } else {
2539 state = STATE_SCRIPT_DATA_ESCAPED;
2540 }
2541 } else if (cc === CC_GREATER_THAN) {
2542 // U+003E GREATER-THAN SIGN (>)
2543 // If the current end tag token is an appropriate end tag token, then switch
2544 // to the data state and emit the current tag token. Otherwise, treat it as
2545 // per the "anything else" entry below.
2546 tagNameEnd = pos;
2547 if (
2548 input.slice(tagNameStart, tagNameEnd).toLowerCase() ===
2549 lastOpenTagName
2550 ) {
2551 flushText(tagStart);
2552 state = STATE_DATA;
2553 pos = emitCloseTag(pos + 1);
2554 } else {
2555 state = STATE_SCRIPT_DATA_ESCAPED;
2556 }
2557 } else if (isAsciiAlpha(cc)) {
2558 // ASCII upper alpha / ASCII lower alpha
2559 pos++;
2560 } else {
2561 // Anything else
2562 // Emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character
2563 // token, and a character token for each of the characters in the temporary
2564 // buffer (in the order they were added to the buffer). Reconsume in the
2565 // script data escaped state.
2566 state = STATE_SCRIPT_DATA_ESCAPED;
2567 // Reconsume
2568 }
2569 break;
2570
2571 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escape-start-state
2572 case STATE_SCRIPT_DATA_DOUBLE_ESCAPE_START:
2573 // Consume the next input character:
2574 // U+0009 CHARACTER TABULATION (tab)
2575 // U+000A LINE FEED (LF)
2576 // U+000C FORM FEED (FF)
2577 // U+0020 SPACE
2578 // U+002F SOLIDUS (/)
2579 // U+003E GREATER-THAN SIGN (>)
2580 // If the temporary buffer is the string "script", then switch to the script
2581 // data double escaped state. Otherwise, switch to the script data escaped
2582 // state. Emit the current input character as a character token.
2583 if (isSpace(cc) || cc === CC_SOLIDUS || cc === CC_GREATER_THAN) {
2584 state =
2585 scriptMatch === 6
2586 ? STATE_SCRIPT_DATA_DOUBLE_ESCAPED
2587 : STATE_SCRIPT_DATA_ESCAPED;
2588 pos++;
2589 } else if (isAsciiUpperAlpha(cc) || isAsciiLowerAlpha(cc)) {
2590 // ASCII alpha — advance the `"script"` match counter if the
2591 // lowercase form matches the next expected char, otherwise
2592 // snap to the sentinel so further chars can't revive a
2593 // match. No buffer allocation.
2594 const lower = isAsciiUpperAlpha(cc) ? cc + 0x20 : cc;
2595 if (scriptMatch < 6 && lower === "script".charCodeAt(scriptMatch)) {
2596 scriptMatch++;
2597 } else {
2598 scriptMatch = 7;
2599 }
2600 pos++;
2601 } else {
2602 // Anything else
2603 // Reconsume in the script data escaped state.
2604 state = STATE_SCRIPT_DATA_ESCAPED;
2605 // Reconsume
2606 }
2607 break;
2608
2609 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-state
2610 case STATE_SCRIPT_DATA_DOUBLE_ESCAPED:
2611 // Consume the next input character:
2612 // U+002D HYPHEN-MINUS (-)
2613 // Switch to the script data double escaped dash state. Emit a U+002D
2614 // HYPHEN-MINUS character token.
2615 if (cc === CC_HYPHEN_MINUS) {
2616 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH;
2617 pos++;
2618 } else if (cc === CC_LESS_THAN) {
2619 // U+003C LESS-THAN SIGN (<)
2620 // Switch to the script data double escaped less-than sign state. Emit a
2621 // U+003C LESS-THAN SIGN character token.
2622 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
2623 pos++;
2624 } else {
2625 // Anything else
2626 // Emit the current input character as a character token.
2627 pos++;
2628 }
2629 break;
2630
2631 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-dash-state
2632 case STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH:
2633 // Consume the next input character:
2634 // U+002D HYPHEN-MINUS (-)
2635 // Switch to the script data double escaped dash dash state. Emit a U+002D
2636 // HYPHEN-MINUS character token.
2637 if (cc === CC_HYPHEN_MINUS) {
2638 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH;
2639 pos++;
2640 } else if (cc === CC_LESS_THAN) {
2641 // U+003C LESS-THAN SIGN (<)
2642 // Switch to the script data double escaped less-than sign state. Emit a
2643 // U+003C LESS-THAN SIGN character token.
2644 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
2645 pos++;
2646 } else {
2647 // Anything else
2648 // Switch to the script data double escaped state. Emit the current input
2649 // character as a character token.
2650 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED;
2651 pos++;
2652 }
2653 break;
2654
2655 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-dash-dash-state
2656 case STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH:
2657 // Consume the next input character:
2658 // U+002D HYPHEN-MINUS (-)
2659 // Emit a U+002D HYPHEN-MINUS character token.
2660 if (cc === CC_HYPHEN_MINUS) {
2661 pos++;
2662 } else if (cc === CC_LESS_THAN) {
2663 // U+003C LESS-THAN SIGN (<)
2664 // Switch to the script data double escaped less-than sign state. Emit a
2665 // U+003C LESS-THAN SIGN character token.
2666 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
2667 pos++;
2668 } else if (cc === CC_GREATER_THAN) {
2669 // U+003E GREATER-THAN SIGN (>)
2670 // Switch to the script data state. Emit a U+003E GREATER-THAN SIGN
2671 // character token.
2672 state = STATE_SCRIPT_DATA;
2673 pos++;
2674 } else {
2675 // Anything else
2676 // Switch to the script data double escaped state. Emit the current input
2677 // character as a character token.
2678 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED;
2679 pos++;
2680 }
2681 break;
2682
2683 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escaped-less-than-sign-state
2684 case STATE_SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN:
2685 // Consume the next input character:
2686 // U+002F SOLIDUS (/)
2687 // Set the temporary buffer to the empty string. Switch to the script data
2688 // double escape end state. Emit a U+002F SOLIDUS character token.
2689 if (cc === CC_SOLIDUS) {
2690 scriptMatch = 0;
2691 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPE_END;
2692 pos++;
2693 } else {
2694 // Anything else
2695 // Reconsume in the script data double escaped state.
2696 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED;
2697 // Reconsume
2698 }
2699 break;
2700
2701 // https://html.spec.whatwg.org/multipage/parsing.html#script-data-double-escape-end-state
2702 case STATE_SCRIPT_DATA_DOUBLE_ESCAPE_END:
2703 // Consume the next input character:
2704 // U+0009 CHARACTER TABULATION (tab)
2705 // U+000A LINE FEED (LF)
2706 // U+000C FORM FEED (FF)
2707 // U+0020 SPACE
2708 // U+002F SOLIDUS (/)
2709 // U+003E GREATER-THAN SIGN (>)
2710 // If the temporary buffer is the string "script", then switch to the script
2711 // data escaped state. Otherwise, switch to the script data double escaped
2712 // state. Emit the current input character as a character token.
2713 if (isSpace(cc) || cc === CC_SOLIDUS || cc === CC_GREATER_THAN) {
2714 state =
2715 scriptMatch === 6
2716 ? STATE_SCRIPT_DATA_ESCAPED
2717 : STATE_SCRIPT_DATA_DOUBLE_ESCAPED;
2718 pos++;
2719 } else if (isAsciiUpperAlpha(cc) || isAsciiLowerAlpha(cc)) {
2720 // ASCII alpha — advance the `"script"` match counter if the
2721 // lowercase form matches the next expected char, otherwise
2722 // snap to the sentinel so further chars can't revive a
2723 // match. No buffer allocation.
2724 const lower = isAsciiUpperAlpha(cc) ? cc + 0x20 : cc;
2725 if (scriptMatch < 6 && lower === "script".charCodeAt(scriptMatch)) {
2726 scriptMatch++;
2727 } else {
2728 scriptMatch = 7;
2729 }
2730 pos++;
2731 } else {
2732 // Anything else
2733 // Reconsume in the script data double escaped state.
2734 state = STATE_SCRIPT_DATA_DOUBLE_ESCAPED;
2735 // Reconsume
2736 }
2737 break;
2738
2739 // https://html.spec.whatwg.org/multipage/parsing.html#plaintext-state
2740 case STATE_PLAINTEXT:
2741 // Consume the next input character:
2742 // Anything else
2743 // Emit the current input character as a character token.
2744 pos++;
2745 break;
2746
2747 // https://html.spec.whatwg.org/multipage/parsing.html#character-reference-state
2748 case STATE_CHARACTER_REFERENCE:
2749 // Set the temporary buffer to the empty string. Append a U+0026
2750 // AMPERSAND (&) character to the temporary buffer.
2751 // Consume the next input character:
2752 if (isAsciiAlphanumeric(cc)) {
2753 // ASCII alphanumeric
2754 // Reconsume in the named character reference state.
2755 state = STATE_NAMED_CHARACTER_REFERENCE;
2756 // Reconsume
2757 } else if (cc === CC_NUMBER_SIGN) {
2758 // U+0023 NUMBER SIGN (#)
2759 // Append the current input character to the temporary buffer.
2760 // Switch to the numeric character reference state.
2761 state = STATE_NUMERIC_CHARACTER_REFERENCE;
2762 pos++;
2763 } else {
2764 // Anything else
2765 // Flush code points consumed as a character reference.
2766 // Reconsume in the return state.
2767 state = returnState;
2768 // Reconsume
2769 }
2770 break;
2771
2772 // https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
2773 case STATE_NAMED_CHARACTER_REFERENCE: {
2774 // Consume the maximum number of characters possible where the
2775 // consumed characters are one of the identifiers in the first
2776 // column of the named character references table.
2777 //
2778 // We measure the longest run of ASCII alphanumeric characters
2779 // (capped at MAX_ENTITY_NAME_LEN - 1 since the optional `;` is
2780 // handled separately), then walk that run from longest to
2781 // shortest looking for the first prefix that exists in the
2782 // entity table (with a trailing `;` if present, otherwise the
2783 // legacy bare form).
2784 let runLen = 0;
2785 while (
2786 pos + runLen < len &&
2787 isAsciiAlphanumeric(input.charCodeAt(pos + runLen)) &&
2788 runLen < MAX_ENTITY_NAME_LEN - 1
2789 ) {
2790 runLen++;
2791 }
2792 const hasSemicolon =
2793 pos + runLen < len && input.charCodeAt(pos + runLen) === CC_SEMICOLON;
2794 namedEntityConsumed = 0;
2795 for (let n = runLen; n > 0; n--) {
2796 // Try with trailing `;` first if one is present after the run.
2797 if (n === runLen && hasSemicolon) {
2798 const withSemi = `${input.slice(pos, pos + n)};`;
2799 if (HTML_ENTITIES[withSemi] !== undefined) {
2800 namedEntityConsumed = n + 1;
2801 break;
2802 }
2803 }
2804 const bare = input.slice(pos, pos + n);
2805 if (HTML_ENTITIES[bare] !== undefined) {
2806 namedEntityConsumed = n;
2807 break;
2808 }
2809 }
2810 if (namedEntityConsumed > 0) {
2811 pos += namedEntityConsumed;
2812 state = returnState;
2813 } else {
2814 // No match — flush code points consumed as a character
2815 // reference. Switch to the ambiguous ampersand state.
2816 state = STATE_AMBIGUOUS_AMPERSAND;
2817 }
2818 break;
2819 }
2820
2821 // https://html.spec.whatwg.org/multipage/parsing.html#ambiguous-ampersand-state
2822 case STATE_AMBIGUOUS_AMPERSAND:
2823 // Consume the next input character:
2824 if (isAsciiAlphanumeric(cc)) {
2825 // ASCII alphanumeric
2826 // If the character reference was consumed as part of an
2827 // attribute, then append the current input character to the
2828 // current attribute's value. Otherwise, emit the current
2829 // input character as a character token.
2830 pos++;
2831 } else if (cc === CC_SEMICOLON) {
2832 // U+003B SEMICOLON (;)
2833 // This is an unknown-named-character-reference parse error.
2834 // Reconsume in the return state.
2835 reportError(
2836 "unknown-named-character-reference",
2837 pos,
2838 pos + 1,
2839 "warning"
2840 );
2841 state = returnState;
2842 // Reconsume
2843 } else {
2844 // Anything else
2845 // Reconsume in the return state.
2846 state = returnState;
2847 // Reconsume
2848 }
2849 break;
2850
2851 // https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-state
2852 case STATE_NUMERIC_CHARACTER_REFERENCE:
2853 // Set the character reference code to zero (0).
2854 // Consume the next input character:
2855 if (cc === 0x78 || cc === 0x58) {
2856 // U+0078 LATIN SMALL LETTER X
2857 // U+0058 LATIN CAPITAL LETTER X
2858 // Append the current input character to the temporary
2859 // buffer. Switch to the hexadecimal character reference
2860 // start state.
2861 state = STATE_HEXADECIMAL_CHARACTER_REFERENCE_START;
2862 pos++;
2863 } else {
2864 // Anything else
2865 // Reconsume in the decimal character reference start state.
2866 state = STATE_DECIMAL_CHARACTER_REFERENCE_START;
2867 // Reconsume
2868 }
2869 break;
2870
2871 // https://html.spec.whatwg.org/multipage/parsing.html#hexadecimal-character-reference-start-state
2872 case STATE_HEXADECIMAL_CHARACTER_REFERENCE_START:
2873 // Consume the next input character:
2874 // ASCII hex digit: reconsume in the hexadecimal character reference state.
2875 // Anything else: absence-of-digits-in-numeric-character-reference parse
2876 // error. Flush code points consumed as a character reference. Reconsume
2877 // in the return state.
2878 if (isAsciiHexDigit(cc)) {
2879 state = STATE_HEXADECIMAL_CHARACTER_REFERENCE;
2880 } else {
2881 reportError(
2882 "absence-of-digits-in-numeric-character-reference",
2883 pos,
2884 pos + 1,
2885 "warning"
2886 );
2887 state = returnState;
2888 }
2889 // Reconsume
2890 break;
2891
2892 // https://html.spec.whatwg.org/multipage/parsing.html#decimal-character-reference-start-state
2893 case STATE_DECIMAL_CHARACTER_REFERENCE_START:
2894 // Consume the next input character:
2895 // ASCII digit: reconsume in the decimal character reference state.
2896 // Anything else: absence-of-digits-in-numeric-character-reference parse
2897 // error. Flush code points consumed as a character reference. Reconsume
2898 // in the return state.
2899 if (isAsciiDigit(cc)) {
2900 state = STATE_DECIMAL_CHARACTER_REFERENCE;
2901 } else {
2902 reportError(
2903 "absence-of-digits-in-numeric-character-reference",
2904 pos,
2905 pos + 1,
2906 "warning"
2907 );
2908 state = returnState;
2909 }
2910 // Reconsume
2911 break;
2912
2913 // https://html.spec.whatwg.org/multipage/parsing.html#hexadecimal-character-reference-state
2914 case STATE_HEXADECIMAL_CHARACTER_REFERENCE:
2915 // Consume the next input character:
2916 if (isAsciiHexDigit(cc)) {
2917 // ASCII digit / upper hex / lower hex
2918 // Multiply the character reference code by 16. Add a numeric
2919 // version of the current input character to the character
2920 // reference code.
2921 pos++;
2922 } else if (cc === CC_SEMICOLON) {
2923 // U+003B SEMICOLON
2924 // Switch to the numeric character reference end state.
2925 state = STATE_NUMERIC_CHARACTER_REFERENCE_END;
2926 pos++;
2927 } else {
2928 // Anything else
2929 // This is a missing-semicolon-after-character-reference
2930 // parse error. Reconsume in the numeric character reference
2931 // end state.
2932 reportError(
2933 "missing-semicolon-after-character-reference",
2934 pos,
2935 pos + 1,
2936 "warning"
2937 );
2938 state = STATE_NUMERIC_CHARACTER_REFERENCE_END;
2939 // Reconsume
2940 }
2941 break;
2942
2943 // https://html.spec.whatwg.org/multipage/parsing.html#decimal-character-reference-state
2944 case STATE_DECIMAL_CHARACTER_REFERENCE:
2945 // Consume the next input character:
2946 if (isAsciiDigit(cc)) {
2947 // ASCII digit
2948 // Multiply the character reference code by 10. Add a numeric
2949 // version of the current input character (subtract 0x0030
2950 // from the character's code point) to the character reference
2951 // code.
2952 pos++;
2953 } else if (cc === CC_SEMICOLON) {
2954 // U+003B SEMICOLON
2955 // Switch to the numeric character reference end state.
2956 state = STATE_NUMERIC_CHARACTER_REFERENCE_END;
2957 pos++;
2958 } else {
2959 // Anything else
2960 // This is a missing-semicolon-after-character-reference
2961 // parse error. Reconsume in the numeric character reference
2962 // end state.
2963 reportError(
2964 "missing-semicolon-after-character-reference",
2965 pos,
2966 pos + 1,
2967 "warning"
2968 );
2969 state = STATE_NUMERIC_CHARACTER_REFERENCE_END;
2970 // Reconsume
2971 }
2972 break;
2973
2974 // https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
2975 case STATE_NUMERIC_CHARACTER_REFERENCE_END:
2976 // Check the character reference code (validation omitted for
2977 // the scanner — we don't decode, just skip past the entity).
2978 // Flush code points consumed as a character reference.
2979 // Switch to the return state.
2980 state = returnState;
2981 // Reconsume
2982 break;
2983
2984 /* istanbul ignore next -- @preserve: defensive fallback, all states are explicit above */
2985 default:
2986 pos++;
2987 }
2988 }
2989
2990 // Handle EOF in non-data states per the WHATWG spec.
2991 //
2992 // Each in-progress comment / doctype / cdata / tag emits its partial
2993 // token range plus a corresponding `eof-in-X` parse error. Severity is
2994 // `"error"` because the emitted token offset range is incomplete (missing
2995 // trailing `-->`, `>`, `]]>`, etc.). For data / `<` / `</` / `<!`-only
2996 // inputs we emit `eof-before-tag-name` and fall through to flush the
2997 // pending text span (which still contains the lone `<`).
2998 // If EOF caught us inside a character-reference state, flush whatever the
2999 // scanner had consumed and resume in the return state so any in-progress
3000 // tag/comment is handled correctly by the branches below.
3001 if (
3002 state >= STATE_CHARACTER_REFERENCE &&
3003 state <= STATE_NUMERIC_CHARACTER_REFERENCE_END
3004 ) {
3005 state = returnState;
3006 }
3007
3008 if (
3009 (state >= STATE_TAG_NAME && state <= STATE_SELF_CLOSING_START_TAG) ||
3010 state === STATE_RCDATA_END_TAG_NAME ||
3011 state === STATE_RAWTEXT_END_TAG_NAME ||
3012 state === STATE_SCRIPT_DATA_END_TAG_NAME ||
3013 state === STATE_SCRIPT_DATA_ESCAPED_END_TAG_NAME
3014 ) {
3015 // EOF mid-tag — emit the partial open/close tag at EOF so the
3016 // consumer still sees the tag. This is a deliberate deviation
3017 // from the spec's per-character emission model: rather than
3018 // dropping the in-progress tag, we emit its offset range up to EOF.
3019 reportError("eof-in-tag", len, len, "error");
3020 // If we hit EOF mid-attribute-name, the name runs to EOF. Set
3021 // attrNameEnd here so the emitted attribute range is valid.
3022 if (state === STATE_ATTRIBUTE_NAME && attrNameStart !== -1) {
3023 attrNameEnd = len;
3024 }
3025 if (attrNameStart !== -1) emitAttribute(len);
3026 // If we hit EOF before the tag-name end was recorded, the name runs
3027 // to EOF. `tagNameEnd` may carry over from a previously emitted tag,
3028 // so reset it whenever it's missing or stale (less than `tagNameStart`)
3029 // — covers `<div` open-tag EOFs as well as `<title>x</tit` and other
3030 // content-mode end-tag-name EOFs.
3031 if (tagNameStart !== -1 && tagNameEnd < tagNameStart) {
3032 tagNameEnd = len;
3033 }
3034 flushText(tagStart);
3035 pos =
3036 input.charCodeAt(tagStart + 1) === CC_SOLIDUS
3037 ? emitCloseTag(len)
3038 : emitOpenTag(len, false);
3039 } else if (
3040 (state >= STATE_COMMENT_START && state <= STATE_BOGUS_COMMENT) ||
3041 (state >= STATE_COMMENT_LESS_THAN_SIGN &&
3042 state <= STATE_COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH) ||
3043 state === STATE_MARKUP_DECLARATION_OPEN
3044 ) {
3045 // Bogus comments at EOF are normal per spec (no parse error).
3046 if (state !== STATE_BOGUS_COMMENT) {
3047 reportError("eof-in-comment", len, len, "error");
3048 }
3049 if (callbacks.comment !== undefined) {
3050 pos = callbacks.comment(input, commentStart, len);
3051 }
3052 } else if (state >= STATE_CDATA_SECTION && state <= STATE_CDATA_SECTION_END) {
3053 reportError("eof-in-cdata", len, len, "error");
3054 if (callbacks.comment !== undefined) {
3055 pos = callbacks.comment(input, commentStart, len);
3056 }
3057 } else if (state >= STATE_DOCTYPE && state <= STATE_BOGUS_DOCTYPE) {
3058 reportError("eof-in-doctype", len, len, "error");
3059 if (callbacks.doctype !== undefined) {
3060 pos = callbacks.doctype(input, commentStart, len);
3061 }
3062 } else {
3063 if (
3064 state === STATE_SCRIPT_DATA_ESCAPED ||
3065 state === STATE_SCRIPT_DATA_ESCAPED_DASH ||
3066 state === STATE_SCRIPT_DATA_ESCAPED_DASH_DASH ||
3067 state === STATE_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN ||
3068 state === STATE_SCRIPT_DATA_DOUBLE_ESCAPED ||
3069 state === STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH ||
3070 state === STATE_SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH ||
3071 state === STATE_SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN ||
3072 state === STATE_SCRIPT_DATA_DOUBLE_ESCAPE_END
3073 ) {
3074 // Inside `<script><!-- … ` at EOF — spec calls this an
3075 // eof-in-script-html-comment-like-text parse error. The
3076 // less-than-sign and double-escape-end states reconsume back
3077 // into the (double-)escaped state on EOF per spec, which then
3078 // hits this same error.
3079 reportError("eof-in-script-html-comment-like-text", len, len, "error");
3080 } else if (state === STATE_TAG_OPEN || state === STATE_END_TAG_OPEN) {
3081 // `<` or `</` with nothing after; spec calls this
3082 // eof-before-tag-name. The lone `<` / `</` is preserved in the
3083 // pending text span which is flushed below.
3084 reportError("eof-before-tag-name", len, len, "warning");
3085 }
3086 if (textStart < len && callbacks.text !== undefined) {
3087 callbacks.text(input, textStart, len);
3088 }
3089 }
3090
3091 return pos;
3092};
3093
3094walkHtmlTokens.QUOTE_NONE = QUOTE_NONE;
3095walkHtmlTokens.QUOTE_SINGLE = QUOTE_SINGLE;
3096walkHtmlTokens.QUOTE_DOUBLE = QUOTE_DOUBLE;
3097
3098// WHATWG numeric-character-reference-end Windows-1252 remap table for the
3099// 0x80-0x9F range. Per spec these C1 control code points decode to the
3100// corresponding Windows-1252 glyph (with a parse error) rather than to the
3101// raw C1 control character.
3102const NUMERIC_C1_REMAP = {
3103 0x80: "€",
3104 0x82: "‚",
3105 0x83: "ƒ",
3106 0x84: "„",
3107 0x85: "…",
3108 0x86: "†",
3109 0x87: "‡",
3110 0x88: "ˆ",
3111 0x89: "‰",
3112 0x8a: "Š",
3113 0x8b: "‹",
3114 0x8c: "Œ",
3115 0x8e: "Ž",
3116 0x91: "‘",
3117 0x92: "’",
3118 0x93: "“",
3119 0x94: "”",
3120 0x95: "•",
3121 0x96: "–",
3122 0x97: "—",
3123 0x98: "˜",
3124 0x99: "™",
3125 0x9a: "š",
3126 0x9b: "›",
3127 0x9c: "œ",
3128 0x9e: "ž",
3129 0x9f: "Ÿ"
3130};
3131
3132/**
3133 * @param {number} code numeric character reference code point
3134 * @returns {string} decoded character per WHATWG remap rules
3135 */
3136const decodeNumericReference = (code) => {
3137 // Per WHATWG numeric-character-reference-end-state:
3138 // - 0x00, > 0x10FFFF, or surrogate (0xD800-0xDFFF) -> U+FFFD.
3139 // - 0x80-0x9F -> Windows-1252 remap (above).
3140 // - Anything else (including noncharacters and C0 controls) -> the
3141 // code point itself; we don't surface the spec's parse-error
3142 // classes here since decoding is happening after the scanner ran.
3143 if (code === 0 || code > 0x10ffff || (code >= 0xd800 && code <= 0xdfff)) {
3144 return "�";
3145 }
3146 if (code >= 0x80 && code <= 0x9f) {
3147 const remapped = /** @type {Record<number, string>} */ (NUMERIC_C1_REMAP)[
3148 code
3149 ];
3150 if (remapped !== undefined) return remapped;
3151 }
3152 return String.fromCodePoint(code);
3153};
3154
3155/**
3156 * Decode HTML character references in a string. Handles all numeric
3157 * references (with WHATWG remap of 0x00, surrogates, out-of-range, and the
3158 * C1 Windows-1252 table) and the full WHATWG named character references
3159 * table. Unknown or malformed references are left as literal text.
3160 *
3161 * When `isAttribute` is `true`, applies the WHATWG
3162 * "consumed-as-part-of-an-attribute" rule: a named reference without a
3163 * trailing `;` whose next character is `=` or ASCII alphanumeric is left
3164 * undecoded, so e.g. `&amp=foo` stays literal in an attribute value but
3165 * decodes to `&=foo` in text.
3166 * @param {string} str the raw string from the token slice
3167 * @param {boolean=} isAttribute true if `str` came from an attribute value
3168 * @returns {string} decoded string
3169 */
3170walkHtmlTokens.decodeHtmlEntities = (str, isAttribute) => {
3171 if (!str.includes("&")) return str;
3172
3173 // Match one of three forms (each with an optional trailing `;`):
3174 // `&#x<hex>` - hex numeric reference (requires the `x`/`X`).
3175 // `&#<dec>` - decimal numeric reference (digits only).
3176 // `&<name>` - named reference (letter followed by alphanumerics).
3177 // The three alternatives are kept separate so a decimal reference like
3178 // `&#65b` doesn't greedily eat the trailing `b` as if it were hex.
3179 return str.replace(
3180 /&(?:#[xX][0-9a-fA-F]+|#[0-9]+|[a-zA-Z][a-zA-Z0-9]*);?/g,
3181 (match, offset, source) => {
3182 // Numeric reference: &#65; or &#x41;
3183 if (match.charCodeAt(1) === 0x23 /* # */) {
3184 const lastChar = match.charAt(match.length - 1);
3185 const isHex =
3186 match.charCodeAt(2) === 0x78 || match.charCodeAt(2) === 0x58;
3187 const body = isHex
3188 ? lastChar === ";"
3189 ? match.slice(3, -1)
3190 : match.slice(3)
3191 : lastChar === ";"
3192 ? match.slice(2, -1)
3193 : match.slice(2);
3194 // The regex above guarantees at least one digit in `body`,
3195 // so `parseInt` always returns a finite number here.
3196 return decodeNumericReference(Number.parseInt(body, isHex ? 16 : 10));
3197 }
3198
3199 // Named reference. Try the full captured name first, then
3200 // progressively shorter prefixes - this handles direct matches
3201 // like `&amp;` as well as WHATWG longest-prefix semantics where
3202 // e.g. `&notpre;` decodes as `&not` (a legacy bare entity)
3203 // followed by `pre;` as literal text.
3204 const name = match.slice(1);
3205 const matchEndsWithSemi = name.charCodeAt(name.length - 1) === 0x3b;
3206
3207 // Attribute-context guard: if the entity match didn't end with `;`
3208 // and the next character in the source is `=` or ASCII
3209 // alphanumeric, the WHATWG spec says to flush the literal text
3210 // rather than decode. The greedy regex already absorbed any
3211 // trailing alphanumerics, so the only candidate "next char" here
3212 // is `=` (or any non-alphanumeric).
3213 if (isAttribute && !matchEndsWithSemi) {
3214 const after = source.charCodeAt(offset + match.length);
3215 if (after === 0x3d /* = */) return match;
3216 }
3217
3218 // Cap the longest-prefix search at MAX_ENTITY_NAME_LEN so pathological
3219 // inputs like `&` + thousands of alphanumerics stay linear-time.
3220 // Anything past that cap can't possibly match and is appended
3221 // verbatim as part of `name.slice(i)`.
3222 const searchLen =
3223 name.length > MAX_ENTITY_NAME_LEN ? MAX_ENTITY_NAME_LEN : name.length;
3224 for (let i = searchLen; i > 0; i--) {
3225 const prefix = name.slice(0, i);
3226 if (HTML_ENTITIES[prefix] !== undefined) {
3227 // Attribute-context longest-prefix guard: if the matched
3228 // prefix doesn't end with `;` and the leftover starts with
3229 // an alphanumeric character, leave literal per WHATWG.
3230 // (The regex greedy-consumes alphanumerics, so any leftover
3231 // within `name` is itself alphanumeric — we only need to
3232 // check non-empty leftover here; the `=` case is handled
3233 // above against the source character after the match.)
3234 if (
3235 isAttribute &&
3236 i < name.length &&
3237 prefix.charCodeAt(prefix.length - 1) !== 0x3b
3238 ) {
3239 return match;
3240 }
3241 return HTML_ENTITIES[prefix] + name.slice(i);
3242 }
3243 }
3244 return match;
3245 }
3246 );
3247};
3248
3249module.exports = walkHtmlTokens;
Note: See TracBrowser for help on using the repository browser.