Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1import { ContextTracker, ExternalTokenizer, LRParser } from '@lezer/lr';
2import { styleTags, tags } from '@lezer/highlight';
3import { parseMixed } from '@lezer/common';
4
5// This file was generated by lezer-generator. You probably shouldn't edit it.
6const scriptText = 55,
7 StartCloseScriptTag = 1,
8 styleText = 56,
9 StartCloseStyleTag = 2,
10 textareaText = 57,
11 StartCloseTextareaTag = 3,
12 EndTag = 4,
13 SelfClosingEndTag = 5,
14 StartTag = 6,
15 StartScriptTag = 7,
16 StartStyleTag = 8,
17 StartTextareaTag = 9,
18 StartSelfClosingTag = 10,
19 StartCloseTag = 11,
20 NoMatchStartCloseTag = 12,
21 MismatchedStartCloseTag = 13,
22 missingCloseTag = 58,
23 IncompleteTag = 14,
24 IncompleteCloseTag = 15,
25 commentContent$1 = 59,
26 Element = 21,
27 TagName = 23,
28 Attribute = 24,
29 AttributeName = 25,
30 AttributeValue = 27,
31 UnquotedAttributeValue = 28,
32 ScriptText = 29,
33 StyleText = 32,
34 TextareaText = 35,
35 OpenTag = 37,
36 CloseTag = 38,
37 Dialect_noMatch = 0,
38 Dialect_selfClosing = 1;
39
40/* Hand-written tokenizers for HTML. */
41
42const selfClosers = {
43 area: true, base: true, br: true, col: true, command: true,
44 embed: true, frame: true, hr: true, img: true, input: true,
45 keygen: true, link: true, meta: true, param: true, source: true,
46 track: true, wbr: true, menuitem: true
47};
48
49const implicitlyClosed = {
50 dd: true, li: true, optgroup: true, option: true, p: true,
51 rp: true, rt: true, tbody: true, td: true, tfoot: true,
52 th: true, tr: true
53};
54
55const closeOnOpen = {
56 dd: {dd: true, dt: true},
57 dt: {dd: true, dt: true},
58 li: {li: true},
59 option: {option: true, optgroup: true},
60 optgroup: {optgroup: true},
61 p: {
62 address: true, article: true, aside: true, blockquote: true, dir: true,
63 div: true, dl: true, fieldset: true, footer: true, form: true,
64 h1: true, h2: true, h3: true, h4: true, h5: true, h6: true,
65 header: true, hgroup: true, hr: true, menu: true, nav: true, ol: true,
66 p: true, pre: true, section: true, table: true, ul: true
67 },
68 rp: {rp: true, rt: true},
69 rt: {rp: true, rt: true},
70 tbody: {tbody: true, tfoot: true},
71 td: {td: true, th: true},
72 tfoot: {tbody: true},
73 th: {td: true, th: true},
74 thead: {tbody: true, tfoot: true},
75 tr: {tr: true}
76};
77
78function nameChar(ch) {
79 return ch == 45 || ch == 46 || ch == 58 || ch >= 65 && ch <= 90 || ch == 95 || ch >= 97 && ch <= 122 || ch >= 161
80}
81
82let cachedName = null, cachedInput = null, cachedPos = 0;
83function tagNameAfter(input, offset) {
84 let pos = input.pos + offset;
85 if (cachedPos == pos && cachedInput == input) return cachedName
86 let next = input.peek(offset), name = "";
87 for (;;) {
88 if (!nameChar(next)) break
89 name += String.fromCharCode(next);
90 next = input.peek(++offset);
91 }
92 // Undefined to signal there's a <? or <!, null for just missing
93 cachedInput = input; cachedPos = pos;
94 return cachedName = name ? name.toLowerCase() : next == question || next == bang ? undefined : null
95}
96
97const lessThan = 60, greaterThan = 62, slash = 47, question = 63, bang = 33, dash = 45;
98
99function ElementContext(name, parent) {
100 this.name = name;
101 this.parent = parent;
102}
103
104const startTagTerms = [StartTag, StartSelfClosingTag, StartScriptTag, StartStyleTag, StartTextareaTag];
105
106const elementContext = new ContextTracker({
107 start: null,
108 shift(context, term, stack, input) {
109 return startTagTerms.indexOf(term) > -1 ? new ElementContext(tagNameAfter(input, 1) || "", context) : context
110 },
111 reduce(context, term) {
112 return term == Element && context ? context.parent : context
113 },
114 reuse(context, node, stack, input) {
115 let type = node.type.id;
116 return type == StartTag || type == OpenTag
117 ? new ElementContext(tagNameAfter(input, 1) || "", context) : context
118 },
119 strict: false
120});
121
122const tagStart = new ExternalTokenizer((input, stack) => {
123 if (input.next != lessThan) {
124 // End of file, close any open tags
125 if (input.next < 0 && stack.context) input.acceptToken(missingCloseTag);
126 return
127 }
128 input.advance();
129 let close = input.next == slash;
130 if (close) input.advance();
131 let name = tagNameAfter(input, 0);
132 if (name === undefined) return
133 if (!name) return input.acceptToken(close ? IncompleteCloseTag : IncompleteTag)
134
135 let parent = stack.context ? stack.context.name : null;
136 if (close) {
137 if (name == parent) return input.acceptToken(StartCloseTag)
138 if (parent && implicitlyClosed[parent]) return input.acceptToken(missingCloseTag, -2)
139 if (stack.dialectEnabled(Dialect_noMatch)) return input.acceptToken(NoMatchStartCloseTag)
140 for (let cx = stack.context; cx; cx = cx.parent) if (cx.name == name) return
141 input.acceptToken(MismatchedStartCloseTag);
142 } else {
143 if (name == "script") return input.acceptToken(StartScriptTag)
144 if (name == "style") return input.acceptToken(StartStyleTag)
145 if (name == "textarea") return input.acceptToken(StartTextareaTag)
146 if (selfClosers.hasOwnProperty(name)) return input.acceptToken(StartSelfClosingTag)
147 if (parent && closeOnOpen[parent] && closeOnOpen[parent][name]) input.acceptToken(missingCloseTag, -1);
148 else input.acceptToken(StartTag);
149 }
150}, {contextual: true});
151
152const commentContent = new ExternalTokenizer(input => {
153 for (let dashes = 0, i = 0;; i++) {
154 if (input.next < 0) {
155 if (i) input.acceptToken(commentContent$1);
156 break
157 }
158 if (input.next == dash) {
159 dashes++;
160 } else if (input.next == greaterThan && dashes >= 2) {
161 if (i >= 3) input.acceptToken(commentContent$1, -2);
162 break
163 } else {
164 dashes = 0;
165 }
166 input.advance();
167 }
168});
169
170function inForeignElement(context) {
171 for (; context; context = context.parent)
172 if (context.name == "svg" || context.name == "math") return true
173 return false
174}
175
176const endTag = new ExternalTokenizer((input, stack) => {
177 if (input.next == slash && input.peek(1) == greaterThan) {
178 let selfClosing = stack.dialectEnabled(Dialect_selfClosing) || inForeignElement(stack.context);
179 input.acceptToken(selfClosing ? SelfClosingEndTag : EndTag, 2);
180 } else if (input.next == greaterThan) {
181 input.acceptToken(EndTag, 1);
182 }
183});
184
185function contentTokenizer(tag, textToken, endToken) {
186 let lastState = 2 + tag.length;
187 return new ExternalTokenizer(input => {
188 // state means:
189 // - 0 nothing matched
190 // - 1 '<' matched
191 // - 2 '</'
192 // - 3-(1+tag.length) part of the tag matched
193 // - lastState whole tag + possibly whitespace matched
194 for (let state = 0, matchedLen = 0, i = 0;; i++) {
195 if (input.next < 0) {
196 if (i) input.acceptToken(textToken);
197 break
198 }
199 if (state == 0 && input.next == lessThan ||
200 state == 1 && input.next == slash ||
201 state >= 2 && state < lastState && input.next == tag.charCodeAt(state - 2)) {
202 state++;
203 matchedLen++;
204 } else if (state == lastState && input.next == greaterThan) {
205 if (i > matchedLen)
206 input.acceptToken(textToken, -matchedLen);
207 else
208 input.acceptToken(endToken, -(matchedLen - 2));
209 break
210 } else if ((input.next == 10 /* '\n' */ || input.next == 13 /* '\r' */) && i) {
211 input.acceptToken(textToken, 1);
212 break
213 } else {
214 state = matchedLen = 0;
215 }
216 input.advance();
217 }
218 })
219}
220
221const scriptTokens = contentTokenizer("script", scriptText, StartCloseScriptTag);
222
223const styleTokens = contentTokenizer("style", styleText, StartCloseStyleTag);
224
225const textareaTokens = contentTokenizer("textarea", textareaText, StartCloseTextareaTag);
226
227const htmlHighlighting = styleTags({
228 "Text RawText IncompleteTag IncompleteCloseTag": tags.content,
229 "StartTag StartCloseTag SelfClosingEndTag EndTag": tags.angleBracket,
230 TagName: tags.tagName,
231 "MismatchedCloseTag/TagName": [tags.tagName, tags.invalid],
232 AttributeName: tags.attributeName,
233 "AttributeValue UnquotedAttributeValue": tags.attributeValue,
234 Is: tags.definitionOperator,
235 "EntityReference CharacterReference": tags.character,
236 Comment: tags.blockComment,
237 ProcessingInst: tags.processingInstruction,
238 DoctypeDecl: tags.documentMeta
239});
240
241// This file was generated by lezer-generator. You probably shouldn't edit it.
242const parser = LRParser.deserialize({
243 version: 14,
244 states: ",xOVO!rOOO!ZQ#tO'#CrO!`Q#tO'#C{O!eQ#tO'#DOO!jQ#tO'#DRO!oQ#tO'#DTO!tOaO'#CqO#PObO'#CqO#[OdO'#CqO$kO!rO'#CqOOO`'#Cq'#CqO$rO$fO'#DUO$zQ#tO'#DWO%PQ#tO'#DXOOO`'#Dl'#DlOOO`'#DZ'#DZQVO!rOOO%UQ&rO,59^O%aQ&rO,59gO%lQ&rO,59jO%wQ&rO,59mO&SQ&rO,59oOOOa'#D_'#D_O&_OaO'#CyO&jOaO,59]OOOb'#D`'#D`O&rObO'#C|O&}ObO,59]OOOd'#Da'#DaO'VOdO'#DPO'bOdO,59]OOO`'#Db'#DbO'jO!rO,59]O'qQ#tO'#DSOOO`,59],59]OOOp'#Dc'#DcO'vO$fO,59pOOO`,59p,59pO(OQ#|O,59rO(TQ#|O,59sOOO`-E7X-E7XO(YQ&rO'#CtOOQW'#D['#D[O(hQ&rO1G.xOOOa1G.x1G.xOOO`1G/Z1G/ZO(sQ&rO1G/ROOOb1G/R1G/RO)OQ&rO1G/UOOOd1G/U1G/UO)ZQ&rO1G/XOOO`1G/X1G/XO)fQ&rO1G/ZOOOa-E7]-E7]O)qQ#tO'#CzOOO`1G.w1G.wOOOb-E7^-E7^O)vQ#tO'#C}OOOd-E7_-E7_O){Q#tO'#DQOOO`-E7`-E7`O*QQ#|O,59nOOOp-E7a-E7aOOO`1G/[1G/[OOO`1G/^1G/^OOO`1G/_1G/_O*VQ,UO,59`OOQW-E7Y-E7YOOOa7+$d7+$dOOO`7+$u7+$uOOOb7+$m7+$mOOOd7+$p7+$pOOO`7+$s7+$sO*bQ#|O,59fO*gQ#|O,59iO*lQ#|O,59lOOO`1G/Y1G/YO*qO7[O'#CwO+SOMhO'#CwOOQW1G.z1G.zOOO`1G/Q1G/QOOO`1G/T1G/TOOO`1G/W1G/WOOOO'#D]'#D]O+eO7[O,59cOOQW,59c,59cOOOO'#D^'#D^O+vOMhO,59cOOOO-E7Z-E7ZOOQW1G.}1G.}OOOO-E7[-E7[",
245 stateData: ",c~O!_OS~OUSOVPOWQOXROYTO[]O][O^^O_^Oa^Ob^Oc^Od^Oy^O|_O!eZO~OgaO~OgbO~OgcO~OgdO~OgeO~O!XfOPmP![mP~O!YiOQpP![pP~O!ZlORsP![sP~OUSOVPOWQOXROYTOZqO[]O][O^^O_^Oa^Ob^Oc^Od^Oy^O!eZO~O![rO~P#gO!]sO!fuO~OgvO~OgwO~OS|OT}OiyO~OS!POT}OiyO~OS!ROT}OiyO~OS!TOT}OiyO~OS}OT}OiyO~O!XfOPmX![mX~OP!WO![!XO~O!YiOQpX![pX~OQ!ZO![!XO~O!ZlORsX![sX~OR!]O![!XO~O![!XO~P#gOg!_O~O!]sO!f!aO~OS!bO~OS!cO~Oj!dOShXThXihX~OS!fOT!gOiyO~OS!hOT!gOiyO~OS!iOT!gOiyO~OS!jOT!gOiyO~OS!gOT!gOiyO~Og!kO~Og!lO~Og!mO~OS!nO~Ol!qO!a!oO!c!pO~OS!rO~OS!sO~OS!tO~Ob!uOc!uOd!uO!a!wO!b!uO~Ob!xOc!xOd!xO!c!wO!d!xO~Ob!uOc!uOd!uO!a!{O!b!uO~Ob!xOc!xOd!xO!c!{O!d!xO~OT~cbd!ey|!e~",
246 goto: "%q!aPPPPPPPPPPPPPPPPPPPPP!b!hP!nPP!zP!}#Q#T#Z#^#a#g#j#m#s#y!bP!b!bP$P$V$m$s$y%P%V%]%cPPPPPPPP%iX^OX`pXUOX`pezabcde{!O!Q!S!UR!q!dRhUR!XhXVOX`pRkVR!XkXWOX`pRnWR!XnXXOX`pQrXR!XpXYOX`pQ`ORx`Q{aQ!ObQ!QcQ!SdQ!UeZ!e{!O!Q!S!UQ!v!oR!z!vQ!y!pR!|!yQgUR!VgQjVR!YjQmWR![mQpXR!^pQtZR!`tS_O`ToXp",
247 nodeNames: "⚠ StartCloseTag StartCloseTag StartCloseTag EndTag SelfClosingEndTag StartTag StartTag StartTag StartTag StartTag StartCloseTag StartCloseTag StartCloseTag IncompleteTag IncompleteCloseTag Document Text EntityReference CharacterReference InvalidEntity Element OpenTag TagName Attribute AttributeName Is AttributeValue UnquotedAttributeValue ScriptText CloseTag OpenTag StyleText CloseTag OpenTag TextareaText CloseTag OpenTag CloseTag SelfClosingTag Comment ProcessingInst MismatchedCloseTag CloseTag DoctypeDecl",
248 maxTerm: 68,
249 context: elementContext,
250 nodeProps: [
251 ["closedBy", -10,1,2,3,7,8,9,10,11,12,13,"EndTag",6,"EndTag SelfClosingEndTag",-4,22,31,34,37,"CloseTag"],
252 ["openedBy", 4,"StartTag StartCloseTag",5,"StartTag",-4,30,33,36,38,"OpenTag"],
253 ["group", -10,14,15,18,19,20,21,40,41,42,43,"Entity",17,"Entity TextContent",-3,29,32,35,"TextContent Entity"],
254 ["isolate", -11,22,30,31,33,34,36,37,38,39,42,43,"ltr",-3,27,28,40,""]
255 ],
256 propSources: [htmlHighlighting],
257 skippedNodes: [0],
258 repeatNodeCount: 9,
259 tokenData: "!<p!aR!YOX$qXY,QYZ,QZ[$q[]&X]^,Q^p$qpq,Qqr-_rs3_sv-_vw3}wxHYx}-_}!OH{!O!P-_!P!Q$q!Q![-_![!]Mz!]!^-_!^!_!$S!_!`!;x!`!a&X!a!c-_!c!}Mz!}#R-_#R#SMz#S#T1k#T#oMz#o#s-_#s$f$q$f%W-_%W%oMz%o%p-_%p&aMz&a&b-_&b1pMz1p4U-_4U4dMz4d4e-_4e$ISMz$IS$I`-_$I`$IbMz$Ib$Kh-_$Kh%#tMz%#t&/x-_&/x&EtMz&Et&FV-_&FV;'SMz;'S;:j!#|;:j;=`3X<%l?&r-_?&r?AhMz?Ah?BY$q?BY?MnMz?MnO$q!Z$|caPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr$qrs&}sv$qvw+Pwx(tx!^$q!^!_*V!_!a&X!a#S$q#S#T&X#T;'S$q;'S;=`+z<%lO$q!R&bXaP!b`!dpOr&Xrs&}sv&Xwx(tx!^&X!^!_*V!_;'S&X;'S;=`*y<%lO&Xq'UVaP!dpOv&}wx'kx!^&}!^!_(V!_;'S&};'S;=`(n<%lO&}P'pTaPOv'kw!^'k!_;'S'k;'S;=`(P<%lO'kP(SP;=`<%l'kp([S!dpOv(Vx;'S(V;'S;=`(h<%lO(Vp(kP;=`<%l(Vq(qP;=`<%l&}a({WaP!b`Or(trs'ksv(tw!^(t!^!_)e!_;'S(t;'S;=`*P<%lO(t`)jT!b`Or)esv)ew;'S)e;'S;=`)y<%lO)e`)|P;=`<%l)ea*SP;=`<%l(t!Q*^V!b`!dpOr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!Q*vP;=`<%l*V!R*|P;=`<%l&XW+UYlWOX+PZ[+P^p+Pqr+Psw+Px!^+P!a#S+P#T;'S+P;'S;=`+t<%lO+PW+wP;=`<%l+P!Z+}P;=`<%l$q!a,]`aP!b`!dp!_^OX&XXY,QYZ,QZ]&X]^,Q^p&Xpq,Qqr&Xrs&}sv&Xwx(tx!^&X!^!_*V!_;'S&X;'S;=`*y<%lO&X!_-ljiSaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx!P-_!P!Q$q!Q!^-_!^!_*V!_!a&X!a#S-_#S#T1k#T#s-_#s$f$q$f;'S-_;'S;=`3X<%l?Ah-_?Ah?BY$q?BY?Mn-_?MnO$q[/ebiSlWOX+PZ[+P^p+Pqr/^sw/^x!P/^!P!Q+P!Q!^/^!a#S/^#S#T0m#T#s/^#s$f+P$f;'S/^;'S;=`1e<%l?Ah/^?Ah?BY+P?BY?Mn/^?MnO+PS0rXiSqr0msw0mx!P0m!Q!^0m!a#s0m$f;'S0m;'S;=`1_<%l?Ah0m?BY?Mn0mS1bP;=`<%l0m[1hP;=`<%l/^!V1vciSaP!b`!dpOq&Xqr1krs&}sv1kvw0mwx(tx!P1k!P!Q&X!Q!^1k!^!_*V!_!a&X!a#s1k#s$f&X$f;'S1k;'S;=`3R<%l?Ah1k?Ah?BY&X?BY?Mn1k?MnO&X!V3UP;=`<%l1k!_3[P;=`<%l-_!Z3hV!ahaP!dpOv&}wx'kx!^&}!^!_(V!_;'S&};'S;=`(n<%lO&}!_4WiiSlWd!ROX5uXZ7SZ[5u[^7S^p5uqr8trs7Sst>]tw8twx7Sx!P8t!P!Q5u!Q!]8t!]!^/^!^!a7S!a#S8t#S#T;{#T#s8t#s$f5u$f;'S8t;'S;=`>V<%l?Ah8t?Ah?BY5u?BY?Mn8t?MnO5u!Z5zblWOX5uXZ7SZ[5u[^7S^p5uqr5urs7Sst+Ptw5uwx7Sx!]5u!]!^7w!^!a7S!a#S5u#S#T7S#T;'S5u;'S;=`8n<%lO5u!R7VVOp7Sqs7St!]7S!]!^7l!^;'S7S;'S;=`7q<%lO7S!R7qOb!R!R7tP;=`<%l7S!Z8OYlWb!ROX+PZ[+P^p+Pqr+Psw+Px!^+P!a#S+P#T;'S+P;'S;=`+t<%lO+P!Z8qP;=`<%l5u!_8{iiSlWOX5uXZ7SZ[5u[^7S^p5uqr8trs7Sst/^tw8twx7Sx!P8t!P!Q5u!Q!]8t!]!^:j!^!a7S!a#S8t#S#T;{#T#s8t#s$f5u$f;'S8t;'S;=`>V<%l?Ah8t?Ah?BY5u?BY?Mn8t?MnO5u!_:sbiSlWb!ROX+PZ[+P^p+Pqr/^sw/^x!P/^!P!Q+P!Q!^/^!a#S/^#S#T0m#T#s/^#s$f+P$f;'S/^;'S;=`1e<%l?Ah/^?Ah?BY+P?BY?Mn/^?MnO+P!V<QciSOp7Sqr;{rs7Sst0mtw;{wx7Sx!P;{!P!Q7S!Q!];{!]!^=]!^!a7S!a#s;{#s$f7S$f;'S;{;'S;=`>P<%l?Ah;{?Ah?BY7S?BY?Mn;{?MnO7S!V=dXiSb!Rqr0msw0mx!P0m!Q!^0m!a#s0m$f;'S0m;'S;=`1_<%l?Ah0m?BY?Mn0m!V>SP;=`<%l;{!_>YP;=`<%l8t!_>dhiSlWOX@OXZAYZ[@O[^AY^p@OqrBwrsAYswBwwxAYx!PBw!P!Q@O!Q!]Bw!]!^/^!^!aAY!a#SBw#S#TE{#T#sBw#s$f@O$f;'SBw;'S;=`HS<%l?AhBw?Ah?BY@O?BY?MnBw?MnO@O!Z@TalWOX@OXZAYZ[@O[^AY^p@Oqr@OrsAYsw@OwxAYx!]@O!]!^Az!^!aAY!a#S@O#S#TAY#T;'S@O;'S;=`Bq<%lO@O!RA]UOpAYq!]AY!]!^Ao!^;'SAY;'S;=`At<%lOAY!RAtOc!R!RAwP;=`<%lAY!ZBRYlWc!ROX+PZ[+P^p+Pqr+Psw+Px!^+P!a#S+P#T;'S+P;'S;=`+t<%lO+P!ZBtP;=`<%l@O!_COhiSlWOX@OXZAYZ[@O[^AY^p@OqrBwrsAYswBwwxAYx!PBw!P!Q@O!Q!]Bw!]!^Dj!^!aAY!a#SBw#S#TE{#T#sBw#s$f@O$f;'SBw;'S;=`HS<%l?AhBw?Ah?BY@O?BY?MnBw?MnO@O!_DsbiSlWc!ROX+PZ[+P^p+Pqr/^sw/^x!P/^!P!Q+P!Q!^/^!a#S/^#S#T0m#T#s/^#s$f+P$f;'S/^;'S;=`1e<%l?Ah/^?Ah?BY+P?BY?Mn/^?MnO+P!VFQbiSOpAYqrE{rsAYswE{wxAYx!PE{!P!QAY!Q!]E{!]!^GY!^!aAY!a#sE{#s$fAY$f;'SE{;'S;=`G|<%l?AhE{?Ah?BYAY?BY?MnE{?MnOAY!VGaXiSc!Rqr0msw0mx!P0m!Q!^0m!a#s0m$f;'S0m;'S;=`1_<%l?Ah0m?BY?Mn0m!VHPP;=`<%lE{!_HVP;=`<%lBw!ZHcW!cxaP!b`Or(trs'ksv(tw!^(t!^!_)e!_;'S(t;'S;=`*P<%lO(t!aIYliSaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx}-_}!OKQ!O!P-_!P!Q$q!Q!^-_!^!_*V!_!a&X!a#S-_#S#T1k#T#s-_#s$f$q$f;'S-_;'S;=`3X<%l?Ah-_?Ah?BY$q?BY?Mn-_?MnO$q!aK_kiSaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx!P-_!P!Q$q!Q!^-_!^!_*V!_!`&X!`!aMS!a#S-_#S#T1k#T#s-_#s$f$q$f;'S-_;'S;=`3X<%l?Ah-_?Ah?BY$q?BY?Mn-_?MnO$q!TM_XaP!b`!dp!fQOr&Xrs&}sv&Xwx(tx!^&X!^!_*V!_;'S&X;'S;=`*y<%lO&X!aNZ!ZiSgQaPlW!b`!dpOX$qXZ&XZ[$q[^&X^p$qpq&Xqr-_rs&}sv-_vw/^wx(tx}-_}!OMz!O!PMz!P!Q$q!Q![Mz![!]Mz!]!^-_!^!_*V!_!a&X!a!c-_!c!}Mz!}#R-_#R#SMz#S#T1k#T#oMz#o#s-_#s$f$q$f$}-_$}%OMz%O%W-_%W%oMz%o%p-_%p&aMz&a&b-_&b1pMz1p4UMz4U4dMz4d4e-_4e$ISMz$IS$I`-_$I`$IbMz$Ib$Je-_$Je$JgMz$Jg$Kh-_$Kh%#tMz%#t&/x-_&/x&EtMz&Et&FV-_&FV;'SMz;'S;:j!#|;:j;=`3X<%l?&r-_?&r?AhMz?Ah?BY$q?BY?MnMz?MnO$q!a!$PP;=`<%lMz!R!$ZY!b`!dpOq*Vqr!$yrs(Vsv*Vwx)ex!a*V!a!b!4t!b;'S*V;'S;=`*s<%lO*V!R!%Q]!b`!dpOr*Vrs(Vsv*Vwx)ex}*V}!O!%y!O!f*V!f!g!']!g#W*V#W#X!0`#X;'S*V;'S;=`*s<%lO*V!R!&QX!b`!dpOr*Vrs(Vsv*Vwx)ex}*V}!O!&m!O;'S*V;'S;=`*s<%lO*V!R!&vV!b`!dp!ePOr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!R!'dX!b`!dpOr*Vrs(Vsv*Vwx)ex!q*V!q!r!(P!r;'S*V;'S;=`*s<%lO*V!R!(WX!b`!dpOr*Vrs(Vsv*Vwx)ex!e*V!e!f!(s!f;'S*V;'S;=`*s<%lO*V!R!(zX!b`!dpOr*Vrs(Vsv*Vwx)ex!v*V!v!w!)g!w;'S*V;'S;=`*s<%lO*V!R!)nX!b`!dpOr*Vrs(Vsv*Vwx)ex!{*V!{!|!*Z!|;'S*V;'S;=`*s<%lO*V!R!*bX!b`!dpOr*Vrs(Vsv*Vwx)ex!r*V!r!s!*}!s;'S*V;'S;=`*s<%lO*V!R!+UX!b`!dpOr*Vrs(Vsv*Vwx)ex!g*V!g!h!+q!h;'S*V;'S;=`*s<%lO*V!R!+xY!b`!dpOr!+qrs!,hsv!+qvw!-Swx!.[x!`!+q!`!a!/j!a;'S!+q;'S;=`!0Y<%lO!+qq!,mV!dpOv!,hvx!-Sx!`!,h!`!a!-q!a;'S!,h;'S;=`!.U<%lO!,hP!-VTO!`!-S!`!a!-f!a;'S!-S;'S;=`!-k<%lO!-SP!-kO|PP!-nP;=`<%l!-Sq!-xS!dp|POv(Vx;'S(V;'S;=`(h<%lO(Vq!.XP;=`<%l!,ha!.aX!b`Or!.[rs!-Ssv!.[vw!-Sw!`!.[!`!a!.|!a;'S!.[;'S;=`!/d<%lO!.[a!/TT!b`|POr)esv)ew;'S)e;'S;=`)y<%lO)ea!/gP;=`<%l!.[!R!/sV!b`!dp|POr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!R!0]P;=`<%l!+q!R!0gX!b`!dpOr*Vrs(Vsv*Vwx)ex#c*V#c#d!1S#d;'S*V;'S;=`*s<%lO*V!R!1ZX!b`!dpOr*Vrs(Vsv*Vwx)ex#V*V#V#W!1v#W;'S*V;'S;=`*s<%lO*V!R!1}X!b`!dpOr*Vrs(Vsv*Vwx)ex#h*V#h#i!2j#i;'S*V;'S;=`*s<%lO*V!R!2qX!b`!dpOr*Vrs(Vsv*Vwx)ex#m*V#m#n!3^#n;'S*V;'S;=`*s<%lO*V!R!3eX!b`!dpOr*Vrs(Vsv*Vwx)ex#d*V#d#e!4Q#e;'S*V;'S;=`*s<%lO*V!R!4XX!b`!dpOr*Vrs(Vsv*Vwx)ex#X*V#X#Y!+q#Y;'S*V;'S;=`*s<%lO*V!R!4{Y!b`!dpOr!4trs!5ksv!4tvw!6Vwx!8]x!a!4t!a!b!:]!b;'S!4t;'S;=`!;r<%lO!4tq!5pV!dpOv!5kvx!6Vx!a!5k!a!b!7W!b;'S!5k;'S;=`!8V<%lO!5kP!6YTO!a!6V!a!b!6i!b;'S!6V;'S;=`!7Q<%lO!6VP!6lTO!`!6V!`!a!6{!a;'S!6V;'S;=`!7Q<%lO!6VP!7QOyPP!7TP;=`<%l!6Vq!7]V!dpOv!5kvx!6Vx!`!5k!`!a!7r!a;'S!5k;'S;=`!8V<%lO!5kq!7yS!dpyPOv(Vx;'S(V;'S;=`(h<%lO(Vq!8YP;=`<%l!5ka!8bX!b`Or!8]rs!6Vsv!8]vw!6Vw!a!8]!a!b!8}!b;'S!8];'S;=`!:V<%lO!8]a!9SX!b`Or!8]rs!6Vsv!8]vw!6Vw!`!8]!`!a!9o!a;'S!8];'S;=`!:V<%lO!8]a!9vT!b`yPOr)esv)ew;'S)e;'S;=`)y<%lO)ea!:YP;=`<%l!8]!R!:dY!b`!dpOr!4trs!5ksv!4tvw!6Vwx!8]x!`!4t!`!a!;S!a;'S!4t;'S;=`!;r<%lO!4t!R!;]V!b`!dpyPOr*Vrs(Vsv*Vwx)ex;'S*V;'S;=`*s<%lO*V!R!;uP;=`<%l!4t!V!<TXjSaP!b`!dpOr&Xrs&}sv&Xwx(tx!^&X!^!_*V!_;'S&X;'S;=`*y<%lO&X",
260 tokenizers: [scriptTokens, styleTokens, textareaTokens, endTag, tagStart, commentContent, 0, 1, 2, 3, 4, 5],
261 topRules: {"Document":[0,16]},
262 dialects: {noMatch: 0, selfClosing: 515},
263 tokenPrec: 517
264});
265
266function getAttrs(openTag, input) {
267 let attrs = Object.create(null);
268 for (let att of openTag.getChildren(Attribute)) {
269 let name = att.getChild(AttributeName), value = att.getChild(AttributeValue) || att.getChild(UnquotedAttributeValue);
270 if (name) attrs[input.read(name.from, name.to)] =
271 !value ? "" : value.type.id == AttributeValue ? input.read(value.from + 1, value.to - 1) : input.read(value.from, value.to);
272 }
273 return attrs
274}
275
276function findTagName(openTag, input) {
277 let tagNameNode = openTag.getChild(TagName);
278 return tagNameNode ? input.read(tagNameNode.from, tagNameNode.to) : " "
279}
280
281function maybeNest(node, input, tags) {
282 let attrs;
283 for (let tag of tags) {
284 if (!tag.attrs || tag.attrs(attrs || (attrs = getAttrs(node.node.parent.firstChild, input))))
285 return {parser: tag.parser, bracketed: true}
286 }
287 return null
288}
289
290// tags?: {
291// tag: string,
292// attrs?: ({[attr: string]: string}) => boolean,
293// parser: Parser
294// }[]
295// attributes?: {
296// name: string,
297// tagName?: string,
298// parser: Parser
299// }[]
300
301function configureNesting(tags = [], attributes = []) {
302 let script = [], style = [], textarea = [], other = [];
303 for (let tag of tags) {
304 let array = tag.tag == "script" ? script : tag.tag == "style" ? style : tag.tag == "textarea" ? textarea : other;
305 array.push(tag);
306 }
307 let attrs = attributes.length ? Object.create(null) : null;
308 for (let attr of attributes) (attrs[attr.name] || (attrs[attr.name] = [])).push(attr);
309
310 return parseMixed((node, input) => {
311 let id = node.type.id;
312 if (id == ScriptText) return maybeNest(node, input, script)
313 if (id == StyleText) return maybeNest(node, input, style)
314 if (id == TextareaText) return maybeNest(node, input, textarea)
315
316 if (id == Element && other.length) {
317 let n = node.node, open = n.firstChild, tagName = open && findTagName(open, input), attrs;
318 if (tagName) for (let tag of other) {
319 if (tag.tag == tagName && (!tag.attrs || tag.attrs(attrs || (attrs = getAttrs(open, input))))) {
320 let close = n.lastChild;
321 let to = close.type.id == CloseTag ? close.from : n.to;
322 if (to > open.to)
323 return {parser: tag.parser, overlay: [{from: open.to, to}]}
324 }
325 }
326 }
327
328 if (attrs && id == Attribute) {
329 let n = node.node, nameNode;
330 if (nameNode = n.firstChild) {
331 let matches = attrs[input.read(nameNode.from, nameNode.to)];
332 if (matches) for (let attr of matches) {
333 if (attr.tagName && attr.tagName != findTagName(n.parent, input)) continue
334 let value = n.lastChild;
335 if (value.type.id == AttributeValue) {
336 let from = value.from + 1;
337 let last = value.lastChild, to = value.to - (last && last.isError ? 0 : 1);
338 if (to > from) return {parser: attr.parser, overlay: [{from, to}], bracketed: true}
339 } else if (value.type.id == UnquotedAttributeValue) {
340 return {parser: attr.parser, overlay: [{from: value.from, to: value.to}]}
341 }
342 }
343 }
344 }
345 return null
346 })
347}
348
349export { configureNesting, parser };