@readme/markdown 14.10.1 → 14.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3568 @@
1
+ /******/ (() => { // webpackBootstrap
2
+ /******/ "use strict";
3
+ /******/ // The require scope
4
+ /******/ var __webpack_require__ = {};
5
+ /******/
6
+ /************************************************************************/
7
+ /******/ /* webpack/runtime/define property getters */
8
+ /******/ (() => {
9
+ /******/ // define getter functions for harmony exports
10
+ /******/ __webpack_require__.d = (exports, definition) => {
11
+ /******/ for(var key in definition) {
12
+ /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13
+ /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14
+ /******/ }
15
+ /******/ }
16
+ /******/ };
17
+ /******/ })();
18
+ /******/
19
+ /******/ /* webpack/runtime/hasOwnProperty shorthand */
20
+ /******/ (() => {
21
+ /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
22
+ /******/ })();
23
+ /******/
24
+ /******/ /* webpack/runtime/make namespace object */
25
+ /******/ (() => {
26
+ /******/ // define __esModule on exports
27
+ /******/ __webpack_require__.r = (exports) => {
28
+ /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
29
+ /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30
+ /******/ }
31
+ /******/ Object.defineProperty(exports, '__esModule', { value: true });
32
+ /******/ };
33
+ /******/ })();
34
+ /******/
35
+ /************************************************************************/
36
+ var __webpack_exports__ = {};
37
+ // ESM COMPAT FLAG
38
+ __webpack_require__.r(__webpack_exports__);
39
+
40
+ // EXPORTS
41
+ __webpack_require__.d(__webpack_exports__, {
42
+ diff: () => (/* reexport */ diff)
43
+ });
44
+
45
+ ;// external "node:crypto"
46
+ const external_node_crypto_namespaceObject = require("node:crypto");
47
+ ;// ./node_modules/domelementtype/dist/index.js
48
+ /** Types of elements found in htmlparser2's DOM */
49
+ var ElementType;
50
+ (function (ElementType) {
51
+ /** Type for the root element of a document */
52
+ ElementType["Root"] = "root";
53
+ /** Type for Text */
54
+ ElementType["Text"] = "text";
55
+ /** Type for <? ... ?> */
56
+ ElementType["Directive"] = "directive";
57
+ /** Type for <!-- ... --> */
58
+ ElementType["Comment"] = "comment";
59
+ /** Type for <script> tags */
60
+ ElementType["Script"] = "script";
61
+ /** Type for <style> tags */
62
+ ElementType["Style"] = "style";
63
+ /** Type for Any tag */
64
+ ElementType["Tag"] = "tag";
65
+ /** Type for <![CDATA[ ... ]]> */
66
+ ElementType["CDATA"] = "cdata";
67
+ /** Type for <!doctype ...> */
68
+ ElementType["Doctype"] = "doctype";
69
+ })(ElementType || (ElementType = {}));
70
+ /**
71
+ * Tests whether an element is a tag or not.
72
+ * @param element Element to test
73
+ * @param element.type Node type discriminator to check.
74
+ */
75
+ function isTag(element) {
76
+ return (element.type === ElementType.Tag ||
77
+ element.type === ElementType.Script ||
78
+ element.type === ElementType.Style);
79
+ }
80
+ // Exports for backwards compatibility
81
+ /** Type for the root element of a document */
82
+ // eslint-disable-next-line prefer-destructuring
83
+ const Root = ElementType.Root;
84
+ /** Type for Text */
85
+ // eslint-disable-next-line prefer-destructuring
86
+ const Text = ElementType.Text;
87
+ /** Type for <? ... ?> */
88
+ // eslint-disable-next-line prefer-destructuring
89
+ const Directive = ElementType.Directive;
90
+ /** Type for <!-- ... --> */
91
+ // eslint-disable-next-line prefer-destructuring
92
+ const Comment = ElementType.Comment;
93
+ /** Type for <script> tags */
94
+ // eslint-disable-next-line prefer-destructuring
95
+ const Script = ElementType.Script;
96
+ /** Type for <style> tags */
97
+ // eslint-disable-next-line prefer-destructuring
98
+ const Style = ElementType.Style;
99
+ /** Type for Any tag */
100
+ // eslint-disable-next-line prefer-destructuring
101
+ const Tag = ElementType.Tag;
102
+ /** Type for <![CDATA[ ... ]]> */
103
+ // eslint-disable-next-line prefer-destructuring
104
+ const CDATA = ElementType.CDATA;
105
+ /** Type for <!doctype ...> */
106
+ // eslint-disable-next-line prefer-destructuring
107
+ const Doctype = ElementType.Doctype;
108
+
109
+ ;// ./node_modules/htmlparser2/node_modules/entities/dist/decode-codepoint.js
110
+ // Adapted from https://github.com/mathiasbynens/he/blob/36afe179392226cf1b6ccdb16ebbb7a5a844d93a/src/he.js#L106-L134
111
+ const decodeMap = new Map([
112
+ [0, 65_533],
113
+ // C1 Unicode control character reference replacements
114
+ [128, 8364],
115
+ [130, 8218],
116
+ [131, 402],
117
+ [132, 8222],
118
+ [133, 8230],
119
+ [134, 8224],
120
+ [135, 8225],
121
+ [136, 710],
122
+ [137, 8240],
123
+ [138, 352],
124
+ [139, 8249],
125
+ [140, 338],
126
+ [142, 381],
127
+ [145, 8216],
128
+ [146, 8217],
129
+ [147, 8220],
130
+ [148, 8221],
131
+ [149, 8226],
132
+ [150, 8211],
133
+ [151, 8212],
134
+ [152, 732],
135
+ [153, 8482],
136
+ [154, 353],
137
+ [155, 8250],
138
+ [156, 339],
139
+ [158, 382],
140
+ [159, 376],
141
+ ]);
142
+ /**
143
+ * Replace the given code point with a replacement character if it is a
144
+ * surrogate or is outside the valid range. Otherwise return the code
145
+ * point unchanged.
146
+ * @param codePoint Unicode code point to convert.
147
+ */
148
+ function replaceCodePoint(codePoint) {
149
+ if ((codePoint >= 0xd8_00 && codePoint <= 0xdf_ff) ||
150
+ codePoint > 0x10_ff_ff) {
151
+ return 0xff_fd;
152
+ }
153
+ return decodeMap.get(codePoint) ?? codePoint;
154
+ }
155
+ //# sourceMappingURL=decode-codepoint.js.map
156
+ ;// ./node_modules/htmlparser2/node_modules/entities/dist/internal/bin-trie-flags.js
157
+ /**
158
+ * Bit flags & masks for the binary trie encoding used for entity decoding.
159
+ *
160
+ * Bit layout (16 bits total):
161
+ * 15..14 VALUE_LENGTH (+1 encoding; 0 => no value)
162
+ * 13 FLAG13. If valueLength>0: semicolon required flag (implicit ';').
163
+ * If valueLength==0: compact run flag.
164
+ * 12..7 BRANCH_LENGTH Branch length (0 => single branch in 6..0 if jumpOffset==char) OR run length (when compact run)
165
+ * 6..0 JUMP_TABLE Jump offset (jump table) OR single-branch char code OR first run char
166
+ */
167
+ var BinTrieFlags;
168
+ (function (BinTrieFlags) {
169
+ BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
170
+ BinTrieFlags[BinTrieFlags["FLAG13"] = 8192] = "FLAG13";
171
+ BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 8064] = "BRANCH_LENGTH";
172
+ BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE";
173
+ })(BinTrieFlags || (BinTrieFlags = {}));
174
+ //# sourceMappingURL=bin-trie-flags.js.map
175
+ ;// ./node_modules/htmlparser2/node_modules/entities/dist/decode.js
176
+
177
+
178
+
179
+
180
+ var CharCodes;
181
+ (function (CharCodes) {
182
+ CharCodes[CharCodes["NUM"] = 35] = "NUM";
183
+ CharCodes[CharCodes["SEMI"] = 59] = "SEMI";
184
+ CharCodes[CharCodes["EQUALS"] = 61] = "EQUALS";
185
+ CharCodes[CharCodes["ZERO"] = 48] = "ZERO";
186
+ CharCodes[CharCodes["NINE"] = 57] = "NINE";
187
+ CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A";
188
+ CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F";
189
+ CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X";
190
+ CharCodes[CharCodes["LOWER_Z"] = 122] = "LOWER_Z";
191
+ CharCodes[CharCodes["UPPER_A"] = 65] = "UPPER_A";
192
+ CharCodes[CharCodes["UPPER_F"] = 70] = "UPPER_F";
193
+ CharCodes[CharCodes["UPPER_Z"] = 90] = "UPPER_Z";
194
+ })(CharCodes || (CharCodes = {}));
195
+ /** Bit that needs to be set to convert an upper case ASCII character to lower case */
196
+ const TO_LOWER_BIT = 0b10_0000;
197
+ function isNumber(code) {
198
+ return code >= CharCodes.ZERO && code <= CharCodes.NINE;
199
+ }
200
+ function isHexadecimalCharacter(code) {
201
+ return ((code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_F) ||
202
+ (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_F));
203
+ }
204
+ function isAsciiAlphaNumeric(code) {
205
+ return ((code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z) ||
206
+ (code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z) ||
207
+ isNumber(code));
208
+ }
209
+ /**
210
+ * Checks if the given character is a valid end character for an entity in an attribute.
211
+ *
212
+ * Attribute values that aren't terminated properly aren't parsed, and shouldn't lead to a parser error.
213
+ * See the example in https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
214
+ * @param code Code point to decode.
215
+ */
216
+ function isEntityInAttributeInvalidEnd(code) {
217
+ return code === CharCodes.EQUALS || isAsciiAlphaNumeric(code);
218
+ }
219
+ var EntityDecoderState;
220
+ (function (EntityDecoderState) {
221
+ EntityDecoderState[EntityDecoderState["EntityStart"] = 0] = "EntityStart";
222
+ EntityDecoderState[EntityDecoderState["NumericStart"] = 1] = "NumericStart";
223
+ EntityDecoderState[EntityDecoderState["NumericDecimal"] = 2] = "NumericDecimal";
224
+ EntityDecoderState[EntityDecoderState["NumericHex"] = 3] = "NumericHex";
225
+ EntityDecoderState[EntityDecoderState["NamedEntity"] = 4] = "NamedEntity";
226
+ })(EntityDecoderState || (EntityDecoderState = {}));
227
+ /**
228
+ * Decoding mode for named entities.
229
+ */
230
+ var DecodingMode;
231
+ (function (DecodingMode) {
232
+ /** Entities in text nodes that can end with any character. */
233
+ DecodingMode[DecodingMode["Legacy"] = 0] = "Legacy";
234
+ /** Only allow entities terminated with a semicolon. */
235
+ DecodingMode[DecodingMode["Strict"] = 1] = "Strict";
236
+ /** Entities in attributes have limitations on ending characters. */
237
+ DecodingMode[DecodingMode["Attribute"] = 2] = "Attribute";
238
+ })(DecodingMode || (DecodingMode = {}));
239
+ /**
240
+ * Token decoder with support of writing partial entities.
241
+ */
242
+ class EntityDecoder {
243
+ decodeTree;
244
+ emitCodePoint;
245
+ errors;
246
+ constructor(
247
+ /** The tree used to decode entities. */
248
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: False positive
249
+ decodeTree,
250
+ /**
251
+ * The function that is called when a codepoint is decoded.
252
+ *
253
+ * For multi-byte named entities, this will be called multiple times,
254
+ * with the second codepoint, and the same `consumed` value.
255
+ * @param codepoint The decoded codepoint.
256
+ * @param consumed The number of bytes consumed by the decoder.
257
+ */
258
+ emitCodePoint,
259
+ /** An object that is used to produce errors. */
260
+ errors) {
261
+ this.decodeTree = decodeTree;
262
+ this.emitCodePoint = emitCodePoint;
263
+ this.errors = errors;
264
+ }
265
+ /** The current state of the decoder. */
266
+ state = EntityDecoderState.EntityStart;
267
+ /** Characters that were consumed while parsing an entity. */
268
+ consumed = 1;
269
+ /**
270
+ * The result of the entity.
271
+ *
272
+ * Either the result index of a numeric entity, or the codepoint of a
273
+ * numeric entity.
274
+ */
275
+ result = 0;
276
+ /** The current index in the decode tree. */
277
+ treeIndex = 0;
278
+ /** The number of characters that were consumed in excess. */
279
+ excess = 1;
280
+ /** The mode in which the decoder is operating. */
281
+ decodeMode = DecodingMode.Strict;
282
+ /** The number of characters that have been consumed in the current run. */
283
+ runConsumed = 0;
284
+ /**
285
+ * Resets the instance to make it reusable.
286
+ * @param decodeMode Entity decoding mode to use.
287
+ */
288
+ startEntity(decodeMode) {
289
+ this.decodeMode = decodeMode;
290
+ this.state = EntityDecoderState.EntityStart;
291
+ this.result = 0;
292
+ this.treeIndex = 0;
293
+ this.excess = 1;
294
+ this.consumed = 1;
295
+ this.runConsumed = 0;
296
+ }
297
+ /**
298
+ * Write an entity to the decoder. This can be called multiple times with partial entities.
299
+ * If the entity is incomplete, the decoder will return -1.
300
+ *
301
+ * Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the
302
+ * entity is incomplete, and resume when the next string is written.
303
+ * @param input The string containing the entity (or a continuation of the entity).
304
+ * @param offset The offset at which the entity begins. Should be 0 if this is not the first call.
305
+ * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
306
+ */
307
+ write(input, offset) {
308
+ switch (this.state) {
309
+ case EntityDecoderState.EntityStart: {
310
+ if (input.charCodeAt(offset) === CharCodes.NUM) {
311
+ this.state = EntityDecoderState.NumericStart;
312
+ this.consumed += 1;
313
+ return this.stateNumericStart(input, offset + 1);
314
+ }
315
+ this.state = EntityDecoderState.NamedEntity;
316
+ return this.stateNamedEntity(input, offset);
317
+ }
318
+ case EntityDecoderState.NumericStart: {
319
+ return this.stateNumericStart(input, offset);
320
+ }
321
+ case EntityDecoderState.NumericDecimal: {
322
+ return this.stateNumericDecimal(input, offset);
323
+ }
324
+ case EntityDecoderState.NumericHex: {
325
+ return this.stateNumericHex(input, offset);
326
+ }
327
+ case EntityDecoderState.NamedEntity: {
328
+ return this.stateNamedEntity(input, offset);
329
+ }
330
+ }
331
+ }
332
+ /**
333
+ * Switches between the numeric decimal and hexadecimal states.
334
+ *
335
+ * Equivalent to the `Numeric character reference state` in the HTML spec.
336
+ * @param input The string containing the entity (or a continuation of the entity).
337
+ * @param offset The current offset.
338
+ * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
339
+ */
340
+ stateNumericStart(input, offset) {
341
+ if (offset >= input.length) {
342
+ return -1;
343
+ }
344
+ if ((input.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes.LOWER_X) {
345
+ this.state = EntityDecoderState.NumericHex;
346
+ this.consumed += 1;
347
+ return this.stateNumericHex(input, offset + 1);
348
+ }
349
+ this.state = EntityDecoderState.NumericDecimal;
350
+ return this.stateNumericDecimal(input, offset);
351
+ }
352
+ /**
353
+ * Parses a hexadecimal numeric entity.
354
+ *
355
+ * Equivalent to the `Hexademical character reference state` in the HTML spec.
356
+ * @param input The string containing the entity (or a continuation of the entity).
357
+ * @param offset The current offset.
358
+ * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
359
+ */
360
+ stateNumericHex(input, offset) {
361
+ while (offset < input.length) {
362
+ const char = input.charCodeAt(offset);
363
+ if (isNumber(char) || isHexadecimalCharacter(char)) {
364
+ // Convert hex digit to value (0-15); 'a'/'A' -> 10.
365
+ const digit = char <= CharCodes.NINE
366
+ ? char - CharCodes.ZERO
367
+ : (char | TO_LOWER_BIT) - CharCodes.LOWER_A + 10;
368
+ this.result = this.result * 16 + digit;
369
+ this.consumed++;
370
+ offset++;
371
+ }
372
+ else {
373
+ return this.emitNumericEntity(char, 3);
374
+ }
375
+ }
376
+ return -1; // Incomplete entity
377
+ }
378
+ /**
379
+ * Parses a decimal numeric entity.
380
+ *
381
+ * Equivalent to the `Decimal character reference state` in the HTML spec.
382
+ * @param input The string containing the entity (or a continuation of the entity).
383
+ * @param offset The current offset.
384
+ * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
385
+ */
386
+ stateNumericDecimal(input, offset) {
387
+ while (offset < input.length) {
388
+ const char = input.charCodeAt(offset);
389
+ if (isNumber(char)) {
390
+ this.result = this.result * 10 + (char - CharCodes.ZERO);
391
+ this.consumed++;
392
+ offset++;
393
+ }
394
+ else {
395
+ return this.emitNumericEntity(char, 2);
396
+ }
397
+ }
398
+ return -1; // Incomplete entity
399
+ }
400
+ /**
401
+ * Validate and emit a numeric entity.
402
+ *
403
+ * Implements the logic from the `Hexademical character reference start
404
+ * state` and `Numeric character reference end state` in the HTML spec.
405
+ * @param lastCp The last code point of the entity. Used to see if the
406
+ * entity was terminated with a semicolon.
407
+ * @param expectedLength The minimum number of characters that should be
408
+ * consumed. Used to validate that at least one digit
409
+ * was consumed.
410
+ * @returns The number of characters that were consumed.
411
+ */
412
+ emitNumericEntity(lastCp, expectedLength) {
413
+ // Ensure we consumed at least one digit.
414
+ if (this.consumed <= expectedLength) {
415
+ this.errors?.absenceOfDigitsInNumericCharacterReference(this.consumed);
416
+ return 0;
417
+ }
418
+ // Figure out if this is a legit end of the entity
419
+ if (lastCp === CharCodes.SEMI) {
420
+ this.consumed += 1;
421
+ }
422
+ else if (this.decodeMode === DecodingMode.Strict) {
423
+ return 0;
424
+ }
425
+ this.emitCodePoint(replaceCodePoint(this.result), this.consumed);
426
+ if (this.errors) {
427
+ if (lastCp !== CharCodes.SEMI) {
428
+ this.errors.missingSemicolonAfterCharacterReference();
429
+ }
430
+ this.errors.validateNumericCharacterReference(this.result);
431
+ }
432
+ return this.consumed;
433
+ }
434
+ /**
435
+ * Parses a named entity.
436
+ *
437
+ * Equivalent to the `Named character reference state` in the HTML spec.
438
+ * @param input The string containing the entity (or a continuation of the entity).
439
+ * @param offset The current offset.
440
+ * @returns The number of characters that were consumed, or -1 if the entity is incomplete.
441
+ */
442
+ stateNamedEntity(input, offset) {
443
+ const { decodeTree } = this;
444
+ let current = decodeTree[this.treeIndex];
445
+ // The length is the number of bytes of the value, including the current byte.
446
+ let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
447
+ while (offset < input.length) {
448
+ // Handle compact runs (possibly inline): valueLength == 0 and SEMI_REQUIRED bit set.
449
+ if (valueLength === 0 && (current & BinTrieFlags.FLAG13) !== 0) {
450
+ const runLength = (current & BinTrieFlags.BRANCH_LENGTH) >> 7; /* 2..63 */
451
+ // If we are starting a run, check the first char.
452
+ if (this.runConsumed === 0) {
453
+ const firstChar = current & BinTrieFlags.JUMP_TABLE;
454
+ if (input.charCodeAt(offset) !== firstChar) {
455
+ return this.result === 0
456
+ ? 0
457
+ : this.emitNotTerminatedNamedEntity();
458
+ }
459
+ offset++;
460
+ this.excess++;
461
+ this.runConsumed++;
462
+ }
463
+ // Check remaining characters in the run.
464
+ while (this.runConsumed < runLength) {
465
+ if (offset >= input.length) {
466
+ return -1;
467
+ }
468
+ const charIndexInPacked = this.runConsumed - 1;
469
+ const packedWord = decodeTree[this.treeIndex + 1 + (charIndexInPacked >> 1)];
470
+ const expectedChar = charIndexInPacked % 2 === 0
471
+ ? packedWord & 0xff
472
+ : (packedWord >> 8) & 0xff;
473
+ if (input.charCodeAt(offset) !== expectedChar) {
474
+ this.runConsumed = 0;
475
+ return this.result === 0
476
+ ? 0
477
+ : this.emitNotTerminatedNamedEntity();
478
+ }
479
+ offset++;
480
+ this.excess++;
481
+ this.runConsumed++;
482
+ }
483
+ this.runConsumed = 0;
484
+ this.treeIndex += 1 + (runLength >> 1);
485
+ current = decodeTree[this.treeIndex];
486
+ valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
487
+ }
488
+ if (offset >= input.length)
489
+ break;
490
+ const char = input.charCodeAt(offset);
491
+ /*
492
+ * Implicit semicolon handling for nodes that require a semicolon but
493
+ * don't have an explicit ';' branch stored in the trie. If we have
494
+ * a value on the current node, it requires a semicolon, and the
495
+ * current input character is a semicolon, emit the entity using the
496
+ * current node (without descending further).
497
+ */
498
+ if (char === CharCodes.SEMI &&
499
+ valueLength !== 0 &&
500
+ (current & BinTrieFlags.FLAG13) !== 0) {
501
+ return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
502
+ }
503
+ this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);
504
+ if (this.treeIndex < 0) {
505
+ return this.result === 0 ||
506
+ // If we are parsing an attribute
507
+ (this.decodeMode === DecodingMode.Attribute &&
508
+ // We shouldn't have consumed any characters after the entity,
509
+ (valueLength === 0 ||
510
+ // And there should be no invalid characters.
511
+ isEntityInAttributeInvalidEnd(char)))
512
+ ? 0
513
+ : this.emitNotTerminatedNamedEntity();
514
+ }
515
+ current = decodeTree[this.treeIndex];
516
+ valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
517
+ // If the branch is a value, store it and continue
518
+ if (valueLength !== 0) {
519
+ // If the entity is terminated by a semicolon, we are done.
520
+ if (char === CharCodes.SEMI) {
521
+ return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
522
+ }
523
+ // If we encounter a non-terminated (legacy) entity while parsing strictly, then ignore it.
524
+ if (this.decodeMode !== DecodingMode.Strict &&
525
+ (current & BinTrieFlags.FLAG13) === 0) {
526
+ this.result = this.treeIndex;
527
+ this.consumed += this.excess;
528
+ this.excess = 0;
529
+ }
530
+ }
531
+ // Increment offset & excess for next iteration
532
+ offset++;
533
+ this.excess++;
534
+ }
535
+ return -1;
536
+ }
537
+ /**
538
+ * Emit a named entity that was not terminated with a semicolon.
539
+ * @returns The number of characters consumed.
540
+ */
541
+ emitNotTerminatedNamedEntity() {
542
+ const { result, decodeTree } = this;
543
+ const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;
544
+ this.emitNamedEntityData(result, valueLength, this.consumed);
545
+ this.errors?.missingSemicolonAfterCharacterReference();
546
+ return this.consumed;
547
+ }
548
+ /**
549
+ * Emit a named entity.
550
+ * @param result The index of the entity in the decode tree.
551
+ * @param valueLength The number of bytes in the entity.
552
+ * @param consumed The number of characters consumed.
553
+ * @returns The number of characters consumed.
554
+ */
555
+ emitNamedEntityData(result, valueLength, consumed) {
556
+ const { decodeTree } = this;
557
+ this.emitCodePoint(valueLength === 1
558
+ ? decodeTree[result] &
559
+ ~(BinTrieFlags.VALUE_LENGTH | BinTrieFlags.FLAG13)
560
+ : decodeTree[result + 1], consumed);
561
+ if (valueLength === 3) {
562
+ // For multi-byte values, we need to emit the second byte.
563
+ this.emitCodePoint(decodeTree[result + 2], consumed);
564
+ }
565
+ return consumed;
566
+ }
567
+ /**
568
+ * Signal to the parser that the end of the input was reached.
569
+ *
570
+ * Remaining data will be emitted and relevant errors will be produced.
571
+ * @returns The number of characters consumed.
572
+ */
573
+ end() {
574
+ switch (this.state) {
575
+ case EntityDecoderState.NamedEntity: {
576
+ // Emit a named entity if we have one.
577
+ return this.result !== 0 &&
578
+ (this.decodeMode !== DecodingMode.Attribute ||
579
+ this.result === this.treeIndex)
580
+ ? this.emitNotTerminatedNamedEntity()
581
+ : 0;
582
+ }
583
+ // Otherwise, emit a numeric entity if we have one.
584
+ case EntityDecoderState.NumericDecimal: {
585
+ return this.emitNumericEntity(0, 2);
586
+ }
587
+ case EntityDecoderState.NumericHex: {
588
+ return this.emitNumericEntity(0, 3);
589
+ }
590
+ case EntityDecoderState.NumericStart: {
591
+ this.errors?.absenceOfDigitsInNumericCharacterReference(this.consumed);
592
+ return 0;
593
+ }
594
+ case EntityDecoderState.EntityStart: {
595
+ // Return 0 if we have no entity.
596
+ return 0;
597
+ }
598
+ }
599
+ }
600
+ }
601
+ /**
602
+ * Creates a function that decodes entities in a string.
603
+ * @param decodeTree The decode tree.
604
+ * @returns A function that decodes entities in a string.
605
+ */
606
+ function getDecoder(decodeTree) {
607
+ let returnValue = "";
608
+ const decoder = new EntityDecoder(decodeTree, (data) => (returnValue += String.fromCodePoint(data)));
609
+ return function decodeWithTrie(input, decodeMode) {
610
+ let lastIndex = 0;
611
+ let offset = 0;
612
+ while ((offset = input.indexOf("&", offset)) >= 0) {
613
+ returnValue += input.slice(lastIndex, offset);
614
+ decoder.startEntity(decodeMode);
615
+ const length = decoder.write(input,
616
+ // Skip the "&"
617
+ offset + 1);
618
+ if (length < 0) {
619
+ lastIndex = offset + decoder.end();
620
+ break;
621
+ }
622
+ lastIndex = offset + length;
623
+ // If `length` is 0, skip the current `&` and continue.
624
+ offset = length === 0 ? lastIndex + 1 : lastIndex;
625
+ }
626
+ const result = returnValue + input.slice(lastIndex);
627
+ // Make sure we don't keep a reference to the final string.
628
+ returnValue = "";
629
+ return result;
630
+ };
631
+ }
632
+ /**
633
+ * Determines the branch of the current node that is taken given the current
634
+ * character. This function is used to traverse the trie.
635
+ * @param decodeTree The trie.
636
+ * @param current The current node.
637
+ * @param nodeIndex Index immediately after the current node header.
638
+ * @param char The current character.
639
+ * @returns The index of the next node, or -1 if no branch is taken.
640
+ */
641
+ function determineBranch(decodeTree, current, nodeIndex, char) {
642
+ const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
643
+ const jumpOffset = current & BinTrieFlags.JUMP_TABLE;
644
+ // Case 1: Single branch encoded in jump offset
645
+ if (branchCount === 0) {
646
+ return jumpOffset !== 0 && char === jumpOffset ? nodeIndex : -1;
647
+ }
648
+ // Case 2: Multiple branches encoded in jump table
649
+ if (jumpOffset) {
650
+ const value = char - jumpOffset;
651
+ return value < 0 || value >= branchCount
652
+ ? -1
653
+ : decodeTree[nodeIndex + value] - 1;
654
+ }
655
+ // Case 3: Multiple branches encoded in packed dictionary (two keys per uint16)
656
+ const packedKeySlots = (branchCount + 1) >> 1;
657
+ /*
658
+ * Treat packed keys as a virtual sorted array of length `branchCount`.
659
+ * Key(i) = low byte for even i, high byte for odd i in slot i>>1.
660
+ */
661
+ let lo = 0;
662
+ let hi = branchCount - 1;
663
+ while (lo <= hi) {
664
+ const mid = (lo + hi) >>> 1;
665
+ const slot = mid >> 1;
666
+ const packed = decodeTree[nodeIndex + slot];
667
+ const midKey = (packed >> ((mid & 1) * 8)) & 0xff;
668
+ if (midKey < char) {
669
+ lo = mid + 1;
670
+ }
671
+ else if (midKey > char) {
672
+ hi = mid - 1;
673
+ }
674
+ else {
675
+ return decodeTree[nodeIndex + packedKeySlots + mid];
676
+ }
677
+ }
678
+ return -1;
679
+ }
680
+ const htmlDecoder = /* #__PURE__ */ (/* unused pure expression or super */ null && (getDecoder(htmlDecodeTree)));
681
+ const xmlDecoder = /* #__PURE__ */ (/* unused pure expression or super */ null && (getDecoder(xmlDecodeTree)));
682
+ /**
683
+ * Decodes an HTML string.
684
+ * @param htmlString The string to decode.
685
+ * @param mode The decoding mode.
686
+ * @returns The decoded string.
687
+ */
688
+ function decodeHTML(htmlString, mode = DecodingMode.Legacy) {
689
+ return htmlDecoder(htmlString, mode);
690
+ }
691
+ /**
692
+ * Decodes an HTML string in an attribute.
693
+ * @param htmlAttribute The string to decode.
694
+ * @returns The decoded string.
695
+ */
696
+ function decodeHTMLAttribute(htmlAttribute) {
697
+ return htmlDecoder(htmlAttribute, DecodingMode.Attribute);
698
+ }
699
+ /**
700
+ * Decodes an HTML string, requiring all entities to be terminated by a semicolon.
701
+ * @param htmlString The string to decode.
702
+ * @returns The decoded string.
703
+ */
704
+ function decodeHTMLStrict(htmlString) {
705
+ return htmlDecoder(htmlString, DecodingMode.Strict);
706
+ }
707
+ /**
708
+ * Decodes an XML string, requiring all entities to be terminated by a semicolon.
709
+ * @param xmlString The string to decode.
710
+ * @returns The decoded string.
711
+ */
712
+ function decodeXML(xmlString) {
713
+ return xmlDecoder(xmlString, DecodingMode.Strict);
714
+ }
715
+
716
+ // Re-export for use by eg. htmlparser2
717
+
718
+
719
+ //# sourceMappingURL=decode.js.map
720
+ ;// ./node_modules/htmlparser2/node_modules/entities/dist/internal/decode-shared.js
721
+ /**
722
+ * Shared base64 decode helper for generated decode data.
723
+ * Assumes global atob is available.
724
+ * @param input Input string to encode or decode.
725
+ */
726
+ function decodeBase64(input) {
727
+ const binary = atob(input);
728
+ const evenLength = binary.length & ~1; // Round down to even length
729
+ const out = new Uint16Array(evenLength / 2);
730
+ for (let index = 0, outIndex = 0; index < evenLength; index += 2) {
731
+ const lo = binary.charCodeAt(index);
732
+ const hi = binary.charCodeAt(index + 1);
733
+ out[outIndex++] = lo | (hi << 8);
734
+ }
735
+ return out;
736
+ }
737
+ //# sourceMappingURL=decode-shared.js.map
738
+ ;// ./node_modules/htmlparser2/node_modules/entities/dist/generated/decode-data-xml.js
739
+ // Generated using scripts/write-decode-map.ts
740
+
741
+ /** Packed XML decode trie data. */
742
+ const decode_data_xml_xmlDecodeTree = /* #__PURE__ */ decodeBase64("AAJhZ2xxBwARABMAFQBtAg0AAAAAAA8AcAAmYG8AcwAnYHQAPmB0ADxg9SFvdCJg");
743
+ //# sourceMappingURL=decode-data-xml.js.map
744
+ ;// ./node_modules/htmlparser2/node_modules/entities/dist/generated/decode-data-html.js
745
+ // Generated using scripts/write-decode-map.ts
746
+
747
+ /** Packed HTML decode trie data. */
748
+ const decode_data_html_htmlDecodeTree = /* #__PURE__ */ decodeBase64("QR08ALkAAgH6AYsDNQR2BO0EPgXZBQEGLAbdBxMISQrvCmQLfQurDKQNLw4fD4YPpA+6D/IPAAAAAAAAAAAAAAAAKhBMEY8TmxUWF2EYLBkxGuAa3RsJHDscWR8YIC8jSCSIJcMl6ie3Ku8rEC0CLjoupS7kLgAIRU1hYmNmZ2xtbm9wcnN0dVQAWgBeAGUAaQBzAHcAfgCBAIQAhwCSAJoAoACsALMAbABpAGcAO4DGAMZAUAA7gCYAJkBjAHUAdABlADuAwQDBQHIiZXZlAAJhAAFpeW0AcgByAGMAO4DCAMJAEGRyAADgNdgE3XIAYQB2AGUAO4DAAMBA8CFoYZFj4SFjcgBhZAAAoFMqAAFncIsAjgBvAG4ABGFmAADgNdg43fAlbHlGdW5jdGlvbgCgYSBpAG4AZwA7gMUAxUAAAWNzpACoAHIAAOA12Jzc6SFnbgCgVCJpAGwAZABlADuAwwDDQG0AbAA7gMQAxEAABGFjZWZvcnN1xQDYANoA7QDxAPYA+QD8AAABY3LJAM8AayNzbGFzaAAAoBYidgHTANUAAKDnKmUAZAAAoAYjeQARZIABY3J0AOAA5QDrAGEidXNlAACgNSLuI291bGxpcwCgLCFhAJJjcgAA4DXYBd1wAGYAAOA12Dnd5SF2ZdhiYwDyAOoAbSJwZXEAAKBOIgAHSE9hY2RlZmhpbG9yc3UXARoBHwE6AVIBVQFiAWQBZgGCAakB6QHtAfIBYwB5ACdkUABZADuAqQCpQIABY3B5ACUBKAE1AfUhdGUGYWmg0iJ0KGFsRGlmZmVyZW50aWFsRAAAoEUhbCJleXMAAKAtIQACYWVpb0EBRAFKAU0B8iFvbgxhZABpAGwAO4DHAMdAcgBjAAhhbiJpbnQAAKAwIm8AdAAKYQABZG5ZAV0BaSJsbGEAuGB0I2VyRG90ALdg8gA5AWkAp2NyImNsZQAAAkRNUFRwAXQBeQF9AW8AdAAAoJkiaSJudXMAAKCWIuwhdXMAoJUiaSJtZXMAAKCXIm8AAAFjc4cBlAFrKndpc2VDb250b3VySW50ZWdyYWwAAKAyImUjQ3VybHkAAAFEUZwBpAFvJXVibGVRdW90ZQAAoB0gdSJvdGUAAKAZIAACbG5wdbABtgHNAdgBbwBuAGWgNyIAoHQqgAFnaXQAvAHBAcUB8iJ1ZW50AKBhIm4AdAAAoC8i7yV1ckludGVncmFsAKAuIgABZnLRAdMBAKACIe8iZHVjdACgECJuLnRlckNsb2Nrd2lzZUNvbnRvdXJJbnRlZ3JhbAAAoDMi7yFzcwCgLypjAHIAAOA12J7ccABDoNMiYQBwAACgTSKABURKU1phY2VmaW9zAAsCEgIVAhgCGwIsAjQCOQI9AnMCfwNvoEUh9CJyYWhkAKARKWMAeQACZGMAeQAFZGMAeQAPZIABZ3JzACECJQIoAuchZXIAoCEgcgAAoKEhaAB2AACg5CoAAWF5MAIzAvIhb24OYRRkbAB0oAciYQCUY3IAAOA12AfdAAFhZkECawIAAWNtRQJnAvIjaXRpY2FsAAJBREdUUAJUAl8CYwJjInV0ZQC0YG8AdAFZAloC2WJiJGxlQWN1dGUA3WJyImF2ZQBgYGkibGRlANxi7yFuZACgxCJmJWVyZW50aWFsRAAAoEYhcAR9AgAAAAAAAIECjgIAABoDZgAA4DXYO91EoagAhQKJAm8AdAAAoNwgcSJ1YWwAAKBQIuIhbGUAA0NETFJVVpkCqAK1Au8C/wIRA28AbgB0AG8AdQByAEkAbgB0AGUAZwByAGEA7ADEAW8AdAKvAgAAAACwAqhgbiNBcnJvdwAAoNMhAAFlb7kC0AJmAHQAgAFBUlQAwQLGAs0CciJyb3cAAKDQIekkZ2h0QXJyb3cAoNQhZQDlACsCbgBnAAABTFLWAugC5SFmdAABQVLcAuECciJyb3cAAKD4J+kkZ2h0QXJyb3cAoPon6SRnaHRBcnJvdwCg+SdpImdodAAAAUFU9gL7AnIicm93AACg0iFlAGUAAKCoInAAQQIGAwAAAAALA3Iicm93AACg0SFvJHduQXJyb3cAAKDVIWUlcnRpY2FsQmFyAACgJSJuAAADQUJMUlRhJAM2AzoDWgNxA3oDciJyb3cAAKGTIUJVLAMwA2EAcgAAoBMpcCNBcnJvdwAAoPUhciJldmUAEWPlIWZ00gJDAwAASwMAAFIDaSVnaHRWZWN0b3IAAKBQKWUkZVZlY3RvcgAAoF4p5SJjdG9yQqC9IWEAcgAAoFYpaSJnaHQA1AFiAwAAaQNlJGVWZWN0b3IAAKBfKeUiY3RvckKgwSFhAHIAAKBXKWUAZQBBoKQiciJyb3cAAKCnIXIAcgBvAPcAtAIAAWN0gwOHA3IA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YwAAoN8i4SFycnCgtiEAoD0pgKIqImJjZG9zACsVMBU6FT4VQRVyImNhcAAAoEgqAAFhdTQVNxVwAACgRipwAACgSipvAHQAAKCNInIAAKBFKgDgKiIA/gACYWxydksVURVuFXMVcgByAG2gtyEAoDwpeQCAAWV2dwBYFWUVaRVxAHACXxUAAAAAYxVyAGUA4wAXFXUA4wAZFWUAZQAAoM4iZSJkZ2UAAKDPImUAbgA7gKQApEBlI2Fycm93AAABbHJ7FX8V5SFmdACgtiFpImdodAAAoLchZQDkAG0VAAFjaYsVkRVvAG4AaQBuAPQAkwFuAHQAAKAxImwiY3R5AACgLSOACUFIYWJjZGVmaGlqbG9yc3R1d3oAuBW7Fb8V1RXgFegV+RUKFhUWHxZUFlcWZRbFFtsW7xb7FgUXChdyAPIAtAJhAHIAAKBlKQACZ2xyc8YVyhXOFdAV5yFlcgCgICDlIXRoAKA4IfIA9QxoAHagECAAoKMiawHZFd4VYSJyb3cAAKAPKWEA4wBfAgABYXnkFecV8iFvbg9hNGQAoUYhYW/tFfQVAAFnciEC8RVyAACgyiF0InNlcQAAoHcqgAFnbG0A/xUCFgUWO4CwALBAdABhALRjcCJ0eXYAAKCxKQABaXIOFhIW8yFodACgfykA4DXYId1hAHIAAAFschsWHRYAoMMhAKDCIYACYWVnc3YAKBauAjYWOhY+Fm0AAKHEIm9zLhY0Fm4AZABzoMQi9SFpdACgZiZhIm1tYQDdY2kAbgAAoPIiAKH3AGlvQxZRFmQAZQAAgfcAO29KFksW90BuI3RpbWVzAACgxyJuAPgAUBZjAHkAUmRjAG8CXhYAAAAAYhZyAG4AAKAeI28AcAAAoA0jgAJscHR1dwBuFnEWdRaSFp4W7CFhciRgZgAA4DXYVd0AotkCZW1wc30WhBaJFo0WcQBkoFAibwB0AACgUSJpIm51cwAAoDgi7CF1cwCgFCLxInVhcmUAoKEiYgBsAGUAYgBhAHIAdwBlAGQAZwDlANcAbgCAAWFkaAClFqoWtBZyAHIAbwD3APUMbwB3AG4AYQByAHIAbwB3APMA8xVhI3Jwb29uAAABbHK8FsAWZQBmAPQAHBZpAGcAaAD0AB4WYgHJFs8WawBhAHIAbwD3AJILbwLUFgAAAADYFnIAbgAAoB8jbwBwAACgDCOAAWNvdADhFukW7BYAAXJ55RboFgDgNdi53FVkbAAAoPYp8iFvaxFhAAFkcvMW9xZvAHQAAKDxImkA5qC/JVsSAAFhaP8WAhdyAPIANQNhAPIA1wvhIm5nbGUAoKYpAAFjaQ4XEBd5AF9k5yJyYXJyAKD/JwAJRGFjZGVmZ2xtbm9wcXJzdHV4MRc4F0YXWxcyBF4XaRd5F40XrBe0F78X2RcVGCEYLRg1GEAYAAFEbzUXgRZvAPQA+BUAAWNzPBdCF3UAdABlADuA6QDpQPQhZXIAoG4qAAJhaW95TRdQF1YXWhfyIW9uG2FyAGOgViI7gOoA6kDsIW9uAKBVIk1kbwB0ABdhAAFEcmIXZhdvAHQAAKBSIgDgNdgi3XKhmipuF3QXYQB2AGUAO4DoAOhAZKCWKm8AdAAAoJgqgKGZKmlscwCAF4UXhxfuInRlcnMAoOcjAKATIWSglSpvAHQAAKCXKoABYXBzAJMXlheiF2MAcgATYXQAeQBzogUinxcAAAAAoRdlAHQAAKAFInAAMaADIDMBqRerFwCgBCAAoAUgAAFnc7AXsRdLYXAAAKACIAABZ3C4F7sXbwBuABlhZgAA4DXYVt2AAWFscwDFF8sXzxdyAHOg1SJsAACg4yl1AHMAAKBxKmkAAKG1A2x21RfYF28AbgC1Y/VjAAJjc3V24BfoF/0XEBgAAWlv5BdWF3IAYwAAoFYiaQLuFwAAAADwF+0ADQThIW50AAFnbPUX+Rd0AHIAAKCWKuUhc3MAoJUqgAFhZWkAAxgGGAoYbABzAD1gcwB0AACgXyJ2AESgYSJEAACgeCrwImFyc2wAoOUpAAFEYRkYHRhvAHQAAKBTInIAcgAAoHEpgAFjZGkAJxgqGO0XcgAAoC8hbwD0AIwCAAFhaDEYMhi3YzuA8ADwQAABbXI5GD0YbAA7gOsA60BvAACgrCCAAWNpcABGGEgYSxhsACFgcwD0ACwEAAFlb08YVxhjAHQAYQB0AGkAbwDuABoEbgBlAG4AdABpAGEAbADlADME4Ql1GAAAgRgAAIMYiBgAAAAAoRilGAAAqhgAALsYvhjRGAAA1xgnGWwAbABpAG4AZwBkAG8AdABzAGUA8QBlF3kARGRtImFsZQAAoEAmgAFpbHIAjRiRGJ0Y7CFpZwCgA/tpApcYAAAAAJoYZwAAoAD7aQBnAACgBPsA4DXYI93sIWlnAKAB++whaWcA4GYAagCAAWFsdACvGLIYthh0AACgbSZpAGcAAKAC+24AcwAAoLElbwBmAJJh8AHCGAAAxhhmAADgNdhX3QABYWvJGMwYbADsAGsEdqDUIgCg2SphI3J0aW50AACgDSoAAWFv2hgiGQABY3PeGB8ZsQPnGP0YBRkSGRUZAAAdGbID7xjyGPQY9xj5GAAA+xg7gL0AvUAAoFMhO4C8ALxAAKBVIQCgWSEAoFshswEBGQAAAxkAoFQhAKBWIbQCCxkOGQAAAAAQGTuAvgC+QACgVyEAoFwhNQAAoFghtgEZGQAAGxkAoFohAKBdITgAAKBeIWwAAKBEIHcAbgAAoCIjYwByAADgNdi73IAIRWFiY2RlZmdpamxub3JzdHYARhlKGVoZXhlmGWkZkhmWGZkZnRmgGa0ZxhnLGc8Z4BkjGmygZyIAoIwqgAFjbXAAUBlTGVgZ9SF0ZfVhbQBhAOSgswM6FgCghipyImV2ZQAfYQABaXliGWUZcgBjAB1hM2RvAHQAIWGAoWUibHFzAMYEcBl6GfGhZSLOBAAAdhlsAGEAbgD0AN8EgKF+KmNkbACBGYQZjBljAACgqSpvAHQAb6CAKmyggioAoIQqZeDbIgD+cwAAoJQqcgAA4DXYJN3noGsirATtIWVsAKA3IWMAeQBTZIChdyJFYWoApxmpGasZAKCSKgCgpSoAoKQqAAJFYWVztBm2Gb0ZwhkAoGkicABwoIoq8iFveACgiipxoIgq8aCIKrUZaQBtAACg5yJwAGYAAOA12FjdYQB2AOUAYwIAAWNp0xnWGXIAAKAKIW0AAKFzImVs3BneGQCgjioAoJAqAIM+ADtjZGxxco0E6xn0GfgZ/BkBGgABY2nvGfEZAKCnKnIAAKB6Km8AdAAAoNci0CFhcgCglSl1ImVzdAAAoHwqgAJhZGVscwAKGvQZFhrVBCAa8AEPGgAAFBpwAHIAbwD4AFkZcgAAoHgpcQAAAWxxxAQbGmwAZQBzAPMASRlpAO0A5AQAAWVuJxouGnIjdG5lcXEAAOBpIgD+xQAsGgAFQWFiY2Vma29zeUAaQxpmGmoabRqDGocalhrCGtMacgDyAMwCAAJpbG1yShpOGlAaVBpyAHMA8ABxD2YAvWBpAGwA9AASBQABZHJYGlsaYwB5AEpkAKGUIWN3YBpkGmkAcgAAoEgpAKCtIWEAcgAAoA8h6SFyYyVhgAFhbHIAcxp7Gn8a8iF0c3WgZSZpAHQAAKBlJuwhaXAAoCYg4yFvbgCguSJyAADgNdgl3XMAAAFld4wakRphInJvdwAAoCUpYSJyb3cAAKAmKYACYW1vcHIAnxqjGqcauhq+GnIAcgAAoP8h9CFodACgOyJrAAABbHKsGrMaZSRmdGFycm93AACgqSHpJGdodGFycm93AKCqIWYAAOA12Fnd4iFhcgCgFSCAAWNsdADIGswa0BpyAADgNdi93GEAcwDoAGka8iFvaydhAAFicNca2xr1IWxsAKBDIOghZW4AoBAg4Qr2GgAA/RoAAAgbExsaGwAAIRs7GwAAAAA+G2IbmRuVG6sbAACyG80b0htjAHUAdABlADuA7QDtQAChYyBpeQEbBhtyAGMAO4DuAO5AOGQAAWN4CxsNG3kANWRjAGwAO4ChAKFAAAFmcssCFhsA4DXYJt1yAGEAdgBlADuA7ADsQIChSCFpbm8AJxsyGzYbAAFpbisbLxtuAHQAAKAMKnQAAKAtIuYhaW4AoNwpdABhAACgKSHsIWlnM2GAAWFvcABDG1sbXhuAAWNndABJG0sbWRtyACthgAFlbHAAcQVRG1UbaQBuAOUAyAVhAHIA9AByBWgAMWFmAACgtyJlAGQAtWEAoggiY2ZvdGkbbRt1G3kb4SFyZQCgBSFpAG4AdKAeImkAZQAAoN0pZABvAPQAWxsAoisiY2VscIEbhRuPG5QbYQBsAACguiIAAWdyiRuNG2UAcgDzACMQ4wCCG2EicmhrAACgFyryIW9kAKA8KgACY2dwdJ8boRukG6gbeQBRZG8AbgAvYWYAAOA12FrdYQC5Y3UAZQBzAHQAO4C/AL9AAAFjabUbuRtyAADgNdi+3G4AAKIIIkVkc3bCG8QbyBvQAwCg+SJvAHQAAKD1Inag9CIAoPMiaaBiIOwhZGUpYesB1hsAANkbYwB5AFZkbAA7gO8A70AAA2NmbW9zdeYb7hvyG/Ub+hsFHAABaXnqG+0bcgBjADVhOWRyAADgNdgn3eEhdGg3YnAAZgAA4DXYW93jAf8bAAADHHIAAOA12L/c8iFjeVhk6yFjeVRkAARhY2ZnaGpvcxUcGhwiHCYcKhwtHDAcNRzwIXBhdqC6A/BjAAFleR4cIRzkIWls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ZmdobG1vcHJzdHV3CiwNLBEsHSwnLDEsQCxLLFIsYix6LIQsjyzLLOgs7Sz/LAotcgDyAAkDYQByAACgYykAAWNyFSwbLHUAdABlADuA+gD6QPIACQ1yAOMBIywAACUseQBeZHYAZQBtYQABaXkrLDAscgBjADuA+wD7QENkgAFhYmgANyw6LD0scgDyANEO7CFhY3FhYQDyAOAOAAFpckQsSCzzIWh0AKB+KQDgNdgy3XIAYQB2AGUAO4D5APlAYQFWLF8scgAAAWxyWixcLACgvyEAoL4hbABrAACggCUAAWN0Zix2LG8CbCwAAAAAcyxyAG4AZaAcI3IAAKAcI28AcAAAoA8jcgBpAACg+CUAAWFsfiyBLGMAcgBrYTuAqACoQAABZ3CILIssbwBuAHNhZgAA4DXYZt0AA2FkaGxzdZksniynLLgsuyzFLHIAcgBvAPcACQ1vAHcAbgBhAHIAcgBvAPcA2A5hI3Jwb29uAAABbHKvLLMsZQBmAPQAWyxpAGcAaAD0AF0sdQDzAKYOaQAAocUDaGzBLMIs0mNvAG4AxWPwI2Fycm93cwCgyCGAAWNpdADRLOEs5CxvAtcsAAAAAN4scgBuAGWgHSNyAACgHSNvAHAAAKAOI24AZwBvYXIAaQAAoPklYwByAADgNdjK3IABZGlyAPMs9yz6LG8AdAAAoPAi7CFkZWlhaQBmoLUlAKC0JQABYW0DLQYtcgDyAMosbAA7gPwA/EDhIm5nbGUAoKcpgAdBQkRhY2RlZmxub3Byc3oAJy0qLTAtNC2bLZ0toS2/LcMtxy3TLdgt3C3gLfwtcgDyABADYQByAHag6CoAoOkqYQBzAOgA/gIAAW5yOC08LechcnQAoJwpgANla25wcnN0AJkpSC1NLVQtXi1iLYItYQBwAHAA4QAaHG8AdABoAGkAbgDnAKEXgAFoaXIAoSmzJFotbwBwAPQAdCVooJUh7wD4JgABaXVmLWotZwBtAOEAuygAAWJwbi14LXMjZXRuZXEAceCKIgD+AODLKgD+cyNldG5lcQBx4IsiAP4A4MwqAP4AAWhyhi2KLWUAdADhABIraSNhbmdsZQAAAWxyki2WLeUhZnQAoLIiaSJnaHQAAKCzInkAMmThIXNoAKCiIoABZWxyAKcttC24LWKiKCKuLQAAAACyLWEAcgAAoLsicQAAoFoi7CFpcACg7iIAAWJ0vC1eD2EA8gBfD3IAAOA12DPddAByAOkAlS1zAHUAAAFicM0t0C0A4IIi0iAA4IMi0iBwAGYAAOA12GfdcgBvAPAAWQt0AHIA6QCaLQABY3XkLegtcgAA4DXYy9wAAWJw7C30LW4AAAFFZXUt8S0A4IoiAP5uAAABRWV/LfktAOCLIgD+6SJnemFnAKCaKYADY2Vmb3BycwANLhAuJS4pLiMuLi40LukhcmN1YQABZGkULiEuAAFiZxguHC5hAHIAAKBfKmUAcaAnIgCgWSLlIXJwAKAYIXIAAOA12DTdcABmAADgNdho3WWgQCJhAHQA6ABqD2MAcgAA4DXYzNzjCuQRUC4AAFQuAABYLmIuAAAAAGMubS5wLnQuAAAAAIguki4AAJouJxIqEnQAcgDpAB0ScgAA4DXYNd0AAUFhWy5eLnIA8gDnAnIA8gCTB75jAAFBYWYuaS5yAPIA4AJyAPIAjAdhAPAAeh5pAHMAAKD7IoABZHB0APgReS6DLgABZmx9LoAuAOA12GnddQDzAP8RaQBtAOUABBIAAUFhiy6OLnIA8gDuAnIA8gCaBwABY3GVLgoScgAA4DXYzdwAAXB0nS6hLmwAdQDzACUScgDpACASAARhY2VmaW9zdbEuvC7ELsguzC7PLtQu2S5jAAABdXm2LrsudABlADuA/QD9QE9kAAFpecAuwy5yAGMAd2FLZG4AO4ClAKVAcgAA4DXYNt1jAHkAV2RwAGYAAOA12GrdYwByAADgNdjO3AABY23dLt8ueQBOZGwAO4D/AP9AAAVhY2RlZmhpb3N38y73Lv8uAi8MLxAvEy8YLx0vIi9jInV0ZQB6YQABYXn7Lv4u8iFvbn5hN2RvAHQAfGEAAWV0Bi8KL3QAcgDmAB8QYQC2Y3IAAOA12DfdYwB5ADZk5yJyYXJyAKDdIXAAZgAA4DXYa91jAHIAAOA12M/cAAFqbiYvKC8AoA0gagAAoAwg");
749
+ //# sourceMappingURL=decode-data-html.js.map
750
+ ;// ./node_modules/htmlparser2/dist/Tokenizer.js
751
+
752
+ var Tokenizer_CharCodes;
753
+ (function (CharCodes) {
754
+ CharCodes[CharCodes["Tab"] = 9] = "Tab";
755
+ CharCodes[CharCodes["NewLine"] = 10] = "NewLine";
756
+ CharCodes[CharCodes["FormFeed"] = 12] = "FormFeed";
757
+ CharCodes[CharCodes["CarriageReturn"] = 13] = "CarriageReturn";
758
+ CharCodes[CharCodes["Space"] = 32] = "Space";
759
+ CharCodes[CharCodes["ExclamationMark"] = 33] = "ExclamationMark";
760
+ CharCodes[CharCodes["Number"] = 35] = "Number";
761
+ CharCodes[CharCodes["Amp"] = 38] = "Amp";
762
+ CharCodes[CharCodes["SingleQuote"] = 39] = "SingleQuote";
763
+ CharCodes[CharCodes["DoubleQuote"] = 34] = "DoubleQuote";
764
+ CharCodes[CharCodes["Dash"] = 45] = "Dash";
765
+ CharCodes[CharCodes["Slash"] = 47] = "Slash";
766
+ CharCodes[CharCodes["Zero"] = 48] = "Zero";
767
+ CharCodes[CharCodes["Nine"] = 57] = "Nine";
768
+ CharCodes[CharCodes["Semi"] = 59] = "Semi";
769
+ CharCodes[CharCodes["Lt"] = 60] = "Lt";
770
+ CharCodes[CharCodes["Eq"] = 61] = "Eq";
771
+ CharCodes[CharCodes["Gt"] = 62] = "Gt";
772
+ CharCodes[CharCodes["Questionmark"] = 63] = "Questionmark";
773
+ CharCodes[CharCodes["UpperA"] = 65] = "UpperA";
774
+ CharCodes[CharCodes["LowerA"] = 97] = "LowerA";
775
+ CharCodes[CharCodes["UpperF"] = 70] = "UpperF";
776
+ CharCodes[CharCodes["LowerF"] = 102] = "LowerF";
777
+ CharCodes[CharCodes["UpperZ"] = 90] = "UpperZ";
778
+ CharCodes[CharCodes["LowerZ"] = 122] = "LowerZ";
779
+ CharCodes[CharCodes["LowerX"] = 120] = "LowerX";
780
+ CharCodes[CharCodes["OpeningSquareBracket"] = 91] = "OpeningSquareBracket";
781
+ })(Tokenizer_CharCodes || (Tokenizer_CharCodes = {}));
782
+ /** All the states the tokenizer can be in. */
783
+ var State;
784
+ (function (State) {
785
+ State[State["Text"] = 1] = "Text";
786
+ State[State["BeforeTagName"] = 2] = "BeforeTagName";
787
+ State[State["InTagName"] = 3] = "InTagName";
788
+ State[State["InSelfClosingTag"] = 4] = "InSelfClosingTag";
789
+ State[State["BeforeClosingTagName"] = 5] = "BeforeClosingTagName";
790
+ State[State["InClosingTagName"] = 6] = "InClosingTagName";
791
+ State[State["AfterClosingTagName"] = 7] = "AfterClosingTagName";
792
+ // Attributes
793
+ State[State["BeforeAttributeName"] = 8] = "BeforeAttributeName";
794
+ State[State["InAttributeName"] = 9] = "InAttributeName";
795
+ State[State["AfterAttributeName"] = 10] = "AfterAttributeName";
796
+ State[State["BeforeAttributeValue"] = 11] = "BeforeAttributeValue";
797
+ State[State["InAttributeValueDq"] = 12] = "InAttributeValueDq";
798
+ State[State["InAttributeValueSq"] = 13] = "InAttributeValueSq";
799
+ State[State["InAttributeValueNq"] = 14] = "InAttributeValueNq";
800
+ // Declarations
801
+ State[State["BeforeDeclaration"] = 15] = "BeforeDeclaration";
802
+ State[State["InDeclaration"] = 16] = "InDeclaration";
803
+ // Processing instructions
804
+ State[State["InProcessingInstruction"] = 17] = "InProcessingInstruction";
805
+ // Comments & CDATA
806
+ State[State["BeforeComment"] = 18] = "BeforeComment";
807
+ State[State["CDATASequence"] = 19] = "CDATASequence";
808
+ State[State["DeclarationSequence"] = 20] = "DeclarationSequence";
809
+ State[State["InSpecialComment"] = 21] = "InSpecialComment";
810
+ State[State["InCommentLike"] = 22] = "InCommentLike";
811
+ // Special tags
812
+ State[State["SpecialStartSequence"] = 23] = "SpecialStartSequence";
813
+ State[State["InSpecialTag"] = 24] = "InSpecialTag";
814
+ State[State["InPlainText"] = 25] = "InPlainText";
815
+ State[State["InEntity"] = 26] = "InEntity";
816
+ })(State || (State = {}));
817
+ function isWhitespace(c) {
818
+ return (c === Tokenizer_CharCodes.Space ||
819
+ c === Tokenizer_CharCodes.NewLine ||
820
+ c === Tokenizer_CharCodes.Tab ||
821
+ c === Tokenizer_CharCodes.FormFeed ||
822
+ c === Tokenizer_CharCodes.CarriageReturn);
823
+ }
824
+ function isEndOfTagSection(c) {
825
+ return c === Tokenizer_CharCodes.Slash || c === Tokenizer_CharCodes.Gt || isWhitespace(c);
826
+ }
827
+ function isASCIIAlpha(c) {
828
+ return ((c >= Tokenizer_CharCodes.LowerA && c <= Tokenizer_CharCodes.LowerZ) ||
829
+ (c >= Tokenizer_CharCodes.UpperA && c <= Tokenizer_CharCodes.UpperZ));
830
+ }
831
+ /**
832
+ * Quote style used for parsed attributes.
833
+ */
834
+ var QuoteType;
835
+ (function (QuoteType) {
836
+ QuoteType[QuoteType["NoValue"] = 0] = "NoValue";
837
+ QuoteType[QuoteType["Unquoted"] = 1] = "Unquoted";
838
+ QuoteType[QuoteType["Single"] = 2] = "Single";
839
+ QuoteType[QuoteType["Double"] = 3] = "Double";
840
+ })(QuoteType || (QuoteType = {}));
841
+ /**
842
+ * Sequences used to match longer strings.
843
+ *
844
+ * We don't have `Script`, `Style`, or `Title` here. Instead, we re-use the *End
845
+ * sequences with an increased offset.
846
+ */
847
+ const Sequences = {
848
+ Empty: new Uint8Array(0),
849
+ Cdata: new Uint8Array([0x43, 0x44, 0x41, 0x54, 0x41, 0x5b]), // CDATA[
850
+ CdataEnd: new Uint8Array([0x5d, 0x5d, 0x3e]), // ]]>
851
+ CommentEnd: new Uint8Array([0x2d, 0x2d, 0x21, 0x3e]), // `--!>`
852
+ Doctype: new Uint8Array([0x64, 0x6f, 0x63, 0x74, 0x79, 0x70, 0x65]), // `doctype`
853
+ IframeEnd: new Uint8Array([0x3c, 0x2f, 0x69, 0x66, 0x72, 0x61, 0x6d, 0x65]), // `</iframe`
854
+ NoembedEnd: new Uint8Array([
855
+ 0x3c, 0x2f, 0x6e, 0x6f, 0x65, 0x6d, 0x62, 0x65, 0x64,
856
+ ]), // `</noembed`
857
+ NoframesEnd: new Uint8Array([
858
+ 0x3c, 0x2f, 0x6e, 0x6f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73,
859
+ ]), // `</noframes`
860
+ Plaintext: new Uint8Array([
861
+ 0x3c, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74,
862
+ ]), // `</plaintext`
863
+ ScriptEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74]), // `</script`
864
+ StyleEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65]), // `</style`
865
+ TitleEnd: new Uint8Array([0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65]), // `</title`
866
+ TextareaEnd: new Uint8Array([
867
+ 0x3c, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x61, 0x72, 0x65, 0x61,
868
+ ]), // `</textarea`
869
+ XmpEnd: new Uint8Array([0x3c, 0x2f, 0x78, 0x6d, 0x70]), // `</xmp`
870
+ };
871
+ /**
872
+ * Maps the first lowercase character of an HTML tag name to the sequence
873
+ * used for special-tag detection. All sequences share a common layout
874
+ * where index 2 is the first tag-name character, so matching always
875
+ * continues from offset 3.
876
+ */
877
+ const specialStartSequences = new Map([
878
+ [Sequences.IframeEnd[2], Sequences.IframeEnd],
879
+ [Sequences.NoembedEnd[2], Sequences.NoembedEnd],
880
+ [Sequences.Plaintext[2], Sequences.Plaintext],
881
+ [Sequences.ScriptEnd[2], Sequences.ScriptEnd],
882
+ [Sequences.TitleEnd[2], Sequences.TitleEnd],
883
+ [Sequences.XmpEnd[2], Sequences.XmpEnd],
884
+ ]);
885
+ /**
886
+ * Tokenizer implementation used by `Parser`.
887
+ */
888
+ class Tokenizer {
889
+ cbs;
890
+ /** The current state the tokenizer is in. */
891
+ state = State.Text;
892
+ /** The read buffer. */
893
+ buffer = "";
894
+ /** The beginning of the section that is currently being read. */
895
+ sectionStart = 0;
896
+ /** The index within the buffer that we are currently looking at. */
897
+ index = 0;
898
+ /** The start of the last entity. */
899
+ entityStart = 0;
900
+ /** Some behavior, eg. when decoding entities, is done while we are in another state. This keeps track of the other state type. */
901
+ baseState = State.Text;
902
+ /** For special parsing behavior inside of script and style tags. */
903
+ isSpecial = false;
904
+ /** Indicates whether the tokenizer has been paused. */
905
+ running = true;
906
+ /** The offset of the current buffer. */
907
+ offset = 0;
908
+ xmlMode;
909
+ decodeEntities;
910
+ recognizeSelfClosing;
911
+ entityDecoder;
912
+ constructor({ xmlMode = false, decodeEntities = true, recognizeSelfClosing = xmlMode, }, cbs) {
913
+ this.cbs = cbs;
914
+ this.xmlMode = xmlMode;
915
+ this.decodeEntities = decodeEntities;
916
+ this.recognizeSelfClosing = recognizeSelfClosing;
917
+ this.entityDecoder = new EntityDecoder(xmlMode ? decode_data_xml_xmlDecodeTree : decode_data_html_htmlDecodeTree, (cp, consumed) => this.emitCodePoint(cp, consumed));
918
+ }
919
+ reset() {
920
+ this.state = State.Text;
921
+ this.buffer = "";
922
+ this.sectionStart = 0;
923
+ this.index = 0;
924
+ this.baseState = State.Text;
925
+ this.isSpecial = false;
926
+ this.currentSequence = Sequences.Empty;
927
+ this.sequenceIndex = 0;
928
+ this.running = true;
929
+ this.offset = 0;
930
+ }
931
+ write(chunk) {
932
+ this.offset += this.buffer.length;
933
+ this.buffer = chunk;
934
+ this.parse();
935
+ }
936
+ end() {
937
+ if (this.running)
938
+ this.finish();
939
+ }
940
+ pause() {
941
+ this.running = false;
942
+ }
943
+ resume() {
944
+ this.running = true;
945
+ if (this.index < this.buffer.length + this.offset) {
946
+ this.parse();
947
+ }
948
+ }
949
+ stateText(c) {
950
+ if (c === Tokenizer_CharCodes.Lt ||
951
+ (!this.decodeEntities && this.fastForwardTo(Tokenizer_CharCodes.Lt))) {
952
+ if (this.index > this.sectionStart) {
953
+ this.cbs.ontext(this.sectionStart, this.index);
954
+ }
955
+ this.state = State.BeforeTagName;
956
+ this.sectionStart = this.index;
957
+ }
958
+ else if (this.decodeEntities && c === Tokenizer_CharCodes.Amp) {
959
+ this.startEntity();
960
+ }
961
+ }
962
+ currentSequence = Sequences.Empty;
963
+ sequenceIndex = 0;
964
+ enterTagBody() {
965
+ if (this.currentSequence === Sequences.Plaintext) {
966
+ this.currentSequence = Sequences.Empty;
967
+ this.state = State.InPlainText;
968
+ }
969
+ else if (this.isSpecial) {
970
+ this.state = State.InSpecialTag;
971
+ this.sequenceIndex = 0;
972
+ }
973
+ else {
974
+ this.state = State.Text;
975
+ }
976
+ }
977
+ /**
978
+ * Match the opening tag name against an HTML text-only tag sequence.
979
+ *
980
+ * Some tags share an initial prefix (`script`/`style`, `title`/`textarea`,
981
+ * `noembed`/`noframes`), so we may switch to an alternate sequence at the
982
+ * first distinguishing byte. On a successful full match we fall back to
983
+ * the normal tag-name state; a later `>` will enter raw-text, RCDATA, or
984
+ * plaintext mode based on `currentSequence` / `isSpecial`.
985
+ * @param c Current character code point.
986
+ */
987
+ stateSpecialStartSequence(c) {
988
+ const lower = c | 0x20;
989
+ // Still matching — check for an alternate sequence at branch points.
990
+ if (this.sequenceIndex < this.currentSequence.length) {
991
+ if (lower === this.currentSequence[this.sequenceIndex]) {
992
+ this.sequenceIndex++;
993
+ return;
994
+ }
995
+ if (this.sequenceIndex === 3) {
996
+ if (this.currentSequence === Sequences.ScriptEnd &&
997
+ lower === Sequences.StyleEnd[3]) {
998
+ this.currentSequence = Sequences.StyleEnd;
999
+ this.sequenceIndex = 4;
1000
+ return;
1001
+ }
1002
+ if (this.currentSequence === Sequences.TitleEnd &&
1003
+ lower === Sequences.TextareaEnd[3]) {
1004
+ this.currentSequence = Sequences.TextareaEnd;
1005
+ this.sequenceIndex = 4;
1006
+ return;
1007
+ }
1008
+ }
1009
+ else if (this.sequenceIndex === 4 &&
1010
+ this.currentSequence === Sequences.NoembedEnd &&
1011
+ lower === Sequences.NoframesEnd[4]) {
1012
+ this.currentSequence = Sequences.NoframesEnd;
1013
+ this.sequenceIndex = 5;
1014
+ return;
1015
+ }
1016
+ }
1017
+ else if (isEndOfTagSection(c)) {
1018
+ // Full match on a valid tag boundary — keep the sequence.
1019
+ this.sequenceIndex = 0;
1020
+ this.state = State.InTagName;
1021
+ this.stateInTagName(c);
1022
+ return;
1023
+ }
1024
+ // No match — abandon special-tag detection.
1025
+ this.isSpecial = false;
1026
+ this.currentSequence = Sequences.Empty;
1027
+ this.sequenceIndex = 0;
1028
+ this.state = State.InTagName;
1029
+ this.stateInTagName(c);
1030
+ }
1031
+ stateCDATASequence(c) {
1032
+ if (c === Sequences.Cdata[this.sequenceIndex]) {
1033
+ if (++this.sequenceIndex === Sequences.Cdata.length) {
1034
+ this.state = State.InCommentLike;
1035
+ this.currentSequence = Sequences.CdataEnd;
1036
+ this.sequenceIndex = 0;
1037
+ this.sectionStart = this.index + 1;
1038
+ }
1039
+ }
1040
+ else {
1041
+ this.sequenceIndex = 0;
1042
+ if (this.xmlMode) {
1043
+ this.state = State.InDeclaration;
1044
+ this.stateInDeclaration(c); // Reconsume the character
1045
+ }
1046
+ else {
1047
+ this.state = State.InSpecialComment;
1048
+ this.stateInSpecialComment(c); // Reconsume the character
1049
+ }
1050
+ }
1051
+ }
1052
+ /**
1053
+ * When we wait for one specific character, we can speed things up
1054
+ * by skipping through the buffer until we find it.
1055
+ * @param c Current character code point.
1056
+ * @returns Whether the character was found.
1057
+ */
1058
+ fastForwardTo(c) {
1059
+ while (++this.index < this.buffer.length + this.offset) {
1060
+ if (this.buffer.charCodeAt(this.index - this.offset) === c) {
1061
+ return true;
1062
+ }
1063
+ }
1064
+ /*
1065
+ * We increment the index at the end of the `parse` loop,
1066
+ * so set it to `buffer.length - 1` here.
1067
+ *
1068
+ * TODO: Refactor `parse` to increment index before calling states.
1069
+ */
1070
+ this.index = this.buffer.length + this.offset - 1;
1071
+ return false;
1072
+ }
1073
+ /**
1074
+ * Emit a comment token and return to the text state.
1075
+ * @param offset Number of characters in the end sequence that have already been matched.
1076
+ */
1077
+ emitComment(offset) {
1078
+ this.cbs.oncomment(this.sectionStart, this.index, offset);
1079
+ this.sequenceIndex = 0;
1080
+ this.sectionStart = this.index + 1;
1081
+ this.state = State.Text;
1082
+ }
1083
+ /**
1084
+ * Comments and CDATA end with `-->` and `]]>`.
1085
+ *
1086
+ * Their common qualities are:
1087
+ * - Their end sequences have a distinct character they start with.
1088
+ * - That character is then repeated, so we have to check multiple repeats.
1089
+ * - All characters but the start character of the sequence can be skipped.
1090
+ * @param c Current character code point.
1091
+ */
1092
+ stateInCommentLike(c) {
1093
+ if (!this.xmlMode &&
1094
+ this.currentSequence === Sequences.CommentEnd &&
1095
+ this.sequenceIndex <= 1 &&
1096
+ /*
1097
+ * We're still at the very start of the comment: the only
1098
+ * characters consumed since `<!--` are the dashes that
1099
+ * advanced sequenceIndex (0 for `<!-->`, 1 for `<!--->`).
1100
+ */
1101
+ this.index === this.sectionStart + this.sequenceIndex &&
1102
+ c === Tokenizer_CharCodes.Gt) {
1103
+ // Abruptly closed empty HTML comment.
1104
+ this.emitComment(this.sequenceIndex);
1105
+ }
1106
+ else if (this.currentSequence === Sequences.CommentEnd &&
1107
+ this.sequenceIndex === 2 &&
1108
+ c === Tokenizer_CharCodes.Gt) {
1109
+ // `!` is optional here, so the same sequence also accepts `-->`.
1110
+ this.emitComment(2);
1111
+ }
1112
+ else if (this.currentSequence === Sequences.CommentEnd &&
1113
+ this.sequenceIndex === this.currentSequence.length - 1 &&
1114
+ c !== Tokenizer_CharCodes.Gt) {
1115
+ this.sequenceIndex = Number(c === Tokenizer_CharCodes.Dash);
1116
+ }
1117
+ else if (c === this.currentSequence[this.sequenceIndex]) {
1118
+ if (++this.sequenceIndex === this.currentSequence.length) {
1119
+ if (this.currentSequence === Sequences.CdataEnd) {
1120
+ this.cbs.oncdata(this.sectionStart, this.index, 2);
1121
+ }
1122
+ else {
1123
+ this.cbs.oncomment(this.sectionStart, this.index, 3);
1124
+ }
1125
+ this.sequenceIndex = 0;
1126
+ this.sectionStart = this.index + 1;
1127
+ this.state = State.Text;
1128
+ }
1129
+ }
1130
+ else if (this.sequenceIndex === 0) {
1131
+ // Fast-forward to the first character of the sequence
1132
+ if (this.fastForwardTo(this.currentSequence[0])) {
1133
+ this.sequenceIndex = 1;
1134
+ }
1135
+ }
1136
+ else if (c !== this.currentSequence[this.sequenceIndex - 1]) {
1137
+ // Allow long sequences, eg. --->, ]]]>
1138
+ this.sequenceIndex = 0;
1139
+ }
1140
+ }
1141
+ /**
1142
+ * HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a tag name.
1143
+ *
1144
+ * XML allows a lot more characters here (@see https://www.w3.org/TR/REC-xml/#NT-NameStartChar).
1145
+ * We allow anything that wouldn't end the tag.
1146
+ * @param c Current character code point.
1147
+ */
1148
+ isTagStartChar(c) {
1149
+ return this.xmlMode ? !isEndOfTagSection(c) : isASCIIAlpha(c);
1150
+ }
1151
+ /**
1152
+ * Scan raw-text / RCDATA content for the matching end tag.
1153
+ *
1154
+ * For RCDATA tags (`<title>`, `<textarea>`) entities are decoded inline.
1155
+ * For raw-text tags (`<script>`, `<style>`, etc.) we fast-forward to `<`.
1156
+ * @param c Current character code point.
1157
+ */
1158
+ stateInSpecialTag(c) {
1159
+ if (this.sequenceIndex === this.currentSequence.length) {
1160
+ if (isEndOfTagSection(c)) {
1161
+ const endOfText = this.index - this.currentSequence.length;
1162
+ if (this.sectionStart < endOfText) {
1163
+ // Spoof the index so that reported locations match up.
1164
+ const actualIndex = this.index;
1165
+ this.index = endOfText;
1166
+ this.cbs.ontext(this.sectionStart, endOfText);
1167
+ this.index = actualIndex;
1168
+ }
1169
+ this.isSpecial = false;
1170
+ this.sectionStart = endOfText + 2; // Skip over the `</`
1171
+ this.stateInClosingTagName(c);
1172
+ return; // We are done; skip the rest of the function.
1173
+ }
1174
+ this.sequenceIndex = 0;
1175
+ }
1176
+ if ((c | 0x20) === this.currentSequence[this.sequenceIndex]) {
1177
+ this.sequenceIndex += 1;
1178
+ }
1179
+ else if (this.sequenceIndex === 0) {
1180
+ if (this.currentSequence === Sequences.TitleEnd ||
1181
+ this.currentSequence === Sequences.TextareaEnd) {
1182
+ // RCDATA tags have to parse entities while still looking for their end tag.
1183
+ if (this.decodeEntities && c === Tokenizer_CharCodes.Amp) {
1184
+ this.startEntity();
1185
+ }
1186
+ }
1187
+ else if (this.fastForwardTo(Tokenizer_CharCodes.Lt)) {
1188
+ // Outside of RCDATA tags, we can fast-forward.
1189
+ this.sequenceIndex = 1;
1190
+ }
1191
+ }
1192
+ else {
1193
+ // If we see a `<`, set the sequence index to 1; useful for eg. `<</script>`.
1194
+ this.sequenceIndex = Number(c === Tokenizer_CharCodes.Lt);
1195
+ }
1196
+ }
1197
+ stateBeforeTagName(c) {
1198
+ if (c === Tokenizer_CharCodes.ExclamationMark) {
1199
+ this.state = State.BeforeDeclaration;
1200
+ this.sectionStart = this.index + 1;
1201
+ }
1202
+ else if (c === Tokenizer_CharCodes.Questionmark) {
1203
+ if (this.xmlMode) {
1204
+ this.state = State.InProcessingInstruction;
1205
+ this.sequenceIndex = 0;
1206
+ this.sectionStart = this.index + 1;
1207
+ }
1208
+ else {
1209
+ this.state = State.InSpecialComment;
1210
+ this.sectionStart = this.index;
1211
+ }
1212
+ }
1213
+ else if (this.isTagStartChar(c)) {
1214
+ this.sectionStart = this.index;
1215
+ const special = this.xmlMode || this.cbs.isInForeignContext?.()
1216
+ ? undefined
1217
+ : specialStartSequences.get(c | 0x20);
1218
+ if (special === undefined) {
1219
+ this.state = State.InTagName;
1220
+ }
1221
+ else {
1222
+ this.isSpecial = true;
1223
+ this.currentSequence = special;
1224
+ this.sequenceIndex = 3;
1225
+ this.state = State.SpecialStartSequence;
1226
+ }
1227
+ }
1228
+ else if (c === Tokenizer_CharCodes.Slash) {
1229
+ this.state = State.BeforeClosingTagName;
1230
+ }
1231
+ else {
1232
+ this.state = State.Text;
1233
+ this.stateText(c);
1234
+ }
1235
+ }
1236
+ stateInTagName(c) {
1237
+ if (isEndOfTagSection(c)) {
1238
+ this.cbs.onopentagname(this.sectionStart, this.index);
1239
+ this.sectionStart = -1;
1240
+ this.state = State.BeforeAttributeName;
1241
+ this.stateBeforeAttributeName(c);
1242
+ }
1243
+ }
1244
+ stateBeforeClosingTagName(c) {
1245
+ if (isWhitespace(c)) {
1246
+ if (this.xmlMode) {
1247
+ // Ignore
1248
+ }
1249
+ else {
1250
+ this.state = State.InSpecialComment;
1251
+ this.sectionStart = this.index;
1252
+ }
1253
+ }
1254
+ else if (c === Tokenizer_CharCodes.Gt) {
1255
+ this.state = State.Text;
1256
+ if (!this.xmlMode) {
1257
+ this.sectionStart = this.index + 1;
1258
+ }
1259
+ }
1260
+ else {
1261
+ this.state = this.isTagStartChar(c)
1262
+ ? State.InClosingTagName
1263
+ : State.InSpecialComment;
1264
+ this.sectionStart = this.index;
1265
+ }
1266
+ }
1267
+ stateInClosingTagName(c) {
1268
+ if (isEndOfTagSection(c)) {
1269
+ this.cbs.onclosetag(this.sectionStart, this.index);
1270
+ this.sectionStart = -1;
1271
+ this.state = State.AfterClosingTagName;
1272
+ this.stateAfterClosingTagName(c);
1273
+ }
1274
+ }
1275
+ stateAfterClosingTagName(c) {
1276
+ // Skip everything until ">"
1277
+ if (c === Tokenizer_CharCodes.Gt || this.fastForwardTo(Tokenizer_CharCodes.Gt)) {
1278
+ this.state = State.Text;
1279
+ this.sectionStart = this.index + 1;
1280
+ }
1281
+ }
1282
+ stateBeforeAttributeName(c) {
1283
+ if (c === Tokenizer_CharCodes.Gt) {
1284
+ this.cbs.onopentagend(this.index);
1285
+ this.enterTagBody();
1286
+ this.sectionStart = this.index + 1;
1287
+ }
1288
+ else if (c === Tokenizer_CharCodes.Slash) {
1289
+ this.state = State.InSelfClosingTag;
1290
+ }
1291
+ else if (!isWhitespace(c)) {
1292
+ this.state = State.InAttributeName;
1293
+ this.sectionStart = this.index;
1294
+ }
1295
+ }
1296
+ /**
1297
+ * Handle `/` before `>` in an opening tag.
1298
+ *
1299
+ * In HTML mode, text-only tags ignore the self-closing flag and still enter
1300
+ * their raw-text/RCDATA/plaintext state unless self-closing tags are being
1301
+ * recognized. In XML mode, or for ordinary tags, the tokenizer returns to
1302
+ * regular text parsing after emitting the self-closing callback.
1303
+ * @param c Current character code point.
1304
+ */
1305
+ stateInSelfClosingTag(c) {
1306
+ if (c === Tokenizer_CharCodes.Gt) {
1307
+ this.cbs.onselfclosingtag(this.index);
1308
+ this.sectionStart = this.index + 1;
1309
+ if (!this.recognizeSelfClosing) {
1310
+ this.enterTagBody();
1311
+ return;
1312
+ }
1313
+ this.state = State.Text;
1314
+ this.isSpecial = false; // Reset special state, in case of self-closing special tags
1315
+ this.currentSequence = Sequences.Empty;
1316
+ }
1317
+ else if (!isWhitespace(c)) {
1318
+ this.state = State.BeforeAttributeName;
1319
+ this.stateBeforeAttributeName(c);
1320
+ }
1321
+ }
1322
+ stateInAttributeName(c) {
1323
+ if (c === Tokenizer_CharCodes.Eq || isEndOfTagSection(c)) {
1324
+ this.cbs.onattribname(this.sectionStart, this.index);
1325
+ this.sectionStart = this.index;
1326
+ this.state = State.AfterAttributeName;
1327
+ this.stateAfterAttributeName(c);
1328
+ }
1329
+ }
1330
+ stateAfterAttributeName(c) {
1331
+ if (c === Tokenizer_CharCodes.Eq) {
1332
+ this.state = State.BeforeAttributeValue;
1333
+ }
1334
+ else if (c === Tokenizer_CharCodes.Slash || c === Tokenizer_CharCodes.Gt) {
1335
+ this.cbs.onattribend(QuoteType.NoValue, this.sectionStart);
1336
+ this.sectionStart = -1;
1337
+ this.state = State.BeforeAttributeName;
1338
+ this.stateBeforeAttributeName(c);
1339
+ }
1340
+ else if (!isWhitespace(c)) {
1341
+ this.cbs.onattribend(QuoteType.NoValue, this.sectionStart);
1342
+ this.state = State.InAttributeName;
1343
+ this.sectionStart = this.index;
1344
+ }
1345
+ }
1346
+ stateBeforeAttributeValue(c) {
1347
+ if (c === Tokenizer_CharCodes.DoubleQuote) {
1348
+ this.state = State.InAttributeValueDq;
1349
+ this.sectionStart = this.index + 1;
1350
+ }
1351
+ else if (c === Tokenizer_CharCodes.SingleQuote) {
1352
+ this.state = State.InAttributeValueSq;
1353
+ this.sectionStart = this.index + 1;
1354
+ }
1355
+ else if (!isWhitespace(c)) {
1356
+ this.sectionStart = this.index;
1357
+ this.state = State.InAttributeValueNq;
1358
+ this.stateInAttributeValueNoQuotes(c); // Reconsume token
1359
+ }
1360
+ }
1361
+ handleInAttributeValue(c, quote) {
1362
+ if (c === quote ||
1363
+ (!this.decodeEntities && this.fastForwardTo(quote))) {
1364
+ this.cbs.onattribdata(this.sectionStart, this.index);
1365
+ this.sectionStart = -1;
1366
+ this.cbs.onattribend(quote === Tokenizer_CharCodes.DoubleQuote
1367
+ ? QuoteType.Double
1368
+ : QuoteType.Single, this.index + 1);
1369
+ this.state = State.BeforeAttributeName;
1370
+ }
1371
+ else if (this.decodeEntities && c === Tokenizer_CharCodes.Amp) {
1372
+ this.startEntity();
1373
+ }
1374
+ }
1375
+ stateInAttributeValueDoubleQuotes(c) {
1376
+ this.handleInAttributeValue(c, Tokenizer_CharCodes.DoubleQuote);
1377
+ }
1378
+ stateInAttributeValueSingleQuotes(c) {
1379
+ this.handleInAttributeValue(c, Tokenizer_CharCodes.SingleQuote);
1380
+ }
1381
+ stateInAttributeValueNoQuotes(c) {
1382
+ if (isWhitespace(c) || c === Tokenizer_CharCodes.Gt) {
1383
+ this.cbs.onattribdata(this.sectionStart, this.index);
1384
+ this.sectionStart = -1;
1385
+ this.cbs.onattribend(QuoteType.Unquoted, this.index);
1386
+ this.state = State.BeforeAttributeName;
1387
+ this.stateBeforeAttributeName(c);
1388
+ }
1389
+ else if (this.decodeEntities && c === Tokenizer_CharCodes.Amp) {
1390
+ this.startEntity();
1391
+ }
1392
+ }
1393
+ /**
1394
+ * Distinguish between CDATA, declarations, HTML comments, and HTML bogus
1395
+ * comments after `<!`.
1396
+ *
1397
+ * In HTML mode, only real comments and doctypes stay on declaration paths;
1398
+ * everything else becomes a bogus comment terminated by the next `>`.
1399
+ * @param c Current character code point.
1400
+ */
1401
+ stateBeforeDeclaration(c) {
1402
+ if (c === Tokenizer_CharCodes.OpeningSquareBracket) {
1403
+ this.state = State.CDATASequence;
1404
+ this.sequenceIndex = 0;
1405
+ }
1406
+ else if (this.xmlMode) {
1407
+ this.state =
1408
+ c === Tokenizer_CharCodes.Dash
1409
+ ? State.BeforeComment
1410
+ : State.InDeclaration;
1411
+ }
1412
+ else if ((c | 0x20) === Sequences.Doctype[0]) {
1413
+ this.state = State.DeclarationSequence;
1414
+ this.currentSequence = Sequences.Doctype;
1415
+ this.sequenceIndex = 1;
1416
+ }
1417
+ else if (c === Tokenizer_CharCodes.Gt) {
1418
+ this.cbs.oncomment(this.sectionStart, this.index, 0);
1419
+ this.state = State.Text;
1420
+ this.sectionStart = this.index + 1;
1421
+ }
1422
+ else if (c === Tokenizer_CharCodes.Dash) {
1423
+ this.state = State.BeforeComment;
1424
+ }
1425
+ else {
1426
+ this.state = State.InSpecialComment;
1427
+ }
1428
+ }
1429
+ /**
1430
+ * Continue matching `doctype` after `<!d`.
1431
+ *
1432
+ * A full `doctype` match stays on the declaration path; any other name falls
1433
+ * back to an HTML bogus comment, which matches browser behavior for
1434
+ * non-doctype `<!...>` constructs.
1435
+ * @param c Current character code point.
1436
+ */
1437
+ stateDeclarationSequence(c) {
1438
+ if (this.sequenceIndex === this.currentSequence.length) {
1439
+ this.state = State.InDeclaration;
1440
+ this.stateInDeclaration(c);
1441
+ }
1442
+ else if ((c | 0x20) === this.currentSequence[this.sequenceIndex]) {
1443
+ this.sequenceIndex += 1;
1444
+ }
1445
+ else if (c === Tokenizer_CharCodes.Gt) {
1446
+ this.cbs.oncomment(this.sectionStart, this.index, 0);
1447
+ this.state = State.Text;
1448
+ this.sectionStart = this.index + 1;
1449
+ }
1450
+ else {
1451
+ this.state = State.InSpecialComment;
1452
+ }
1453
+ }
1454
+ stateInDeclaration(c) {
1455
+ if (c === Tokenizer_CharCodes.Gt || this.fastForwardTo(Tokenizer_CharCodes.Gt)) {
1456
+ this.cbs.ondeclaration(this.sectionStart, this.index);
1457
+ this.state = State.Text;
1458
+ this.sectionStart = this.index + 1;
1459
+ }
1460
+ }
1461
+ /**
1462
+ * XML processing instructions (`<?...?>`).
1463
+ *
1464
+ * In HTML mode `<?` is routed to `InSpecialComment` instead, so this
1465
+ * state is only reachable in XML mode.
1466
+ * @param c Current character code point.
1467
+ */
1468
+ stateInProcessingInstruction(c) {
1469
+ if (c === Tokenizer_CharCodes.Questionmark) {
1470
+ // Remember that we just consumed `?`, so the next `>` closes the PI.
1471
+ this.sequenceIndex = 1;
1472
+ }
1473
+ else if (c === Tokenizer_CharCodes.Gt && this.sequenceIndex === 1) {
1474
+ this.cbs.onprocessinginstruction(this.sectionStart, this.index - 1);
1475
+ this.sequenceIndex = 0;
1476
+ this.state = State.Text;
1477
+ this.sectionStart = this.index + 1;
1478
+ }
1479
+ else {
1480
+ // Keep scanning for the next `?`, which can start a closing `?>`.
1481
+ this.sequenceIndex = Number(this.fastForwardTo(Tokenizer_CharCodes.Questionmark));
1482
+ }
1483
+ }
1484
+ stateBeforeComment(c) {
1485
+ if (c === Tokenizer_CharCodes.Dash) {
1486
+ this.state = State.InCommentLike;
1487
+ this.currentSequence = Sequences.CommentEnd;
1488
+ this.sequenceIndex = 0;
1489
+ this.sectionStart = this.index + 1;
1490
+ }
1491
+ else if (this.xmlMode) {
1492
+ this.state = State.InDeclaration;
1493
+ }
1494
+ else if (c === Tokenizer_CharCodes.Gt) {
1495
+ this.cbs.oncomment(this.sectionStart, this.index, 0);
1496
+ this.state = State.Text;
1497
+ this.sectionStart = this.index + 1;
1498
+ }
1499
+ else {
1500
+ this.state = State.InSpecialComment;
1501
+ }
1502
+ }
1503
+ stateInSpecialComment(c) {
1504
+ if (c === Tokenizer_CharCodes.Gt || this.fastForwardTo(Tokenizer_CharCodes.Gt)) {
1505
+ this.cbs.oncomment(this.sectionStart, this.index, 0);
1506
+ this.state = State.Text;
1507
+ this.sectionStart = this.index + 1;
1508
+ }
1509
+ }
1510
+ startEntity() {
1511
+ this.baseState = this.state;
1512
+ this.state = State.InEntity;
1513
+ this.entityStart = this.index;
1514
+ this.entityDecoder.startEntity(this.xmlMode
1515
+ ? DecodingMode.Strict
1516
+ : this.baseState === State.Text ||
1517
+ this.baseState === State.InSpecialTag
1518
+ ? DecodingMode.Legacy
1519
+ : DecodingMode.Attribute);
1520
+ }
1521
+ stateInEntity() {
1522
+ const indexInBuffer = this.index - this.offset;
1523
+ const length = this.entityDecoder.write(this.buffer, indexInBuffer);
1524
+ // If `length` is positive, we are done with the entity.
1525
+ if (length >= 0) {
1526
+ this.state = this.baseState;
1527
+ if (length === 0) {
1528
+ this.index -= 1;
1529
+ }
1530
+ }
1531
+ else {
1532
+ if (indexInBuffer < this.buffer.length &&
1533
+ this.buffer.charCodeAt(indexInBuffer) === Tokenizer_CharCodes.Amp) {
1534
+ this.state = this.baseState;
1535
+ this.index -= 1;
1536
+ return;
1537
+ }
1538
+ // Mark buffer as consumed.
1539
+ this.index = this.offset + this.buffer.length - 1;
1540
+ }
1541
+ }
1542
+ /**
1543
+ * Remove data that has already been consumed from the buffer.
1544
+ */
1545
+ cleanup() {
1546
+ // If we are inside of text or attributes, emit what we already have.
1547
+ if (this.running && this.sectionStart !== this.index) {
1548
+ if (this.state === State.Text ||
1549
+ this.state === State.InPlainText ||
1550
+ (this.state === State.InSpecialTag && this.sequenceIndex === 0)) {
1551
+ this.cbs.ontext(this.sectionStart, this.index);
1552
+ this.sectionStart = this.index;
1553
+ }
1554
+ else if (this.state === State.InAttributeValueDq ||
1555
+ this.state === State.InAttributeValueSq ||
1556
+ this.state === State.InAttributeValueNq) {
1557
+ this.cbs.onattribdata(this.sectionStart, this.index);
1558
+ this.sectionStart = this.index;
1559
+ }
1560
+ }
1561
+ }
1562
+ shouldContinue() {
1563
+ return this.index < this.buffer.length + this.offset && this.running;
1564
+ }
1565
+ /**
1566
+ * Iterates through the buffer, calling the function corresponding to the current state.
1567
+ *
1568
+ * States that are more likely to be hit are higher up, as a performance improvement.
1569
+ */
1570
+ parse() {
1571
+ while (this.shouldContinue()) {
1572
+ const c = this.buffer.charCodeAt(this.index - this.offset);
1573
+ switch (this.state) {
1574
+ case State.Text: {
1575
+ this.stateText(c);
1576
+ break;
1577
+ }
1578
+ case State.InPlainText: {
1579
+ // Skip to end of buffer; cleanup() emits the text.
1580
+ this.index = this.buffer.length + this.offset - 1;
1581
+ break;
1582
+ }
1583
+ case State.SpecialStartSequence: {
1584
+ this.stateSpecialStartSequence(c);
1585
+ break;
1586
+ }
1587
+ case State.InSpecialTag: {
1588
+ this.stateInSpecialTag(c);
1589
+ break;
1590
+ }
1591
+ case State.CDATASequence: {
1592
+ this.stateCDATASequence(c);
1593
+ break;
1594
+ }
1595
+ case State.DeclarationSequence: {
1596
+ this.stateDeclarationSequence(c);
1597
+ break;
1598
+ }
1599
+ case State.InAttributeValueDq: {
1600
+ this.stateInAttributeValueDoubleQuotes(c);
1601
+ break;
1602
+ }
1603
+ case State.InAttributeName: {
1604
+ this.stateInAttributeName(c);
1605
+ break;
1606
+ }
1607
+ case State.InCommentLike: {
1608
+ this.stateInCommentLike(c);
1609
+ break;
1610
+ }
1611
+ case State.InSpecialComment: {
1612
+ this.stateInSpecialComment(c);
1613
+ break;
1614
+ }
1615
+ case State.BeforeAttributeName: {
1616
+ this.stateBeforeAttributeName(c);
1617
+ break;
1618
+ }
1619
+ case State.InTagName: {
1620
+ this.stateInTagName(c);
1621
+ break;
1622
+ }
1623
+ case State.InClosingTagName: {
1624
+ this.stateInClosingTagName(c);
1625
+ break;
1626
+ }
1627
+ case State.BeforeTagName: {
1628
+ this.stateBeforeTagName(c);
1629
+ break;
1630
+ }
1631
+ case State.AfterAttributeName: {
1632
+ this.stateAfterAttributeName(c);
1633
+ break;
1634
+ }
1635
+ case State.InAttributeValueSq: {
1636
+ this.stateInAttributeValueSingleQuotes(c);
1637
+ break;
1638
+ }
1639
+ case State.BeforeAttributeValue: {
1640
+ this.stateBeforeAttributeValue(c);
1641
+ break;
1642
+ }
1643
+ case State.BeforeClosingTagName: {
1644
+ this.stateBeforeClosingTagName(c);
1645
+ break;
1646
+ }
1647
+ case State.AfterClosingTagName: {
1648
+ this.stateAfterClosingTagName(c);
1649
+ break;
1650
+ }
1651
+ case State.InAttributeValueNq: {
1652
+ this.stateInAttributeValueNoQuotes(c);
1653
+ break;
1654
+ }
1655
+ case State.InSelfClosingTag: {
1656
+ this.stateInSelfClosingTag(c);
1657
+ break;
1658
+ }
1659
+ case State.InDeclaration: {
1660
+ this.stateInDeclaration(c);
1661
+ break;
1662
+ }
1663
+ case State.BeforeDeclaration: {
1664
+ this.stateBeforeDeclaration(c);
1665
+ break;
1666
+ }
1667
+ case State.BeforeComment: {
1668
+ this.stateBeforeComment(c);
1669
+ break;
1670
+ }
1671
+ case State.InProcessingInstruction: {
1672
+ this.stateInProcessingInstruction(c);
1673
+ break;
1674
+ }
1675
+ case State.InEntity: {
1676
+ this.stateInEntity();
1677
+ break;
1678
+ }
1679
+ }
1680
+ this.index++;
1681
+ }
1682
+ this.cleanup();
1683
+ }
1684
+ finish() {
1685
+ if (this.state === State.InEntity) {
1686
+ this.entityDecoder.end();
1687
+ this.state = this.baseState;
1688
+ }
1689
+ this.handleTrailingData();
1690
+ this.cbs.onend();
1691
+ }
1692
+ handleTrailingCommentLikeData(endIndex) {
1693
+ if (this.state !== State.InCommentLike) {
1694
+ return false;
1695
+ }
1696
+ if (this.currentSequence === Sequences.CdataEnd) {
1697
+ if (this.xmlMode) {
1698
+ if (this.sectionStart < endIndex) {
1699
+ this.cbs.oncdata(this.sectionStart, endIndex, 0);
1700
+ }
1701
+ }
1702
+ else {
1703
+ /* In HTML mode, unclosed CDATA is a bogus comment. */
1704
+ const cdataStart = this.sectionStart - Sequences.Cdata.length - 1;
1705
+ this.cbs.oncomment(cdataStart, endIndex, 0);
1706
+ }
1707
+ }
1708
+ else {
1709
+ const offset = this.xmlMode
1710
+ ? 0
1711
+ : Math.min(this.sequenceIndex, Sequences.CommentEnd.length - 1);
1712
+ this.cbs.oncomment(this.sectionStart, endIndex, offset);
1713
+ }
1714
+ return true;
1715
+ }
1716
+ handleTrailingMarkupDeclaration(endIndex) {
1717
+ if (this.xmlMode) {
1718
+ switch (this.state) {
1719
+ case State.InSpecialComment:
1720
+ case State.BeforeComment:
1721
+ case State.CDATASequence:
1722
+ case State.DeclarationSequence:
1723
+ case State.InDeclaration: {
1724
+ this.cbs.ontext(this.sectionStart, endIndex);
1725
+ return true;
1726
+ }
1727
+ default: {
1728
+ return false;
1729
+ }
1730
+ }
1731
+ }
1732
+ switch (this.state) {
1733
+ case State.BeforeDeclaration:
1734
+ case State.InSpecialComment:
1735
+ case State.BeforeComment:
1736
+ case State.CDATASequence: {
1737
+ this.cbs.oncomment(this.sectionStart, endIndex, 0);
1738
+ return true;
1739
+ }
1740
+ case State.DeclarationSequence: {
1741
+ if (this.sequenceIndex !== Sequences.Doctype.length) {
1742
+ this.cbs.oncomment(this.sectionStart, endIndex, 0);
1743
+ }
1744
+ return true;
1745
+ }
1746
+ case State.InDeclaration: {
1747
+ return true;
1748
+ }
1749
+ default: {
1750
+ return false;
1751
+ }
1752
+ }
1753
+ }
1754
+ /** Handle any trailing data. */
1755
+ handleTrailingData() {
1756
+ const endIndex = this.buffer.length + this.offset;
1757
+ if (this.handleTrailingCommentLikeData(endIndex) ||
1758
+ this.handleTrailingMarkupDeclaration(endIndex)) {
1759
+ return;
1760
+ }
1761
+ // If there is no remaining data, we are done.
1762
+ if (this.sectionStart >= endIndex) {
1763
+ return;
1764
+ }
1765
+ switch (this.state) {
1766
+ case State.InTagName:
1767
+ case State.BeforeAttributeName:
1768
+ case State.BeforeAttributeValue:
1769
+ case State.AfterAttributeName:
1770
+ case State.InAttributeName:
1771
+ case State.InAttributeValueSq:
1772
+ case State.InAttributeValueDq:
1773
+ case State.InAttributeValueNq:
1774
+ case State.InClosingTagName: {
1775
+ /*
1776
+ * If we are currently in an opening or closing tag, us not calling the
1777
+ * respective callback signals that the tag should be ignored.
1778
+ */
1779
+ break;
1780
+ }
1781
+ default: {
1782
+ this.cbs.ontext(this.sectionStart, endIndex);
1783
+ }
1784
+ }
1785
+ }
1786
+ emitCodePoint(cp, consumed) {
1787
+ if (this.baseState !== State.Text &&
1788
+ this.baseState !== State.InSpecialTag) {
1789
+ if (this.sectionStart < this.entityStart) {
1790
+ this.cbs.onattribdata(this.sectionStart, this.entityStart);
1791
+ }
1792
+ this.sectionStart = this.entityStart + consumed;
1793
+ this.index = this.sectionStart - 1;
1794
+ this.cbs.onattribentity(cp);
1795
+ }
1796
+ else {
1797
+ if (this.sectionStart < this.entityStart) {
1798
+ this.cbs.ontext(this.sectionStart, this.entityStart);
1799
+ }
1800
+ this.sectionStart = this.entityStart + consumed;
1801
+ this.index = this.sectionStart - 1;
1802
+ this.cbs.ontextentity(cp, this.sectionStart);
1803
+ }
1804
+ }
1805
+ }
1806
+ //# sourceMappingURL=Tokenizer.js.map
1807
+ ;// ./node_modules/htmlparser2/dist/Parser.js
1808
+ const { fromCodePoint } = String;
1809
+
1810
+ const formTags = new Set([
1811
+ "input",
1812
+ "option",
1813
+ "optgroup",
1814
+ "select",
1815
+ "button",
1816
+ "datalist",
1817
+ "textarea",
1818
+ ]);
1819
+ const pTag = new Set(["p"]);
1820
+ const headingTags = new Set(["h1", "h2", "h3", "h4", "h5", "h6", "p"]);
1821
+ const tableSectionTags = new Set(["thead", "tbody"]);
1822
+ const ddtTags = new Set(["dd", "dt"]);
1823
+ const rtpTags = new Set(["rt", "rp"]);
1824
+ const openImpliesClose = new Map([
1825
+ ["tr", new Set(["tr", "th", "td"])],
1826
+ ["th", new Set(["th"])],
1827
+ ["td", new Set(["thead", "th", "td"])],
1828
+ ["body", new Set(["head", "link", "script"])],
1829
+ ["a", new Set(["a"])],
1830
+ ["li", new Set(["li"])],
1831
+ ["p", pTag],
1832
+ ["h1", headingTags],
1833
+ ["h2", headingTags],
1834
+ ["h3", headingTags],
1835
+ ["h4", headingTags],
1836
+ ["h5", headingTags],
1837
+ ["h6", headingTags],
1838
+ ["select", formTags],
1839
+ ["input", formTags],
1840
+ ["output", formTags],
1841
+ ["button", formTags],
1842
+ ["datalist", formTags],
1843
+ ["textarea", formTags],
1844
+ ["option", new Set(["option"])],
1845
+ ["optgroup", new Set(["optgroup", "option"])],
1846
+ ["dd", ddtTags],
1847
+ ["dt", ddtTags],
1848
+ ["address", pTag],
1849
+ ["article", pTag],
1850
+ ["aside", pTag],
1851
+ ["blockquote", pTag],
1852
+ ["details", pTag],
1853
+ ["div", pTag],
1854
+ ["dl", pTag],
1855
+ ["fieldset", pTag],
1856
+ ["figcaption", pTag],
1857
+ ["figure", pTag],
1858
+ ["footer", pTag],
1859
+ ["form", pTag],
1860
+ ["header", pTag],
1861
+ ["hr", pTag],
1862
+ ["main", pTag],
1863
+ ["nav", pTag],
1864
+ ["ol", pTag],
1865
+ ["pre", pTag],
1866
+ ["section", pTag],
1867
+ ["table", pTag],
1868
+ ["ul", pTag],
1869
+ ["rt", rtpTags],
1870
+ ["rp", rtpTags],
1871
+ ["tbody", tableSectionTags],
1872
+ ["tfoot", tableSectionTags],
1873
+ ]);
1874
+ const DOCUMENT_TYPE = "doctype";
1875
+ const voidElements = new Set([
1876
+ "area",
1877
+ "base",
1878
+ "basefont",
1879
+ "br",
1880
+ "col",
1881
+ "command",
1882
+ "embed",
1883
+ "frame",
1884
+ "hr",
1885
+ "img",
1886
+ "input",
1887
+ "isindex",
1888
+ "keygen",
1889
+ "link",
1890
+ "meta",
1891
+ "param",
1892
+ "source",
1893
+ "track",
1894
+ "wbr",
1895
+ ]);
1896
+ const foreignContextElements = new Set(["math", "svg"]);
1897
+ /**
1898
+ * Elements that can be used to integrate HTML content within foreign namespaces (e.g., SVG or MathML).
1899
+ *
1900
+ * Entries must use the SVG-adjusted casing (e.g. "foreignObject" not
1901
+ * "foreignobject") since they are compared against adjusted tag names.
1902
+ */
1903
+ const htmlIntegrationElements = new Set([
1904
+ "mi",
1905
+ "mo",
1906
+ "mn",
1907
+ "ms",
1908
+ "mtext",
1909
+ "annotation-xml",
1910
+ "foreignObject",
1911
+ "desc",
1912
+ "title",
1913
+ ]);
1914
+ const svgTagNameAdjustments = new Map([
1915
+ ["altglyph", "altGlyph"],
1916
+ ["altglyphdef", "altGlyphDef"],
1917
+ ["altglyphitem", "altGlyphItem"],
1918
+ ["animatecolor", "animateColor"],
1919
+ ["animatemotion", "animateMotion"],
1920
+ ["animatetransform", "animateTransform"],
1921
+ ["clippath", "clipPath"],
1922
+ ["feblend", "feBlend"],
1923
+ ["fecolormatrix", "feColorMatrix"],
1924
+ ["fecomponenttransfer", "feComponentTransfer"],
1925
+ ["fecomposite", "feComposite"],
1926
+ ["feconvolvematrix", "feConvolveMatrix"],
1927
+ ["fediffuselighting", "feDiffuseLighting"],
1928
+ ["fedisplacementmap", "feDisplacementMap"],
1929
+ ["fedistantlight", "feDistantLight"],
1930
+ ["fedropshadow", "feDropShadow"],
1931
+ ["feflood", "feFlood"],
1932
+ ["fefunca", "feFuncA"],
1933
+ ["fefuncb", "feFuncB"],
1934
+ ["fefuncg", "feFuncG"],
1935
+ ["fefuncr", "feFuncR"],
1936
+ ["fegaussianblur", "feGaussianBlur"],
1937
+ ["feimage", "feImage"],
1938
+ ["femerge", "feMerge"],
1939
+ ["femergenode", "feMergeNode"],
1940
+ ["femorphology", "feMorphology"],
1941
+ ["feoffset", "feOffset"],
1942
+ ["fepointlight", "fePointLight"],
1943
+ ["fespecularlighting", "feSpecularLighting"],
1944
+ ["fespotlight", "feSpotLight"],
1945
+ ["fetile", "feTile"],
1946
+ ["feturbulence", "feTurbulence"],
1947
+ ["foreignobject", "foreignObject"],
1948
+ ["glyphref", "glyphRef"],
1949
+ ["lineargradient", "linearGradient"],
1950
+ ["radialgradient", "radialGradient"],
1951
+ ["textpath", "textPath"],
1952
+ ]);
1953
+ var ForeignContext;
1954
+ (function (ForeignContext) {
1955
+ ForeignContext[ForeignContext["None"] = 0] = "None";
1956
+ ForeignContext[ForeignContext["Svg"] = 1] = "Svg";
1957
+ ForeignContext[ForeignContext["MathML"] = 2] = "MathML";
1958
+ })(ForeignContext || (ForeignContext = {}));
1959
+ const reNameEnd = /\s|\//;
1960
+ /**
1961
+ * Incremental parser implementation.
1962
+ */
1963
+ class Parser_Parser {
1964
+ options;
1965
+ /** The start index of the last event. */
1966
+ startIndex = 0;
1967
+ /** The end index of the last event. */
1968
+ endIndex = 0;
1969
+ /**
1970
+ * Store the start index of the current open tag,
1971
+ * so we can update the start index for attributes.
1972
+ */
1973
+ openTagStart = 0;
1974
+ tagname = "";
1975
+ attribname = "";
1976
+ attribvalue = "";
1977
+ attribs = null;
1978
+ stack = [];
1979
+ foreignContext;
1980
+ cbs;
1981
+ lowerCaseTagNames;
1982
+ lowerCaseAttributeNames;
1983
+ recognizeSelfClosing;
1984
+ /** We are parsing HTML. Inverse of the `xmlMode` option. */
1985
+ htmlMode;
1986
+ tokenizer;
1987
+ buffers = [];
1988
+ bufferOffset = 0;
1989
+ /** The index of the last written buffer. Used when resuming after a `pause()`. */
1990
+ writeIndex = 0;
1991
+ /** Indicates whether the parser has finished running / `.end` has been called. */
1992
+ ended = false;
1993
+ constructor(cbs, options = {}) {
1994
+ this.options = options;
1995
+ this.cbs = cbs ?? {};
1996
+ this.htmlMode = !this.options.xmlMode;
1997
+ this.lowerCaseTagNames = options.lowerCaseTags ?? this.htmlMode;
1998
+ this.lowerCaseAttributeNames =
1999
+ options.lowerCaseAttributeNames ?? this.htmlMode;
2000
+ this.recognizeSelfClosing =
2001
+ options.recognizeSelfClosing ?? !this.htmlMode;
2002
+ this.tokenizer = new (options.Tokenizer ?? Tokenizer)(this.options, this);
2003
+ this.foreignContext = [ForeignContext.None];
2004
+ this.cbs.onparserinit?.(this);
2005
+ }
2006
+ // Tokenizer event handlers
2007
+ /**
2008
+ * @param start Start index for the current parser event.
2009
+ * @param endIndex End index for the current parser event.
2010
+ * @internal
2011
+ */
2012
+ ontext(start, endIndex) {
2013
+ const data = this.getSlice(start, endIndex);
2014
+ this.endIndex = endIndex - 1;
2015
+ this.cbs.ontext?.(data);
2016
+ this.startIndex = endIndex;
2017
+ }
2018
+ /**
2019
+ * @param cp Current Unicode code point.
2020
+ * @param endIndex End index for the current parser event.
2021
+ * @internal
2022
+ */
2023
+ ontextentity(cp, endIndex) {
2024
+ this.endIndex = endIndex - 1;
2025
+ this.cbs.ontext?.(fromCodePoint(cp));
2026
+ this.startIndex = endIndex;
2027
+ }
2028
+ /** @internal */
2029
+ isInForeignContext() {
2030
+ return this.foreignContext[0] !== ForeignContext.None;
2031
+ }
2032
+ /**
2033
+ * Checks if the current tag is a void element. Override this if you want
2034
+ * to specify your own additional void elements.
2035
+ * @param name Name of the pseudo selector.
2036
+ */
2037
+ isVoidElement(name) {
2038
+ return this.htmlMode && voidElements.has(name);
2039
+ }
2040
+ /**
2041
+ * Read a tag name from the buffer.
2042
+ *
2043
+ * When `lowerCaseTagNames` is enabled (the default in HTML mode), the name
2044
+ * is lowercased and may be adjusted for SVG casing or the `image` → `img`
2045
+ * alias.
2046
+ * @param start Start index of the tag name in the buffer.
2047
+ * @param endIndex End index of the tag name in the buffer.
2048
+ */
2049
+ readTagName(start, endIndex) {
2050
+ const name = this.lowerCaseTagNames
2051
+ ? this.getSlice(start, endIndex).toLowerCase()
2052
+ : this.getSlice(start, endIndex);
2053
+ if (!(this.lowerCaseTagNames && this.htmlMode)) {
2054
+ return name;
2055
+ }
2056
+ if (this.foreignContext[0] === ForeignContext.Svg) {
2057
+ return svgTagNameAdjustments.get(name) ?? name;
2058
+ }
2059
+ /*
2060
+ * Closing tags for SVG elements inside HTML integration points
2061
+ * (e.g. </foreignObject> while inside its own content) need case
2062
+ * adjustment so the name matches what was pushed to the stack.
2063
+ * `foreignContext.length > 1` means a foreign ancestor exists —
2064
+ * the base [None] entry plus at least one pushed context.
2065
+ */
2066
+ if (this.foreignContext.length > 1) {
2067
+ const adjusted = svgTagNameAdjustments.get(name);
2068
+ if (adjusted !== undefined && this.stack.includes(adjusted)) {
2069
+ return adjusted;
2070
+ }
2071
+ }
2072
+ if (!this.isInForeignContext()) {
2073
+ return name === "image" ? "img" : name;
2074
+ }
2075
+ return name;
2076
+ }
2077
+ /**
2078
+ * @param start Start index for the current parser event.
2079
+ * @param endIndex End index for the current parser event.
2080
+ * @internal
2081
+ */
2082
+ onopentagname(start, endIndex) {
2083
+ this.endIndex = endIndex;
2084
+ this.emitOpenTag(this.readTagName(start, endIndex));
2085
+ }
2086
+ emitOpenTag(name) {
2087
+ this.openTagStart = this.startIndex;
2088
+ this.tagname = name;
2089
+ /*
2090
+ * The spec ignores a second <form> when one is already open.
2091
+ * Setting tagname to "" suppresses all downstream effects: attribs
2092
+ * stays null so endOpenTag is a no-op, and closeCurrentTag can't
2093
+ * match "" on the stack.
2094
+ */
2095
+ if (this.htmlMode && name === "form" && this.stack.includes("form")) {
2096
+ this.tagname = "";
2097
+ return;
2098
+ }
2099
+ const impliesClose = this.htmlMode && openImpliesClose.get(name);
2100
+ if (impliesClose) {
2101
+ while (this.stack.length > 0 && impliesClose.has(this.stack[0])) {
2102
+ this.popElement(true);
2103
+ }
2104
+ }
2105
+ if (!this.isVoidElement(name)) {
2106
+ this.stack.unshift(name);
2107
+ if (this.htmlMode) {
2108
+ if (name === "svg") {
2109
+ this.foreignContext.unshift(ForeignContext.Svg);
2110
+ }
2111
+ else if (name === "math") {
2112
+ this.foreignContext.unshift(ForeignContext.MathML);
2113
+ }
2114
+ else if (htmlIntegrationElements.has(name)) {
2115
+ this.foreignContext.unshift(ForeignContext.None);
2116
+ }
2117
+ }
2118
+ }
2119
+ this.cbs.onopentagname?.(name);
2120
+ if (this.cbs.onopentag)
2121
+ this.attribs = {};
2122
+ }
2123
+ endOpenTag(isImplied) {
2124
+ this.startIndex = this.openTagStart;
2125
+ if (this.attribs) {
2126
+ this.cbs.onopentag?.(this.tagname, this.attribs, isImplied);
2127
+ this.attribs = null;
2128
+ }
2129
+ if (this.cbs.onclosetag && this.isVoidElement(this.tagname)) {
2130
+ this.cbs.onclosetag(this.tagname, true);
2131
+ }
2132
+ this.tagname = "";
2133
+ }
2134
+ /**
2135
+ * @param endIndex End index for the current parser event.
2136
+ * @internal
2137
+ */
2138
+ onopentagend(endIndex) {
2139
+ this.endIndex = endIndex;
2140
+ this.endOpenTag(false);
2141
+ // Set `startIndex` for next node
2142
+ this.startIndex = endIndex + 1;
2143
+ }
2144
+ /**
2145
+ * @param start Start index for the current parser event.
2146
+ * @param endIndex End index for the current parser event.
2147
+ * @internal
2148
+ */
2149
+ onclosetag(start, endIndex) {
2150
+ this.endIndex = endIndex;
2151
+ const name = this.readTagName(start, endIndex);
2152
+ if (!this.isVoidElement(name)) {
2153
+ const pos = this.stack.indexOf(name);
2154
+ if (pos !== -1) {
2155
+ for (let index = 0; index < pos; index++) {
2156
+ this.popElement(true);
2157
+ }
2158
+ this.popElement(false);
2159
+ }
2160
+ else if (this.htmlMode && name === "p") {
2161
+ // Implicit open before close
2162
+ this.emitOpenTag("p");
2163
+ this.closeCurrentTag(true);
2164
+ }
2165
+ }
2166
+ else if (this.htmlMode && name === "br") {
2167
+ // We can't use `emitOpenTag` for implicit open, as `br` would be implicitly closed.
2168
+ this.cbs.onopentagname?.("br");
2169
+ this.cbs.onopentag?.("br", {}, true);
2170
+ this.cbs.onclosetag?.("br", false);
2171
+ }
2172
+ // Set `startIndex` for next node
2173
+ this.startIndex = endIndex + 1;
2174
+ }
2175
+ /**
2176
+ * @param endIndex End index for the current parser event.
2177
+ * @internal
2178
+ */
2179
+ onselfclosingtag(endIndex) {
2180
+ this.endIndex = endIndex;
2181
+ if (this.recognizeSelfClosing || this.isInForeignContext()) {
2182
+ this.closeCurrentTag(false);
2183
+ // Set `startIndex` for next node
2184
+ this.startIndex = endIndex + 1;
2185
+ }
2186
+ else {
2187
+ // Ignore the fact that the tag is self-closing.
2188
+ this.onopentagend(endIndex);
2189
+ }
2190
+ }
2191
+ /**
2192
+ * Pop the top element off the stack, emit a close event, and maintain
2193
+ * the foreign context stack.
2194
+ * @param implied Whether this close is implied (not from an explicit end tag).
2195
+ */
2196
+ popElement(implied) {
2197
+ // biome-ignore lint/style/noNonNullAssertion: The element is guaranteed to exist.
2198
+ const element = this.stack.shift();
2199
+ if (this.htmlMode &&
2200
+ (foreignContextElements.has(element) ||
2201
+ htmlIntegrationElements.has(element))) {
2202
+ this.foreignContext.shift();
2203
+ }
2204
+ this.cbs.onclosetag?.(element, implied);
2205
+ }
2206
+ closeCurrentTag(isOpenImplied) {
2207
+ const name = this.tagname;
2208
+ this.endOpenTag(isOpenImplied);
2209
+ // Self-closing tags will be on the top of the stack
2210
+ if (this.stack[0] === name) {
2211
+ this.popElement(!isOpenImplied);
2212
+ }
2213
+ }
2214
+ /**
2215
+ * @param start Start index for the current parser event.
2216
+ * @param endIndex End index for the current parser event.
2217
+ * @internal
2218
+ */
2219
+ onattribname(start, endIndex) {
2220
+ this.startIndex = start;
2221
+ const name = this.getSlice(start, endIndex);
2222
+ this.attribname = this.lowerCaseAttributeNames
2223
+ ? name.toLowerCase()
2224
+ : name;
2225
+ }
2226
+ /**
2227
+ * @param start Start index for the current parser event.
2228
+ * @param endIndex End index for the current parser event.
2229
+ * @internal
2230
+ */
2231
+ onattribdata(start, endIndex) {
2232
+ this.attribvalue += this.getSlice(start, endIndex);
2233
+ }
2234
+ /**
2235
+ * @param cp Current Unicode code point.
2236
+ * @internal
2237
+ */
2238
+ onattribentity(cp) {
2239
+ this.attribvalue += fromCodePoint(cp);
2240
+ }
2241
+ /**
2242
+ * @param quote Quote type used for the current attribute.
2243
+ * @param endIndex End index for the current parser event.
2244
+ * @internal
2245
+ */
2246
+ onattribend(quote, endIndex) {
2247
+ this.endIndex = endIndex;
2248
+ this.cbs.onattribute?.(this.attribname, this.attribvalue, quote === QuoteType.Double
2249
+ ? '"'
2250
+ : quote === QuoteType.Single
2251
+ ? "'"
2252
+ : quote === QuoteType.NoValue
2253
+ ? undefined
2254
+ : null);
2255
+ if (this.attribs && !Object.hasOwn(this.attribs, this.attribname)) {
2256
+ this.attribs[this.attribname] = this.attribvalue;
2257
+ }
2258
+ this.attribvalue = "";
2259
+ }
2260
+ getInstructionName(value) {
2261
+ const index = value.search(reNameEnd);
2262
+ let name = index < 0 ? value : value.substr(0, index);
2263
+ if (this.lowerCaseTagNames) {
2264
+ name = name.toLowerCase();
2265
+ }
2266
+ return name;
2267
+ }
2268
+ /**
2269
+ * @param start Start index for the current parser event.
2270
+ * @param endIndex End index for the current parser event.
2271
+ * @internal
2272
+ */
2273
+ ondeclaration(start, endIndex) {
2274
+ this.endIndex = endIndex;
2275
+ const value = this.getSlice(start, endIndex);
2276
+ if (this.cbs.onprocessinginstruction) {
2277
+ /*
2278
+ * In HTML mode, ondeclaration is only reached for DOCTYPE
2279
+ * (the tokenizer routes everything else to bogus comments).
2280
+ */
2281
+ const name = this.htmlMode
2282
+ ? this.lowerCaseTagNames
2283
+ ? DOCUMENT_TYPE
2284
+ : value.slice(0, DOCUMENT_TYPE.length)
2285
+ : this.getInstructionName(value);
2286
+ this.cbs.onprocessinginstruction(`!${name}`, `!${value}`);
2287
+ }
2288
+ // Set `startIndex` for next node
2289
+ this.startIndex = endIndex + 1;
2290
+ }
2291
+ /**
2292
+ * @param start Start index for the current parser event.
2293
+ * @param endIndex End index for the current parser event.
2294
+ * @internal
2295
+ */
2296
+ onprocessinginstruction(start, endIndex) {
2297
+ this.endIndex = endIndex;
2298
+ const value = this.getSlice(start, endIndex);
2299
+ if (this.cbs.onprocessinginstruction) {
2300
+ const name = this.getInstructionName(value);
2301
+ this.cbs.onprocessinginstruction(`?${name}`, `?${value}`);
2302
+ }
2303
+ // Set `startIndex` for next node
2304
+ this.startIndex = endIndex + 1;
2305
+ }
2306
+ /**
2307
+ * @param start Start index for the current parser event.
2308
+ * @param endIndex End index for the current parser event.
2309
+ * @param offset Offset applied when computing parser indices.
2310
+ * @internal
2311
+ */
2312
+ oncomment(start, endIndex, offset) {
2313
+ this.endIndex = endIndex;
2314
+ this.cbs.oncomment?.(this.getSlice(start, endIndex - offset));
2315
+ this.cbs.oncommentend?.();
2316
+ // Set `startIndex` for next node
2317
+ this.startIndex = endIndex + 1;
2318
+ }
2319
+ /**
2320
+ * @param start Start index for the current parser event.
2321
+ * @param endIndex End index for the current parser event.
2322
+ * @param offset Offset applied when computing parser indices.
2323
+ * @internal
2324
+ */
2325
+ oncdata(start, endIndex, offset) {
2326
+ this.endIndex = endIndex;
2327
+ const value = this.getSlice(start, endIndex - offset);
2328
+ if (!this.htmlMode || this.options.recognizeCDATA) {
2329
+ this.cbs.oncdatastart?.();
2330
+ this.cbs.ontext?.(value);
2331
+ this.cbs.oncdataend?.();
2332
+ }
2333
+ else if (this.isInForeignContext()) {
2334
+ this.cbs.ontext?.(value);
2335
+ }
2336
+ else {
2337
+ this.cbs.oncomment?.(`[CDATA[${value}]]`);
2338
+ this.cbs.oncommentend?.();
2339
+ }
2340
+ // Set `startIndex` for next node
2341
+ this.startIndex = endIndex + 1;
2342
+ }
2343
+ /** @internal */
2344
+ onend() {
2345
+ if (this.cbs.onclosetag) {
2346
+ // Set the end index for all remaining tags
2347
+ this.endIndex = this.startIndex;
2348
+ for (let index = 0; index < this.stack.length; index++) {
2349
+ this.cbs.onclosetag(this.stack[index], true);
2350
+ }
2351
+ }
2352
+ this.cbs.onend?.();
2353
+ }
2354
+ /**
2355
+ * Resets the parser to a blank state, ready to parse a new HTML document
2356
+ */
2357
+ reset() {
2358
+ this.cbs.onreset?.();
2359
+ this.tokenizer.reset();
2360
+ this.tagname = "";
2361
+ this.attribname = "";
2362
+ this.attribvalue = "";
2363
+ this.attribs = null;
2364
+ this.stack.length = 0;
2365
+ this.startIndex = 0;
2366
+ this.endIndex = 0;
2367
+ this.cbs.onparserinit?.(this);
2368
+ this.buffers.length = 0;
2369
+ this.foreignContext.length = 0;
2370
+ this.foreignContext.unshift(ForeignContext.None);
2371
+ this.bufferOffset = 0;
2372
+ this.writeIndex = 0;
2373
+ this.ended = false;
2374
+ }
2375
+ /**
2376
+ * Resets the parser, then parses a complete document and
2377
+ * pushes it to the handler.
2378
+ * @param data Document to parse.
2379
+ */
2380
+ parseComplete(data) {
2381
+ this.reset();
2382
+ this.end(data);
2383
+ }
2384
+ getSlice(start, end) {
2385
+ if (start === end) {
2386
+ return "";
2387
+ }
2388
+ while (start - this.bufferOffset >= this.buffers[0].length) {
2389
+ this.shiftBuffer();
2390
+ }
2391
+ let slice = this.buffers[0].slice(start - this.bufferOffset, end - this.bufferOffset);
2392
+ while (end - this.bufferOffset > this.buffers[0].length) {
2393
+ this.shiftBuffer();
2394
+ slice += this.buffers[0].slice(0, end - this.bufferOffset);
2395
+ }
2396
+ return slice;
2397
+ }
2398
+ shiftBuffer() {
2399
+ this.bufferOffset += this.buffers[0].length;
2400
+ this.writeIndex--;
2401
+ this.buffers.shift();
2402
+ }
2403
+ /**
2404
+ * Parses a chunk of data and calls the corresponding callbacks.
2405
+ * @param chunk Chunk to parse.
2406
+ */
2407
+ write(chunk) {
2408
+ if (this.ended) {
2409
+ this.cbs.onerror?.(new Error(".write() after done!"));
2410
+ return;
2411
+ }
2412
+ this.buffers.push(chunk);
2413
+ if (this.tokenizer.running) {
2414
+ this.tokenizer.write(chunk);
2415
+ this.writeIndex++;
2416
+ }
2417
+ }
2418
+ /**
2419
+ * Parses the end of the buffer and clears the stack, calls onend.
2420
+ * @param chunk Optional final chunk to parse.
2421
+ */
2422
+ end(chunk) {
2423
+ if (this.ended) {
2424
+ this.cbs.onerror?.(new Error(".end() after done!"));
2425
+ return;
2426
+ }
2427
+ if (chunk)
2428
+ this.write(chunk);
2429
+ this.ended = true;
2430
+ this.tokenizer.end();
2431
+ }
2432
+ /**
2433
+ * Pauses parsing. The parser won't emit events until `resume` is called.
2434
+ */
2435
+ pause() {
2436
+ this.tokenizer.pause();
2437
+ }
2438
+ /**
2439
+ * Resumes parsing after `pause` was called.
2440
+ */
2441
+ resume() {
2442
+ this.tokenizer.resume();
2443
+ while (this.tokenizer.running &&
2444
+ this.writeIndex < this.buffers.length) {
2445
+ this.tokenizer.write(this.buffers[this.writeIndex++]);
2446
+ }
2447
+ if (this.ended)
2448
+ this.tokenizer.end();
2449
+ }
2450
+ }
2451
+ //# sourceMappingURL=Parser.js.map
2452
+ ;// ./node_modules/domhandler/dist/node.js
2453
+
2454
+ /**
2455
+ * This object will be used as the prototype for Nodes when creating a
2456
+ * DOM-Level-1-compliant structure.
2457
+ */
2458
+ class Node {
2459
+ /** Parent of the node */
2460
+ parent = null;
2461
+ /** Previous sibling */
2462
+ prev = null;
2463
+ /** Next sibling */
2464
+ next = null;
2465
+ /** The start index of the node. Requires `withStartIndices` on the handler to be `true. */
2466
+ startIndex = null;
2467
+ /** The end index of the node. Requires `withEndIndices` on the handler to be `true. */
2468
+ endIndex = null;
2469
+ // Read-write aliases for properties
2470
+ /**
2471
+ * Same as {@link parent}.
2472
+ * [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
2473
+ */
2474
+ get parentNode() {
2475
+ return this.parent;
2476
+ }
2477
+ set parentNode(parent) {
2478
+ this.parent = parent;
2479
+ }
2480
+ /**
2481
+ * Same as {@link prev}.
2482
+ * [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
2483
+ */
2484
+ get previousSibling() {
2485
+ return this.prev;
2486
+ }
2487
+ set previousSibling(previous) {
2488
+ this.prev = previous;
2489
+ }
2490
+ /**
2491
+ * Same as {@link next}.
2492
+ * [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
2493
+ */
2494
+ get nextSibling() {
2495
+ return this.next;
2496
+ }
2497
+ set nextSibling(next) {
2498
+ this.next = next;
2499
+ }
2500
+ /**
2501
+ * Clone this node, and optionally its children.
2502
+ * @param recursive Clone child nodes as well.
2503
+ * @returns A clone of the node.
2504
+ */
2505
+ cloneNode(recursive = false) {
2506
+ return cloneNode(this, recursive);
2507
+ }
2508
+ }
2509
+ /**
2510
+ * A node that contains some data.
2511
+ */
2512
+ class DataNode extends Node {
2513
+ data;
2514
+ /**
2515
+ * @param data The content of the data node
2516
+ */
2517
+ constructor(data) {
2518
+ super();
2519
+ this.data = data;
2520
+ }
2521
+ /**
2522
+ * Same as {@link data}.
2523
+ * [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
2524
+ */
2525
+ get nodeValue() {
2526
+ return this.data;
2527
+ }
2528
+ set nodeValue(data) {
2529
+ this.data = data;
2530
+ }
2531
+ }
2532
+ /**
2533
+ * Text within the document.
2534
+ */
2535
+ class node_Text extends DataNode {
2536
+ type = ElementType.Text;
2537
+ get nodeType() {
2538
+ return 3;
2539
+ }
2540
+ }
2541
+ /**
2542
+ * Comments within the document.
2543
+ */
2544
+ class node_Comment extends DataNode {
2545
+ type = ElementType.Comment;
2546
+ get nodeType() {
2547
+ return 8;
2548
+ }
2549
+ }
2550
+ /**
2551
+ * Processing instructions, including doc types.
2552
+ */
2553
+ class ProcessingInstruction extends DataNode {
2554
+ type = ElementType.Directive;
2555
+ name;
2556
+ constructor(name, data) {
2557
+ super(data);
2558
+ this.name = name;
2559
+ }
2560
+ get nodeType() {
2561
+ return 1;
2562
+ }
2563
+ /** If this is a doctype, the document type name (parse5 only). */
2564
+ "x-name";
2565
+ /** If this is a doctype, the document type public identifier (parse5 only). */
2566
+ "x-publicId";
2567
+ /** If this is a doctype, the document type system identifier (parse5 only). */
2568
+ "x-systemId";
2569
+ }
2570
+ /**
2571
+ * A node that can have children.
2572
+ */
2573
+ class NodeWithChildren extends Node {
2574
+ children;
2575
+ /**
2576
+ * @param children Children of the node. Only certain node types can have children.
2577
+ */
2578
+ constructor(children) {
2579
+ super();
2580
+ this.children = children;
2581
+ }
2582
+ // Aliases
2583
+ /** First child of the node. */
2584
+ get firstChild() {
2585
+ return this.children[0] ?? null;
2586
+ }
2587
+ /** Last child of the node. */
2588
+ get lastChild() {
2589
+ return this.children.length > 0
2590
+ ? this.children[this.children.length - 1]
2591
+ : null;
2592
+ }
2593
+ /**
2594
+ * Same as {@link children}.
2595
+ * [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
2596
+ */
2597
+ get childNodes() {
2598
+ return this.children;
2599
+ }
2600
+ set childNodes(children) {
2601
+ this.children = children;
2602
+ }
2603
+ }
2604
+ /**
2605
+ * CDATA nodes.
2606
+ */
2607
+ class node_CDATA extends NodeWithChildren {
2608
+ type = ElementType.CDATA;
2609
+ get nodeType() {
2610
+ return 4;
2611
+ }
2612
+ }
2613
+ /**
2614
+ * The root node of the document.
2615
+ */
2616
+ class Document extends NodeWithChildren {
2617
+ type = ElementType.Root;
2618
+ get nodeType() {
2619
+ return 9;
2620
+ }
2621
+ }
2622
+ /**
2623
+ * An element within the DOM.
2624
+ */
2625
+ class Element extends NodeWithChildren {
2626
+ name;
2627
+ attribs;
2628
+ type;
2629
+ /**
2630
+ * @param name Name of the tag, eg. `div`, `span`.
2631
+ * @param attribs Object mapping attribute names to attribute values.
2632
+ * @param children Children of the node.
2633
+ * @param type Node type used for the new node instance.
2634
+ */
2635
+ constructor(name, attribs, children = [], type = name === "script"
2636
+ ? ElementType.Script
2637
+ : name === "style"
2638
+ ? ElementType.Style
2639
+ : ElementType.Tag) {
2640
+ super(children);
2641
+ this.name = name;
2642
+ this.attribs = attribs;
2643
+ this.type = type;
2644
+ }
2645
+ get nodeType() {
2646
+ return 1;
2647
+ }
2648
+ // DOM Level 1 aliases
2649
+ /**
2650
+ * Same as {@link name}.
2651
+ * [DOM spec](https://dom.spec.whatwg.org)-compatible alias.
2652
+ */
2653
+ get tagName() {
2654
+ return this.name;
2655
+ }
2656
+ set tagName(name) {
2657
+ this.name = name;
2658
+ }
2659
+ get attributes() {
2660
+ return Object.keys(this.attribs).map((name) => ({
2661
+ name,
2662
+ value: this.attribs[name],
2663
+ namespace: this["x-attribsNamespace"]?.[name],
2664
+ prefix: this["x-attribsPrefix"]?.[name],
2665
+ }));
2666
+ }
2667
+ /** Element namespace (parse5 only). */
2668
+ namespace;
2669
+ /** Element attribute namespaces (parse5 only). */
2670
+ "x-attribsNamespace";
2671
+ /** Element attribute namespace-related prefixes (parse5 only). */
2672
+ "x-attribsPrefix";
2673
+ }
2674
+ /**
2675
+ * Checks if `node` is an element node.
2676
+ * @param node Node to check.
2677
+ * @returns `true` if the node is an element node.
2678
+ */
2679
+ function node_isTag(node) {
2680
+ return isTag(node);
2681
+ }
2682
+ /**
2683
+ * Checks if `node` is a CDATA node.
2684
+ * @param node Node to check.
2685
+ * @returns `true` if the node is a CDATA node.
2686
+ */
2687
+ function isCDATA(node) {
2688
+ return node.type === ElementType.CDATA;
2689
+ }
2690
+ /**
2691
+ * Checks if `node` is a text node.
2692
+ * @param node Node to check.
2693
+ * @returns `true` if the node is a text node.
2694
+ */
2695
+ function isText(node) {
2696
+ return node.type === ElementType.Text;
2697
+ }
2698
+ /**
2699
+ * Checks if `node` is a comment node.
2700
+ * @param node Node to check.
2701
+ * @returns `true` if the node is a comment node.
2702
+ */
2703
+ function isComment(node) {
2704
+ return node.type === ElementType.Comment;
2705
+ }
2706
+ /**
2707
+ * Checks if `node` is a directive node.
2708
+ * @param node Node to check.
2709
+ * @returns `true` if the node is a directive node.
2710
+ */
2711
+ function isDirective(node) {
2712
+ return node.type === ElementType.Directive;
2713
+ }
2714
+ /**
2715
+ * Checks if `node` is a document node.
2716
+ * @param node Node to check.
2717
+ * @returns `true` if the node is a document node.
2718
+ */
2719
+ function isDocument(node) {
2720
+ return node.type === ElementType.Root;
2721
+ }
2722
+ /**
2723
+ * Checks if `node` has children.
2724
+ * @param node Node to check.
2725
+ * @returns `true` if the node has children.
2726
+ */
2727
+ function hasChildren(node) {
2728
+ return Object.hasOwn(node, "children");
2729
+ }
2730
+ /**
2731
+ * Clone a node, and optionally its children.
2732
+ * @param node Node to clone.
2733
+ * @param recursive Clone child nodes as well.
2734
+ * @returns A clone of the node.
2735
+ */
2736
+ function cloneNode(node, recursive = false) {
2737
+ let result;
2738
+ if (isText(node)) {
2739
+ result = new node_Text(node.data);
2740
+ }
2741
+ else if (isComment(node)) {
2742
+ result = new node_Comment(node.data);
2743
+ }
2744
+ else if (node_isTag(node)) {
2745
+ const children = recursive ? cloneChildren(node.children) : [];
2746
+ const clone = new Element(node.name, { ...node.attribs }, children);
2747
+ for (const child of children) {
2748
+ child.parent = clone;
2749
+ }
2750
+ if (node.namespace != null) {
2751
+ clone.namespace = node.namespace;
2752
+ }
2753
+ if (node["x-attribsNamespace"]) {
2754
+ clone["x-attribsNamespace"] = { ...node["x-attribsNamespace"] };
2755
+ }
2756
+ if (node["x-attribsPrefix"]) {
2757
+ clone["x-attribsPrefix"] = { ...node["x-attribsPrefix"] };
2758
+ }
2759
+ result = clone;
2760
+ }
2761
+ else if (isCDATA(node)) {
2762
+ const children = recursive ? cloneChildren(node.children) : [];
2763
+ const clone = new node_CDATA(children);
2764
+ for (const child of children) {
2765
+ child.parent = clone;
2766
+ }
2767
+ result = clone;
2768
+ }
2769
+ else if (isDocument(node)) {
2770
+ const children = recursive ? cloneChildren(node.children) : [];
2771
+ const clone = new Document(children);
2772
+ for (const child of children) {
2773
+ child.parent = clone;
2774
+ }
2775
+ if (node["x-mode"]) {
2776
+ clone["x-mode"] = node["x-mode"];
2777
+ }
2778
+ result = clone;
2779
+ }
2780
+ else if (isDirective(node)) {
2781
+ const instruction = new ProcessingInstruction(node.name, node.data);
2782
+ if (node["x-name"] != null) {
2783
+ instruction["x-name"] = node["x-name"];
2784
+ instruction["x-publicId"] = node["x-publicId"];
2785
+ instruction["x-systemId"] = node["x-systemId"];
2786
+ }
2787
+ result = instruction;
2788
+ }
2789
+ else {
2790
+ throw new Error(`Not implemented yet: ${node.type}`);
2791
+ }
2792
+ result.startIndex = node.startIndex;
2793
+ result.endIndex = node.endIndex;
2794
+ if (node.sourceCodeLocation != null) {
2795
+ result.sourceCodeLocation = node.sourceCodeLocation;
2796
+ }
2797
+ return result;
2798
+ }
2799
+ /**
2800
+ * Clone a list of child nodes.
2801
+ * @param childs The child nodes to clone.
2802
+ * @returns A list of cloned child nodes.
2803
+ */
2804
+ function cloneChildren(childs) {
2805
+ const children = childs.map((child) => cloneNode(child, true));
2806
+ for (let index = 1; index < children.length; index++) {
2807
+ children[index].prev = children[index - 1];
2808
+ children[index - 1].next = children[index];
2809
+ }
2810
+ return children;
2811
+ }
2812
+
2813
+ ;// ./node_modules/domhandler/dist/index.js
2814
+
2815
+
2816
+
2817
+ // Default options
2818
+ const defaultOptions = {
2819
+ withStartIndices: false,
2820
+ withEndIndices: false,
2821
+ xmlMode: false,
2822
+ };
2823
+ /**
2824
+ * Event-based handler that builds a DOM tree from parser callbacks.
2825
+ */
2826
+ class dist_DomHandler {
2827
+ /** The elements of the DOM */
2828
+ dom = [];
2829
+ /** The root element for the DOM */
2830
+ root = new Document(this.dom);
2831
+ /** Called once parsing has completed. */
2832
+ callback;
2833
+ /** Settings for the handler. */
2834
+ options;
2835
+ /** Callback whenever a tag is closed. */
2836
+ elementCB;
2837
+ /** Indicated whether parsing has been completed. */
2838
+ done = false;
2839
+ /** Stack of open tags. */
2840
+ tagStack = [this.root];
2841
+ /** A data node that is still being written to. */
2842
+ lastNode = null;
2843
+ /** Reference to the parser instance. Used for location information. */
2844
+ parser = null;
2845
+ /**
2846
+ * @param callback Called once parsing has completed.
2847
+ * @param options Settings for the handler.
2848
+ * @param elementCB Callback whenever a tag is closed.
2849
+ */
2850
+ constructor(callback, options, elementCB) {
2851
+ // Make it possible to skip arguments, for backwards-compatibility
2852
+ if (typeof options === "function") {
2853
+ elementCB = options;
2854
+ options = defaultOptions;
2855
+ }
2856
+ if (typeof callback === "object") {
2857
+ options = callback;
2858
+ callback = undefined;
2859
+ }
2860
+ this.callback = callback ?? null;
2861
+ this.options = options ?? defaultOptions;
2862
+ this.elementCB = elementCB ?? null;
2863
+ }
2864
+ onparserinit(parser) {
2865
+ this.parser = parser;
2866
+ }
2867
+ // Resets the handler back to starting state
2868
+ onreset() {
2869
+ this.dom = [];
2870
+ this.root = new Document(this.dom);
2871
+ this.done = false;
2872
+ this.tagStack = [this.root];
2873
+ this.lastNode = null;
2874
+ this.parser = null;
2875
+ }
2876
+ // Signals the handler that parsing is done
2877
+ onend() {
2878
+ if (this.done)
2879
+ return;
2880
+ this.done = true;
2881
+ this.parser = null;
2882
+ this.handleCallback(null);
2883
+ }
2884
+ onerror(error) {
2885
+ this.handleCallback(error);
2886
+ }
2887
+ onclosetag() {
2888
+ this.lastNode = null;
2889
+ const element = this.tagStack.pop();
2890
+ if (this.options.withEndIndices && this.parser) {
2891
+ element.endIndex = this.parser.endIndex;
2892
+ }
2893
+ if (this.elementCB)
2894
+ this.elementCB(element);
2895
+ }
2896
+ onopentag(name, attribs) {
2897
+ const type = this.options.xmlMode ? ElementType.Tag : undefined;
2898
+ const element = new Element(name, attribs, undefined, type);
2899
+ this.addNode(element);
2900
+ this.tagStack.push(element);
2901
+ }
2902
+ ontext(data) {
2903
+ const { lastNode } = this;
2904
+ if (lastNode && lastNode.type === ElementType.Text) {
2905
+ lastNode.data += data;
2906
+ if (this.options.withEndIndices && this.parser) {
2907
+ lastNode.endIndex = this.parser.endIndex;
2908
+ }
2909
+ }
2910
+ else {
2911
+ const node = new node_Text(data);
2912
+ this.addNode(node);
2913
+ this.lastNode = node;
2914
+ }
2915
+ }
2916
+ oncomment(data) {
2917
+ if (this.lastNode && this.lastNode.type === ElementType.Comment) {
2918
+ this.lastNode.data += data;
2919
+ return;
2920
+ }
2921
+ const node = new node_Comment(data);
2922
+ this.addNode(node);
2923
+ this.lastNode = node;
2924
+ }
2925
+ oncommentend() {
2926
+ this.lastNode = null;
2927
+ }
2928
+ oncdatastart() {
2929
+ const text = new node_Text("");
2930
+ const node = new node_CDATA([text]);
2931
+ this.addNode(node);
2932
+ text.parent = node;
2933
+ this.lastNode = text;
2934
+ }
2935
+ oncdataend() {
2936
+ this.lastNode = null;
2937
+ }
2938
+ onprocessinginstruction(name, data) {
2939
+ const node = new ProcessingInstruction(name, data);
2940
+ this.addNode(node);
2941
+ }
2942
+ handleCallback(error) {
2943
+ if (typeof this.callback === "function") {
2944
+ this.callback(error, this.dom);
2945
+ }
2946
+ else if (error) {
2947
+ throw error;
2948
+ }
2949
+ }
2950
+ addNode(node) {
2951
+ const parent = this.tagStack[this.tagStack.length - 1];
2952
+ const previousSibling = parent.children[parent.children.length - 1];
2953
+ if (this.options.withStartIndices && this.parser) {
2954
+ node.startIndex = this.parser.startIndex;
2955
+ }
2956
+ if (this.options.withEndIndices && this.parser) {
2957
+ node.endIndex = this.parser.endIndex;
2958
+ }
2959
+ parent.children.push(node);
2960
+ if (previousSibling) {
2961
+ node.prev = previousSibling;
2962
+ previousSibling.next = node;
2963
+ }
2964
+ node.parent = parent;
2965
+ this.lastNode = null;
2966
+ }
2967
+ }
2968
+ /* harmony default export */ const dist = ((/* unused pure expression or super */ null && (dist_DomHandler)));
2969
+
2970
+ ;// ./node_modules/htmlparser2/dist/index.js
2971
+
2972
+
2973
+
2974
+
2975
+ // Helper methods
2976
+ /**
2977
+ * Parses the data, returns the resulting document.
2978
+ * @param data The data that should be parsed.
2979
+ * @param options Optional options for the parser and DOM handler.
2980
+ */
2981
+ function parseDocument(data, options) {
2982
+ const handler = new dist_DomHandler(undefined, options);
2983
+ new Parser_Parser(handler, options).end(data);
2984
+ return handler.root;
2985
+ }
2986
+ /**
2987
+ * Creates a parser instance, with an attached DOM handler.
2988
+ * @param callback A callback that will be called once parsing has been completed, with the resulting document.
2989
+ * @param options Optional options for the parser and DOM handler.
2990
+ * @param elementCallback An optional callback that will be called every time a tag has been completed inside of the DOM.
2991
+ */
2992
+ function createDocumentStream(callback, options, elementCallback) {
2993
+ const handler = new DomHandler((error) => callback(error, handler.root), options, elementCallback);
2994
+ return new Parser(handler, options);
2995
+ }
2996
+ /*
2997
+ * All of the following exports exist for backwards-compatibility.
2998
+ * They should probably be removed eventually.
2999
+ */
3000
+
3001
+
3002
+
3003
+
3004
+ const parseFeedDefaultOptions = { xmlMode: true };
3005
+ /**
3006
+ * Parse a feed.
3007
+ * @param feed The feed that should be parsed, as a string.
3008
+ * @param options Optionally, options for parsing. When using this, you should set `xmlMode` to `true`.
3009
+ */
3010
+ function parseFeed(feed, options = parseFeedDefaultOptions) {
3011
+ return getFeed(parseDocument(feed, options).children);
3012
+ }
3013
+
3014
+ //# sourceMappingURL=index.js.map
3015
+ ;// ./lib/render-diff/differ.ts
3016
+
3017
+ // eslint-disable-next-line import/no-extraneous-dependencies -- transitive via htmlparser2
3018
+
3019
+
3020
+ /* ---------- constant sets ---------- */
3021
+ const VOID_TAGS = new Set([
3022
+ 'area',
3023
+ 'base',
3024
+ 'br',
3025
+ 'col',
3026
+ 'embed',
3027
+ 'hr',
3028
+ 'img',
3029
+ 'input',
3030
+ 'link',
3031
+ 'meta',
3032
+ 'param',
3033
+ 'source',
3034
+ 'track',
3035
+ 'wbr',
3036
+ ]);
3037
+ const NOISE_ATTRS = new Set(['data-reactroot', 'data-testid', 'suppresshydrationwarning']);
3038
+ const CONTENT_ATTRS = new Set(['href', 'src', 'id', 'value', 'alt', 'title']);
3039
+ // Inline-level tags whose adjacent whitespace is significant relative to
3040
+ // surrounding siblings — e.g. the space in `a <em>b</em> c` lives at the edges
3041
+ // of the text nodes around <em>, and the space before/after an inline <br> or
3042
+ // <img> is a real rendered space. normalizeBoundaryWhitespace() treats a text
3043
+ // node's edge as a block boundary (and trims it) only when the neighbour is
3044
+ // block-level; inline neighbours (and inline element edges) keep their
3045
+ // whitespace. Includes the inline-level void/replaced elements (br, wbr, img,
3046
+ // input) so whitespace around them is preserved. Bare <span>s are flattened
3047
+ // into their parent before normalization, so their edge whitespace flows up
3048
+ // intact regardless.
3049
+ const INLINE_TAGS = new Set([
3050
+ 'a',
3051
+ 'abbr',
3052
+ 'b',
3053
+ 'bdi',
3054
+ 'bdo',
3055
+ 'br',
3056
+ 'cite',
3057
+ 'code',
3058
+ 'data',
3059
+ 'del',
3060
+ 'dfn',
3061
+ 'em',
3062
+ 'i',
3063
+ 'img',
3064
+ 'input',
3065
+ 'ins',
3066
+ 'kbd',
3067
+ 'mark',
3068
+ 'q',
3069
+ 'rp',
3070
+ 'rt',
3071
+ 'ruby',
3072
+ 's',
3073
+ 'samp',
3074
+ 'small',
3075
+ 'span',
3076
+ 'strong',
3077
+ 'sub',
3078
+ 'sup',
3079
+ 'time',
3080
+ 'u',
3081
+ 'var',
3082
+ 'wbr',
3083
+ ]);
3084
+ /* ---------- canonicalization ---------- */
3085
+ function hashText(value) {
3086
+ return (0,external_node_crypto_namespaceObject.createHash)('sha1').update(`t:${value}`).digest('hex');
3087
+ }
3088
+ function hashElement(tag, attrs, children) {
3089
+ const sortedAttrKeys = Object.keys(attrs).sort();
3090
+ const attrStr = sortedAttrKeys.map(k => `${k}=${attrs[k]}`).join('|');
3091
+ const childStr = children.map(c => c.hash).join(',');
3092
+ return (0,external_node_crypto_namespaceObject.createHash)('sha1').update(`e:${tag}|${attrStr}|${childStr}`).digest('hex');
3093
+ }
3094
+ function walkAndCanonicalize(node, opts, isRoot) {
3095
+ // Text node — collapse internal whitespace runs to a single space but do NOT
3096
+ // trim. Boundary whitespace is significant at inline boundaries: the space in
3097
+ // `hello <strong>world</strong>` lives at the trailing edge of the "hello "
3098
+ // text node, so trimming here would make `hello world` and `helloworld`
3099
+ // canonicalize identically (a false match). Insignificant edge whitespace at
3100
+ // *block* content boundaries is removed later by normalizeBoundaryWhitespace().
3101
+ if (node.type === ElementType.Text) {
3102
+ const collapsed = node.data.replace(/\s+/g, ' ');
3103
+ return { type: 'text', value: collapsed, hash: hashText(collapsed) };
3104
+ }
3105
+ // Comment, directive (includes <!doctype>) — treat as empty text to drop them out of comparison.
3106
+ // Note: in domhandler's AnyNode union, doctypes are represented as ProcessingInstruction
3107
+ // nodes with type === ElementType.Directive (not ElementType.Doctype).
3108
+ if (node.type === ElementType.Comment || node.type === ElementType.Directive) {
3109
+ return { type: 'text', value: '', hash: hashText('') };
3110
+ }
3111
+ // Root node (Document type = 'root') or element. HTML tag names are
3112
+ // case-insensitive, but htmlparser2's xmlMode preserves the source casing, so
3113
+ // lowercase here — exactly as attribute names are lowercased below. Otherwise
3114
+ // an uppercase tag would miss VOID_TAGS / INLINE_TAGS / heading-id
3115
+ // classification and case-only tag differences (`<DIV>` vs `<div>`) would
3116
+ // surface as spurious structural diffs.
3117
+ const tag = isRoot ? '#root' : node.name.toLowerCase();
3118
+ // Attributes: domhandler gives plain Record<string,string> — not a {name,value}[] array
3119
+ const rawAttrs = isRoot ? {} : (node.attribs ?? {});
3120
+ const attrs = {};
3121
+ for (const [rawName, value] of Object.entries(rawAttrs)) {
3122
+ // HTML attribute names are case-insensitive, but htmlparser2's xmlMode
3123
+ // (used by canonicalize) preserves the source casing. Lowercase before every
3124
+ // set-membership / literal check below — and use it as the stored key — so
3125
+ // noise-drop, attrIgnore, class/style/id and aria-hidden normalization apply
3126
+ // regardless of source casing, and case-only differences never surface as
3127
+ // spurious attr diffs (e.g. `DATA-TESTID` must drop like `data-testid`).
3128
+ const name = rawName.toLowerCase();
3129
+ // oxlint-disable-next-line no-continue
3130
+ if (NOISE_ATTRS.has(name))
3131
+ continue;
3132
+ // oxlint-disable-next-line no-continue
3133
+ if (opts.attrIgnore?.has(name))
3134
+ continue;
3135
+ // oxlint-disable-next-line no-continue
3136
+ if (name === 'aria-hidden' && value === 'false')
3137
+ continue;
3138
+ let normalizedValue = value;
3139
+ if (name === 'class') {
3140
+ normalizedValue = normalizedValue
3141
+ .split(/\s+/)
3142
+ .filter(Boolean)
3143
+ .sort()
3144
+ .join(' ');
3145
+ // oxlint-disable-next-line no-continue
3146
+ if (!normalizedValue)
3147
+ continue; // drop empty class
3148
+ }
3149
+ // oxlint-disable-next-line no-continue
3150
+ if (name === 'style' && normalizedValue.trim() === '')
3151
+ continue;
3152
+ // Heading-slug counter normalization
3153
+ if (name === 'id' && /^h[1-6]$/.test(tag) && !opts.preserveHeadingCounters) {
3154
+ normalizedValue = normalizedValue.replace(/^(.+)-\d+$/, '$1');
3155
+ }
3156
+ // Canonicalize whitespace-only non-class/non-style values to '' so that
3157
+ // (a) two semantically-equivalent whitespace values (`" "` vs `" "`) do
3158
+ // not diff as unequal, and (b) they flow into the boolean denormalization
3159
+ // below — matching the existing intent that "empty" attributes are
3160
+ // equivalent to a boolean-true presence. Class is handled separately
3161
+ // above (sort+filter); style short-circuits via the `continue` above.
3162
+ if (name !== 'class' && name !== 'style' && normalizedValue.trim() === '') {
3163
+ normalizedValue = '';
3164
+ }
3165
+ // Boolean attribute denormalization: empty → "true"
3166
+ if (normalizedValue === '')
3167
+ normalizedValue = 'true';
3168
+ attrs[name] = normalizedValue;
3169
+ }
3170
+ // Children
3171
+ const rawChildren = isRoot
3172
+ ? (node.children ?? [])
3173
+ : isTag(node)
3174
+ ? node.children ?? []
3175
+ : [];
3176
+ const children = [];
3177
+ for (const c of rawChildren) {
3178
+ const canon = walkAndCanonicalize(c, opts, false);
3179
+ // oxlint-disable-next-line no-continue
3180
+ if (canon.type === 'text' && canon.value === '')
3181
+ continue;
3182
+ children.push(canon);
3183
+ }
3184
+ // Void elements never have children; force-empty for stability.
3185
+ // For everything else, normalize text-equivalent structure differences, then
3186
+ // drop whitespace that is insignificant at block boundaries (block content
3187
+ // edges + between block siblings) while keeping whitespace that is a real
3188
+ // rendered space at inline boundaries (see normalizeBoundaryWhitespace).
3189
+ const normalized = VOID_TAGS.has(tag) ? [] : normalizeTextEquivalent(children, opts);
3190
+ const finalChildren = normalizeBoundaryWhitespace(normalized, INLINE_TAGS.has(tag));
3191
+ // Bottom-up hash — recomputed after children are in their final form
3192
+ const hash = hashElement(tag, attrs, finalChildren);
3193
+ return { type: 'element', tag, attrs, children: finalChildren, hash };
3194
+ }
3195
+ function canonicalize(html, opts) {
3196
+ // xmlMode: true — avoids <html><head><body> wrapper injection.
3197
+ // React-rendered HTML is well-formed; xmlMode gives us a flat Document > [content] tree.
3198
+ const doc = parseDocument(html, { xmlMode: true });
3199
+ // Wrap doc in a synthetic root element so the walker has a single entry node.
3200
+ // We pass the Document node directly and treat it as root (isRoot=true).
3201
+ return walkAndCanonicalize(doc, opts, true);
3202
+ }
3203
+ /**
3204
+ * Make the children sequence forgiving of two specific text-equivalent
3205
+ * structural differences between MDX and MDXish:
3206
+ *
3207
+ * 1. Plain `<span>` wrappers (no attributes) — bare grouping with no semantic
3208
+ * weight, replaced by their children.
3209
+ * 2. Adjacent text children — merged into one. MDX inserts `<!---->` between
3210
+ * JSX text fragments which canonicalization drops to empty text, leaving
3211
+ * runs of adjacent text nodes that MDXish would render as a single text.
3212
+ *
3213
+ * Adjacent text is concatenated VERBATIM (no inserted separator). Significant
3214
+ * boundary whitespace around MDX's inline markers is preserved on the text
3215
+ * nodes themselves by walkAndCanonicalize, so the merge reproduces the rendered
3216
+ * text exactly: `foo ` + `bar` → "foo bar", `foo` + `bar` → "foobar". Inserting
3217
+ * a space unconditionally (as a previous version did) fabricated "foo bar" from
3218
+ * "foobar", masking real content differences. The re-collapse keeps the merged
3219
+ * value canonical when both sides contributed boundary whitespace.
3220
+ */
3221
+ function normalizeTextEquivalent(children, opts) {
3222
+ // Span-flatten and adjacent-text-merge are engine-bridging transforms: they
3223
+ // absorb MDX-specific serialization artifacts (bare <span> wrappers,
3224
+ // comment-split text nodes). Skip both in 'minimal' preset so same-engine
3225
+ // before/after comparisons surface real structural changes.
3226
+ if (opts.preset === 'minimal')
3227
+ return children;
3228
+ // Pass 1: flatten plain <span> wrappers.
3229
+ const flat = [];
3230
+ for (const c of children) {
3231
+ if (c.type === 'element' && c.tag === 'span' && Object.keys(c.attrs).length === 0) {
3232
+ flat.push(...c.children);
3233
+ }
3234
+ else {
3235
+ flat.push(c);
3236
+ }
3237
+ }
3238
+ // Pass 2: merge adjacent text children by concatenating verbatim. Boundary
3239
+ // whitespace already lives on the fragments (walkAndCanonicalize no longer
3240
+ // trims it), so a dropped `<!---->` between `foo ` and `bar` reconstructs
3241
+ // "foo bar", while between `foo` and `bar` it stays "foobar". The re-collapse
3242
+ // folds any doubled space (e.g. `foo ` + ` bar`) back to a single space.
3243
+ const merged = [];
3244
+ for (const c of flat) {
3245
+ const last = merged[merged.length - 1];
3246
+ if (c.type === 'text' && last && last.type === 'text') {
3247
+ const combined = `${last.value}${c.value}`.replace(/\s+/g, ' ');
3248
+ merged[merged.length - 1] = { type: 'text', value: combined, hash: hashText(combined) };
3249
+ }
3250
+ else {
3251
+ merged.push(c);
3252
+ }
3253
+ }
3254
+ return merged;
3255
+ }
3256
+ /**
3257
+ * A canonical node is "block-level" if it is an element whose tag is not in
3258
+ * INLINE_TAGS. Text nodes and inline elements are inline-level. Unknown tags
3259
+ * are treated as block (the conservative choice — block boundaries strip more
3260
+ * whitespace, matching how custom block components render).
3261
+ */
3262
+ function isBlockLevel(node) {
3263
+ return node.type === 'element' && !INLINE_TAGS.has(node.tag);
3264
+ }
3265
+ /**
3266
+ * Trim whitespace at one content edge (`leading` = start, `trailing` = end) of
3267
+ * a node that sits at a block boundary, reaching *through* inline-element
3268
+ * wrappers to the actual edge text node. CSS collapses whitespace at the
3269
+ * start/end of a block's inline formatting context even when it is nested
3270
+ * inside inline elements — the trailing space in `<p><strong>hi </strong></p>`
3271
+ * does not render — so the trim must descend through `<strong>`/`<em>`/`<a>`/…
3272
+ * to the edge text. Block-level nodes own their own edges (already normalized
3273
+ * when they were canonicalized) and are returned untouched, which is what stops
3274
+ * the descent from crossing into an unrelated block subtree.
3275
+ *
3276
+ * Returns the same node reference when nothing changed (so callers can detect a
3277
+ * no-op), a rebuilt node when an edge was trimmed, or `null` when the node is a
3278
+ * text node the trim empties (signalling the caller to drop it). An inline
3279
+ * element is never returned as `null` — empty inline elements are preserved,
3280
+ * matching how empty elements are kept elsewhere.
3281
+ */
3282
+ function trimInlineEdge(node, side) {
3283
+ if (node.type === 'text') {
3284
+ const value = side === 'leading' ? node.value.replace(/^\s+/, '') : node.value.replace(/\s+$/, '');
3285
+ if (value === node.value)
3286
+ return node; // unchanged
3287
+ if (value === '')
3288
+ return null; // emptied → drop
3289
+ return { type: 'text', value, hash: hashText(value) };
3290
+ }
3291
+ // Only reach through inline elements; block elements own their edges.
3292
+ if (!INLINE_TAGS.has(node.tag) || node.children.length === 0)
3293
+ return node;
3294
+ const idx = side === 'leading' ? 0 : node.children.length - 1;
3295
+ const edge = node.children[idx];
3296
+ const trimmed = trimInlineEdge(edge, side);
3297
+ if (trimmed === edge)
3298
+ return node; // nothing changed deeper down
3299
+ const newChildren = trimmed === null
3300
+ ? node.children.filter((_, i) => i !== idx)
3301
+ : node.children.map((c, i) => (i === idx ? trimmed : c));
3302
+ return {
3303
+ type: 'element',
3304
+ tag: node.tag,
3305
+ attrs: node.attrs,
3306
+ children: newChildren,
3307
+ hash: hashElement(node.tag, node.attrs, newChildren),
3308
+ };
3309
+ }
3310
+ /**
3311
+ * Drop whitespace that does not survive rendering, while preserving whitespace
3312
+ * that does. Mirrors the CSS whitespace model at the granularity this differ
3313
+ * needs:
3314
+ *
3315
+ * - Whitespace at a *block boundary* — the content edge of a block element,
3316
+ * or the side of a node that abuts a block-level sibling — collapses away in
3317
+ * rendered output, so it is trimmed. The trim reaches through inline
3318
+ * wrappers at the edge (see trimInlineEdge), and a whitespace-only text node
3319
+ * between two blocks is emptied and dropped entirely.
3320
+ * - Whitespace at an *inline boundary* — between text and an inline element,
3321
+ * or between two inline siblings — is a real rendered space (the space in
3322
+ * "hello world") and is kept. Trimming it is what previously made
3323
+ * `hello world` and `helloworld` canonicalize identically.
3324
+ *
3325
+ * `selfInline` is the block/inline-ness of the element these children belong
3326
+ * to: it decides the *outer* edges. A block element trims its first child's
3327
+ * leading and last child's trailing whitespace; an inline element does not
3328
+ * (its edge whitespace is significant relative to its own siblings one level
3329
+ * up, and is handled when that ancestor block is normalized). Interior edges
3330
+ * are decided by each node's immediate siblings.
3331
+ */
3332
+ function normalizeBoundaryWhitespace(children, selfInline) {
3333
+ if (children.length === 0)
3334
+ return children;
3335
+ const out = [];
3336
+ for (let k = 0; k < children.length; k += 1) {
3337
+ const leftIsBlockBoundary = k === 0 ? !selfInline : isBlockLevel(children[k - 1]);
3338
+ const rightIsBlockBoundary = k === children.length - 1 ? !selfInline : isBlockLevel(children[k + 1]);
3339
+ let node = children[k];
3340
+ if (leftIsBlockBoundary)
3341
+ node = trimInlineEdge(node, 'leading');
3342
+ if (node !== null && rightIsBlockBoundary)
3343
+ node = trimInlineEdge(node, 'trailing');
3344
+ // oxlint-disable-next-line no-continue
3345
+ if (node === null)
3346
+ continue; // whitespace fully absorbed at a block boundary
3347
+ out.push(node);
3348
+ }
3349
+ return out;
3350
+ }
3351
+ /* ---------- diff walker ---------- */
3352
+ function diffNodes(a, b, pathStr, changes) {
3353
+ if (a.hash === b.hash)
3354
+ return;
3355
+ if (a.type === 'text' || b.type === 'text') {
3356
+ if (a.type === 'text' && b.type === 'text') {
3357
+ if (a.value !== b.value) {
3358
+ changes.push({
3359
+ path: pathStr,
3360
+ kind: 'text',
3361
+ severity: 'content',
3362
+ left: a.value,
3363
+ right: b.value,
3364
+ });
3365
+ }
3366
+ }
3367
+ else {
3368
+ // One side is text, the other is an element — record as tag mismatch.
3369
+ changes.push({
3370
+ path: pathStr,
3371
+ kind: 'tag',
3372
+ severity: 'structural',
3373
+ left: a.type === 'text' ? `#text(${JSON.stringify(a.value)})` : `<${a.tag}>`,
3374
+ right: b.type === 'text' ? `#text(${JSON.stringify(b.value)})` : `<${b.tag}>`,
3375
+ });
3376
+ }
3377
+ return;
3378
+ }
3379
+ // Both are elements
3380
+ if (a.tag !== b.tag) {
3381
+ changes.push({
3382
+ path: pathStr,
3383
+ kind: 'tag',
3384
+ severity: 'structural',
3385
+ left: a.tag,
3386
+ right: b.tag,
3387
+ });
3388
+ return; // don't descend — children compare unrelated subtrees
3389
+ }
3390
+ // Attribute diff
3391
+ diffAttrs(a.attrs, b.attrs, pathStr, changes);
3392
+ // Children diff via simple greedy alignment with single-step lookahead
3393
+ alignChildren(a.children, b.children, pathStr, changes);
3394
+ }
3395
+ function diffAttrs(aAttrs, bAttrs, pathStr, changes) {
3396
+ const keys = new Set([...Object.keys(aAttrs), ...Object.keys(bAttrs)]);
3397
+ for (const k of [...keys].sort()) {
3398
+ const av = aAttrs[k];
3399
+ const bv = bAttrs[k];
3400
+ // oxlint-disable-next-line no-continue
3401
+ if (av === bv)
3402
+ continue;
3403
+ changes.push({
3404
+ path: pathStr,
3405
+ kind: 'attr',
3406
+ attrName: k,
3407
+ severity: attrSeverity(k),
3408
+ left: av ?? null,
3409
+ right: bv ?? null,
3410
+ });
3411
+ }
3412
+ }
3413
+ function attrSeverity(name) {
3414
+ if (CONTENT_ATTRS.has(name))
3415
+ return 'content';
3416
+ if (name === 'class' || name === 'style')
3417
+ return 'structural';
3418
+ if (name.startsWith('data-') || name.startsWith('aria-'))
3419
+ return 'cosmetic';
3420
+ return 'structural';
3421
+ }
3422
+ /**
3423
+ * Align two child arrays using a single-step lookahead — at each unmatched
3424
+ * position we peek at `aChildren[i+1]` and `bChildren[j+1]` only, which is
3425
+ * enough to recover from one isolated insertion or deletion. Handles single
3426
+ * insertions / deletions / substitutions without cascading. For more complex
3427
+ * rearrangements (e.g. consecutive double-inserts) we degrade gracefully — a
3428
+ * long diff may not be optimal but it'll surface as "this page differs a lot"
3429
+ * which is the right signal.
3430
+ *
3431
+ * Children are visited in document position order.
3432
+ */
3433
+ function alignChildren(aChildren, bChildren, parentPath, changes) {
3434
+ let i = 0;
3435
+ let j = 0;
3436
+ while (i < aChildren.length && j < bChildren.length) {
3437
+ const a = aChildren[i];
3438
+ const b = bChildren[j];
3439
+ if (a.hash === b.hash) {
3440
+ i += 1;
3441
+ j += 1;
3442
+ // oxlint-disable-next-line no-continue
3443
+ continue;
3444
+ }
3445
+ // Lookahead: is a[i] missing in b (b[j] matches a[i+1])?
3446
+ if (i + 1 < aChildren.length && aChildren[i + 1].hash === b.hash) {
3447
+ changes.push(missingOrExtra('missing', a, `${parentPath}/${describeNode(a, i)}`));
3448
+ i += 1;
3449
+ // oxlint-disable-next-line no-continue
3450
+ continue;
3451
+ }
3452
+ // Lookahead: is b[j] extra (a[i] matches b[j+1])?
3453
+ if (j + 1 < bChildren.length && a.hash === bChildren[j + 1].hash) {
3454
+ changes.push(missingOrExtra('extra', b, `${parentPath}/${describeNode(b, j)}`));
3455
+ j += 1;
3456
+ // oxlint-disable-next-line no-continue
3457
+ continue;
3458
+ }
3459
+ // Otherwise substitute and recurse
3460
+ diffNodes(a, b, `${parentPath}/${describeNode(a, i)}`, changes);
3461
+ i += 1;
3462
+ j += 1;
3463
+ }
3464
+ // Trailing missings / extras
3465
+ while (i < aChildren.length) {
3466
+ const a = aChildren[i];
3467
+ changes.push(missingOrExtra('missing', a, `${parentPath}/${describeNode(a, i)}`));
3468
+ i += 1;
3469
+ }
3470
+ while (j < bChildren.length) {
3471
+ const b = bChildren[j];
3472
+ changes.push(missingOrExtra('extra', b, `${parentPath}/${describeNode(b, j)}`));
3473
+ j += 1;
3474
+ }
3475
+ }
3476
+ function missingOrExtra(kind, node, pathStr) {
3477
+ // 'missing' = present in left, absent in right; 'extra' = present in right, absent in left.
3478
+ const isText = node.type === 'text';
3479
+ const severity = isText ? 'content' : 'structural';
3480
+ const repr = node.type === 'text' ? `#text(${JSON.stringify(node.value)})` : serializeShallow(node);
3481
+ return {
3482
+ path: pathStr,
3483
+ kind,
3484
+ severity,
3485
+ left: kind === 'missing' ? repr : null,
3486
+ right: kind === 'extra' ? repr : null,
3487
+ };
3488
+ }
3489
+ function describeNode(node, index) {
3490
+ if (node.type === 'text')
3491
+ return `#text[${index}]`;
3492
+ return `${node.tag}[${index}]`;
3493
+ }
3494
+ function serializeShallow(node) {
3495
+ // Attribute values may contain `"` (e.g. `title='he said "hi"'`); without
3496
+ // escaping the quote, the rendered diff string becomes malformed and
3497
+ // misleads during debugging. No security impact — this string is for
3498
+ // human-readable diff output only — but tightening keeps the output
3499
+ // unambiguous. Escape `"` to `&quot;` to mirror standard HTML attribute
3500
+ // escaping.
3501
+ const attrs = Object.entries(node.attrs)
3502
+ .map(([k, v]) => `${k}="${v.replace(/"/g, '&quot;')}"`)
3503
+ .join(' ');
3504
+ const head = attrs ? `<${node.tag} ${attrs}>` : `<${node.tag}>`;
3505
+ if (VOID_TAGS.has(node.tag))
3506
+ return head;
3507
+ return node.children.length === 0
3508
+ ? `${head}</${node.tag}>`
3509
+ : `${head}…(${node.children.length} children)…</${node.tag}>`;
3510
+ }
3511
+ const SEVERITY_ORDER = { cosmetic: 0, structural: 1, content: 2 };
3512
+ function pageSeverity(changes) {
3513
+ let max = 'cosmetic';
3514
+ for (const c of changes) {
3515
+ if (SEVERITY_ORDER[c.severity] > SEVERITY_ORDER[max])
3516
+ max = c.severity;
3517
+ }
3518
+ return max;
3519
+ }
3520
+ /* ---------- public API ---------- */
3521
+ /**
3522
+ * Diff two rendered HTML strings.
3523
+ *
3524
+ * The diff tool is engine-agnostic — `leftHtml` and `rightHtml` are simply
3525
+ * the two HTML strings to compare in that order. Common use cases:
3526
+ * - MDX vs MDXish (Suite B in this repo)
3527
+ * - Before vs after a `@readme/markdown` version bump on the same source
3528
+ * - Any two HTML strings a consumer wants to compare
3529
+ *
3530
+ * Both strings are canonicalized (whitespace collapse, class sort, attribute
3531
+ * normalization, noise-attr drop, heading-counter strip, void-tag handling,
3532
+ * text-equivalent merging) before comparison.
3533
+ *
3534
+ * A bottom-up content hash provides a fast-path: if both trees hash identically,
3535
+ * `{ status: 'match' }` is returned without a full walk.
3536
+ *
3537
+ * The returned `changes[]` is ordered by document position and is identical
3538
+ * across repeated calls on the same input. Each change carries `left` and
3539
+ * `right` fields corresponding to the two inputs.
3540
+ *
3541
+ * @param leftHtml - First HTML string to compare.
3542
+ * @param rightHtml - Second HTML string to compare.
3543
+ * @param opts - Optional canonicalization / diff configuration.
3544
+ * @returns `{ status: 'match' }` or `{ status: 'differ', severity, changes }`.
3545
+ */
3546
+ function diff(leftHtml, rightHtml, opts = {}) {
3547
+ const a = canonicalize(leftHtml, opts);
3548
+ const b = canonicalize(rightHtml, opts);
3549
+ if (!opts.noHashFastPath && a.hash === b.hash) {
3550
+ return { status: 'match' }; // no severity/changes on match
3551
+ }
3552
+ const changes = [];
3553
+ diffNodes(a, b, '', changes);
3554
+ if (changes.length === 0) {
3555
+ // Hashes differ but the walker found no structural differences — hash-only
3556
+ // variation (unlikely in practice). Treat as match.
3557
+ return { status: 'match' };
3558
+ }
3559
+ return { status: 'differ', severity: pageSeverity(changes), changes };
3560
+ }
3561
+
3562
+ ;// ./lib/render-diff/index.ts
3563
+
3564
+
3565
+ module.exports = __webpack_exports__;
3566
+ /******/ })()
3567
+ ;
3568
+ //# sourceMappingURL=render-diff.node.js.map