@rgrove/parse-xml 4.1.0 → 4.2.0

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.
package/dist/browser.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @rgrove/parse-xml v4.1.0 | ISC License | Copyright Ryan Grove */
1
+ /*! @rgrove/parse-xml v4.2.0 | ISC License | Copyright Ryan Grove */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -40,24 +40,24 @@ var emptyString = "";
40
40
  var surrogatePair = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
41
41
  var StringScanner = class {
42
42
  constructor(string) {
43
- this.k = this.q(string, true);
43
+ this.k = this.u(string, true);
44
44
  this.d = 0;
45
45
  this.length = string.length;
46
- this.n = this.k !== this.length;
47
- this.m = string;
48
- if (this.n) {
46
+ this.l = this.k !== this.length;
47
+ this.h = string;
48
+ if (this.l) {
49
49
  let charsToBytes = [];
50
50
  for (let byteIndex = 0, charIndex = 0; charIndex < this.k; ++charIndex) {
51
51
  charsToBytes[charIndex] = byteIndex;
52
52
  byteIndex += string.codePointAt(byteIndex) > 65535 ? 2 : 1;
53
53
  }
54
- this.y = charsToBytes;
54
+ this.A = charsToBytes;
55
55
  }
56
56
  }
57
57
  /**
58
58
  * Whether the current character index is at the end of the input string.
59
59
  */
60
- get z() {
60
+ get B() {
61
61
  return this.d >= this.k;
62
62
  }
63
63
  // -- Protected Methods ------------------------------------------------------
@@ -65,7 +65,7 @@ var StringScanner = class {
65
65
  * Returns the number of characters in the given string, which may differ from
66
66
  * the byte length if the string contains multibyte characters.
67
67
  */
68
- q(string, multiByteSafe = this.n) {
68
+ u(string, multiByteSafe = this.l) {
69
69
  return multiByteSafe ? string.replace(surrogatePair, "_").length : string.length;
70
70
  }
71
71
  // -- Public Methods ---------------------------------------------------------
@@ -73,16 +73,16 @@ var StringScanner = class {
73
73
  * Advances the scanner by the given number of characters, stopping if the end
74
74
  * of the string is reached.
75
75
  */
76
- g(count = 1) {
76
+ p(count = 1) {
77
77
  this.d = Math.min(this.k, this.d + count);
78
78
  }
79
79
  /**
80
80
  * Returns the byte index of the given character index in the string. The two
81
81
  * may differ in strings that contain multibyte characters.
82
82
  */
83
- i(charIndex = this.d) {
83
+ f(charIndex = this.d) {
84
84
  var _a;
85
- return this.n ? (_a = this.y[charIndex]) != null ? _a : Infinity : charIndex;
85
+ return this.l ? (_a = this.A[charIndex]) != null ? _a : Infinity : charIndex;
86
86
  }
87
87
  /**
88
88
  * Consumes and returns the given number of characters if possible, advancing
@@ -90,46 +90,53 @@ var StringScanner = class {
90
90
  *
91
91
  * If no characters could be consumed, an empty string will be returned.
92
92
  */
93
- F(count = 1) {
94
- let chars = this.h(count);
95
- this.g(count);
93
+ G(charCount = 1) {
94
+ let chars = this.m(charCount);
95
+ this.p(charCount);
96
96
  return chars;
97
97
  }
98
98
  /**
99
- * Consumes a match for the given sticky regex, advances the scanner, updates
100
- * the `lastIndex` property of the regex, and returns the matching string.
99
+ * Consumes and returns the given number of bytes if possible, advancing the
100
+ * scanner and stopping if the end of the string is reached.
101
101
  *
102
- * The regex must have a sticky flag ("y") so that its `lastIndex` prop can be
103
- * used to anchor the match at the current scanner position.
102
+ * It's up to the caller to ensure that the given byte count doesn't split a
103
+ * multibyte character.
104
104
  *
105
- * Returns the consumed string, or an empty string if nothing was consumed.
105
+ * If no bytes could be consumed, an empty string will be returned.
106
106
  */
107
- G(regex) {
108
- if (!regex.sticky) {
109
- throw new Error('`regex` must have a sticky flag ("y")');
110
- }
111
- regex.lastIndex = this.i();
112
- let result = regex.exec(this.m);
113
- if (result === null || result.length === 0) {
114
- return emptyString;
115
- }
116
- let match = result[0];
117
- this.g(this.q(match));
118
- return match;
107
+ v(byteCount) {
108
+ let byteIndex = this.f();
109
+ let result = this.h.slice(byteIndex, byteIndex + byteCount);
110
+ this.p(this.u(result));
111
+ return result;
119
112
  }
120
113
  /**
121
- * Consumes and returns all characters for which the given function returns a
122
- * truthy value, stopping on the first falsy return value or if the end of the
123
- * input is reached.
114
+ * Consumes and returns all characters for which the given function returns
115
+ * `true`, stopping when `false` is returned or the end of the input is
116
+ * reached.
124
117
  */
125
- v(fn) {
126
- let char;
127
- let match = emptyString;
128
- while ((char = this.h()) && fn(char)) {
129
- match += char;
130
- this.g();
118
+ w(fn) {
119
+ let { length, l: multiByteMode, h: string } = this;
120
+ let startByteIndex = this.f();
121
+ let endByteIndex = startByteIndex;
122
+ if (multiByteMode) {
123
+ while (endByteIndex < length) {
124
+ let char = string[endByteIndex];
125
+ let isSurrogatePair = char >= "\uD800" && char <= "\uDBFF";
126
+ if (isSurrogatePair) {
127
+ char += string[endByteIndex + 1];
128
+ }
129
+ if (!fn(char)) {
130
+ break;
131
+ }
132
+ endByteIndex += isSurrogatePair ? 2 : 1;
133
+ }
134
+ } else {
135
+ while (endByteIndex < length && fn(string[endByteIndex])) {
136
+ ++endByteIndex;
137
+ }
131
138
  }
132
- return match;
139
+ return this.v(endByteIndex - startByteIndex);
133
140
  }
134
141
  /**
135
142
  * Consumes the given string if it exists at the current character index, and
@@ -138,29 +145,11 @@ var StringScanner = class {
138
145
  * If the given string doesn't exist at the current character index, an empty
139
146
  * string will be returned and the scanner will not be advanced.
140
147
  */
141
- Q(stringToConsume) {
142
- if (this.b(stringToConsume)) {
143
- return stringToConsume;
144
- }
145
- if (this.n) {
146
- let { length } = stringToConsume;
147
- let charLengthToMatch = this.q(stringToConsume);
148
- if (charLengthToMatch !== length && stringToConsume === this.h(charLengthToMatch)) {
149
- this.g(charLengthToMatch);
150
- return stringToConsume;
151
- }
152
- }
153
- return emptyString;
154
- }
155
- /**
156
- * Does the same thing as `consumeString()`, but doesn't support consuming
157
- * multibyte characters. This can be faster if you only need to match single
158
- * byte characters.
159
- */
160
148
  b(stringToConsume) {
161
149
  let { length } = stringToConsume;
162
- if (this.h(length) === stringToConsume) {
163
- this.g(length);
150
+ let byteIndex = this.f();
151
+ if (stringToConsume === this.h.slice(byteIndex, byteIndex + length)) {
152
+ this.p(length === 1 ? 1 : this.u(stringToConsume));
164
153
  return stringToConsume;
165
154
  }
166
155
  return emptyString;
@@ -172,15 +161,9 @@ var StringScanner = class {
172
161
  *
173
162
  * Returns the consumed string, or an empty string if nothing was consumed.
174
163
  */
175
- A(regex) {
176
- let restOfString = this.m.slice(this.i());
177
- let matchByteIndex = restOfString.search(regex);
178
- if (matchByteIndex <= 0) {
179
- return emptyString;
180
- }
181
- let result = restOfString.slice(0, matchByteIndex);
182
- this.g(this.q(result));
183
- return result;
164
+ x(regex) {
165
+ let matchByteIndex = this.h.slice(this.f()).search(regex);
166
+ return matchByteIndex > 0 ? this.v(matchByteIndex) : emptyString;
184
167
  }
185
168
  /**
186
169
  * Consumes characters until the given string is found, advancing the scanner
@@ -189,34 +172,19 @@ var StringScanner = class {
189
172
  *
190
173
  * Returns the consumed string, or an empty string if nothing was consumed.
191
174
  */
192
- t(searchString) {
193
- let { m: string } = this;
194
- let byteIndex = this.i();
195
- let matchByteIndex = string.indexOf(searchString, byteIndex);
196
- if (matchByteIndex <= 0) {
197
- return emptyString;
198
- }
199
- let result = string.slice(byteIndex, matchByteIndex);
200
- this.g(this.q(result));
201
- return result;
175
+ s(searchString) {
176
+ let byteIndex = this.f();
177
+ let matchByteIndex = this.h.indexOf(searchString, byteIndex);
178
+ return matchByteIndex > 0 ? this.v(matchByteIndex - byteIndex) : emptyString;
202
179
  }
203
180
  /**
204
181
  * Returns the given number of characters starting at the current character
205
182
  * index, without advancing the scanner and without exceeding the end of the
206
183
  * input string.
207
184
  */
208
- h(count = 1) {
209
- let { d: charIndex, n: multiByteMode, m: string } = this;
210
- if (multiByteMode) {
211
- if (charIndex >= this.k) {
212
- return emptyString;
213
- }
214
- return string.slice(
215
- this.i(charIndex),
216
- this.i(charIndex + count)
217
- );
218
- }
219
- return string.slice(charIndex, charIndex + count);
185
+ m(count = 1) {
186
+ let { d: charIndex, h: string } = this;
187
+ return this.l ? string.slice(this.f(charIndex), this.f(charIndex + count)) : string.slice(charIndex, charIndex + count);
220
188
  }
221
189
  /**
222
190
  * Resets the scanner position to the given character _index_, or to the start
@@ -225,14 +193,14 @@ var StringScanner = class {
225
193
  * If _index_ is negative, the scanner position will be moved backward by that
226
194
  * many characters, stopping if the beginning of the string is reached.
227
195
  */
228
- o(index = 0) {
196
+ n(index = 0) {
229
197
  this.d = index >= 0 ? Math.min(this.k, index) : Math.max(0, this.d + index);
230
198
  }
231
199
  };
232
200
 
233
201
  // src/lib/syntax.ts
234
- var attValueCharDoubleQuote = /[^"&<]+/y;
235
- var attValueCharSingleQuote = /[^'&<]+/y;
202
+ var attValueCharDoubleQuote = /["&<]/;
203
+ var attValueCharSingleQuote = /['&<]/;
236
204
  var attValueNormalizedWhitespace = /\r\n|[\n\r\t]/g;
237
205
  var endCharData = /<|&|]]>/;
238
206
  var predefinedEntities = Object.freeze(Object.assign(/* @__PURE__ */ Object.create(null), {
@@ -243,28 +211,25 @@ var predefinedEntities = Object.freeze(Object.assign(/* @__PURE__ */ Object.crea
243
211
  quot: '"'
244
212
  }));
245
213
  function isNameChar(char) {
246
- let cp = getCodePoint(char);
247
- return cp >= 97 && cp <= 122 || cp >= 65 && cp <= 90 || cp >= 48 && cp <= 57 || cp === 45 || cp === 46 || cp === 183 || cp >= 768 && cp <= 879 || cp >= 8255 && cp <= 8256 || isNameStartChar(char, cp);
214
+ let cp = char.codePointAt(0);
215
+ return cp >= 97 && cp <= 122 || cp >= 65 && cp <= 90 || cp >= 48 && cp <= 57 || cp === 45 || cp === 46 || cp === 183 || cp >= 768 && cp <= 879 || cp === 8255 || cp === 8256 || isNameStartChar(char, cp);
248
216
  }
249
- function isNameStartChar(char, cp = getCodePoint(char)) {
250
- return cp >= 97 && cp <= 122 || cp >= 65 && cp <= 90 || cp === 58 || cp === 95 || cp >= 192 && cp <= 214 || cp >= 216 && cp <= 246 || cp >= 248 && cp <= 767 || cp >= 880 && cp <= 893 || cp >= 895 && cp <= 8191 || cp >= 8204 && cp <= 8205 || cp >= 8304 && cp <= 8591 || cp >= 11264 && cp <= 12271 || cp >= 12289 && cp <= 55295 || cp >= 63744 && cp <= 64975 || cp >= 65008 && cp <= 65533 || cp >= 65536 && cp <= 983039;
217
+ function isNameStartChar(char, cp = char.codePointAt(0)) {
218
+ return cp >= 97 && cp <= 122 || cp >= 65 && cp <= 90 || cp === 58 || cp === 95 || cp >= 192 && cp <= 214 || cp >= 216 && cp <= 246 || cp >= 248 && cp <= 767 || cp >= 880 && cp <= 893 || cp >= 895 && cp <= 8191 || cp === 8204 || cp === 8205 || cp >= 8304 && cp <= 8591 || cp >= 11264 && cp <= 12271 || cp >= 12289 && cp <= 55295 || cp >= 63744 && cp <= 64975 || cp >= 65008 && cp <= 65533 || cp >= 65536 && cp <= 983039;
251
219
  }
252
220
  function isReferenceChar(char) {
253
221
  return char === "#" || isNameChar(char);
254
222
  }
255
223
  function isWhitespace(char) {
256
- let cp = getCodePoint(char);
224
+ let cp = char.codePointAt(0);
257
225
  return cp === 32 || cp === 9 || cp === 10 || cp === 13;
258
226
  }
259
227
  function isXmlCodePoint(cp) {
260
- return cp === 9 || cp === 10 || cp === 13 || cp >= 32 && cp <= 55295 || cp >= 57344 && cp <= 65533 || cp >= 65536 && cp <= 1114111;
261
- }
262
- function getCodePoint(char) {
263
- return char.codePointAt(0) || -1;
228
+ return cp >= 32 && cp <= 55295 || cp === 10 || cp === 9 || cp === 13 || cp >= 57344 && cp <= 65533 || cp >= 65536 && cp <= 1114111;
264
229
  }
265
230
 
266
231
  // src/lib/XmlNode.ts
267
- var _XmlNode = class {
232
+ var _XmlNode = class _XmlNode {
268
233
  constructor() {
269
234
  /**
270
235
  * Parent node of this node, or `null` if this node has no parent.
@@ -345,39 +310,39 @@ var _XmlNode = class {
345
310
  return json;
346
311
  }
347
312
  };
348
- var XmlNode = _XmlNode;
349
313
  /**
350
314
  * Type value for an `XmlCdata` node.
351
315
  */
352
- XmlNode.TYPE_CDATA = "cdata";
316
+ _XmlNode.TYPE_CDATA = "cdata";
353
317
  /**
354
318
  * Type value for an `XmlComment` node.
355
319
  */
356
- XmlNode.TYPE_COMMENT = "comment";
320
+ _XmlNode.TYPE_COMMENT = "comment";
357
321
  /**
358
322
  * Type value for an `XmlDocument` node.
359
323
  */
360
- XmlNode.TYPE_DOCUMENT = "document";
324
+ _XmlNode.TYPE_DOCUMENT = "document";
361
325
  /**
362
326
  * Type value for an `XmlDocumentType` node.
363
327
  */
364
- XmlNode.TYPE_DOCUMENT_TYPE = "doctype";
328
+ _XmlNode.TYPE_DOCUMENT_TYPE = "doctype";
365
329
  /**
366
330
  * Type value for an `XmlElement` node.
367
331
  */
368
- XmlNode.TYPE_ELEMENT = "element";
332
+ _XmlNode.TYPE_ELEMENT = "element";
369
333
  /**
370
334
  * Type value for an `XmlProcessingInstruction` node.
371
335
  */
372
- XmlNode.TYPE_PROCESSING_INSTRUCTION = "pi";
336
+ _XmlNode.TYPE_PROCESSING_INSTRUCTION = "pi";
373
337
  /**
374
338
  * Type value for an `XmlText` node.
375
339
  */
376
- XmlNode.TYPE_TEXT = "text";
340
+ _XmlNode.TYPE_TEXT = "text";
377
341
  /**
378
342
  * Type value for an `XmlDeclaration` node.
379
343
  */
380
- XmlNode.TYPE_XML_DECLARATION = "xmldecl";
344
+ _XmlNode.TYPE_XML_DECLARATION = "xmldecl";
345
+ var XmlNode = _XmlNode;
381
346
 
382
347
  // src/lib/XmlText.ts
383
348
  var XmlText = class extends XmlNode {
@@ -442,7 +407,7 @@ var XmlDeclaration = class extends XmlNode {
442
407
  };
443
408
 
444
409
  // src/lib/XmlElement.ts
445
- var XmlElement = class extends XmlNode {
410
+ var XmlElement = class _XmlElement extends XmlNode {
446
411
  constructor(name, attributes = /* @__PURE__ */ Object.create(null), children = []) {
447
412
  super();
448
413
  this.name = name;
@@ -457,7 +422,7 @@ var XmlElement = class extends XmlNode {
457
422
  }
458
423
  get preserveWhitespace() {
459
424
  let node = this;
460
- while (node instanceof XmlElement) {
425
+ while (node instanceof _XmlElement) {
461
426
  if ("xml:space" in node.attributes) {
462
427
  return node.attributes["xml:space"] === "preserve";
463
428
  }
@@ -611,42 +576,33 @@ var Parser = class {
611
576
  */
612
577
  constructor(xml, options = {}) {
613
578
  let doc = this.document = new XmlDocument();
614
- let scanner = this.c = new StringScanner(xml);
615
- this.l = doc;
616
- this.f = options;
617
- if (this.f.includeOffsets) {
579
+ this.j = doc;
580
+ this.g = options;
581
+ this.c = new StringScanner(xml);
582
+ if (this.g.includeOffsets) {
618
583
  doc.start = 0;
619
584
  doc.end = xml.length;
620
585
  }
621
- scanner.b("\uFEFF");
622
- this.H();
623
- if (!this.B()) {
624
- throw this.a("Root element is missing or invalid");
625
- }
626
- while (this.w()) {
627
- }
628
- if (!scanner.z) {
629
- throw this.a("Extra content at the end of the document");
630
- }
586
+ this.parse();
631
587
  }
632
588
  /**
633
589
  * Adds the given `XmlNode` as a child of `this.currentNode`.
634
590
  */
635
- j(node, charIndex) {
636
- node.parent = this.l;
637
- if (this.f.includeOffsets) {
638
- node.start = this.c.i(charIndex);
639
- node.end = this.c.i();
591
+ i(node, charIndex) {
592
+ node.parent = this.j;
593
+ if (this.g.includeOffsets) {
594
+ node.start = this.c.f(charIndex);
595
+ node.end = this.c.f();
640
596
  }
641
- this.l.children.push(node);
597
+ this.j.children.push(node);
642
598
  return true;
643
599
  }
644
600
  /**
645
601
  * Adds the given _text_ to the document, either by appending it to a
646
602
  * preceding `XmlText` node (if possible) or by creating a new `XmlText` node.
647
603
  */
648
- x(text, charIndex) {
649
- let { children } = this.l;
604
+ y(text, charIndex) {
605
+ let { children } = this.j;
650
606
  let { length } = children;
651
607
  text = normalizeLineBreaks(text);
652
608
  if (length > 0) {
@@ -654,27 +610,27 @@ var Parser = class {
654
610
  if ((prevNode == null ? void 0 : prevNode.type) === XmlNode.TYPE_TEXT) {
655
611
  let textNode = prevNode;
656
612
  textNode.text += text;
657
- if (this.f.includeOffsets) {
658
- textNode.end = this.c.i();
613
+ if (this.g.includeOffsets) {
614
+ textNode.end = this.c.f();
659
615
  }
660
616
  return true;
661
617
  }
662
618
  }
663
- return this.j(new XmlText(text), charIndex);
619
+ return this.i(new XmlText(text), charIndex);
664
620
  }
665
621
  /**
666
622
  * Consumes element attributes.
667
623
  *
668
624
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-starttags
669
625
  */
670
- I() {
626
+ H() {
671
627
  let attributes = /* @__PURE__ */ Object.create(null);
672
628
  while (this.e()) {
673
- let attrName = this.r();
629
+ let attrName = this.q();
674
630
  if (!attrName) {
675
631
  break;
676
632
  }
677
- let attrValue = this.u() && this.J();
633
+ let attrValue = this.t() && this.I();
678
634
  if (attrValue === false) {
679
635
  throw this.a("Attribute value expected");
680
636
  }
@@ -686,7 +642,7 @@ var Parser = class {
686
642
  }
687
643
  attributes[attrName] = attrValue;
688
644
  }
689
- if (this.f.sortAttributes) {
645
+ if (this.g.sortAttributes) {
690
646
  let attrNames = Object.keys(attributes).sort();
691
647
  let sortedAttributes = /* @__PURE__ */ Object.create(null);
692
648
  for (let i = 0; i < attrNames.length; ++i) {
@@ -707,41 +663,40 @@ var Parser = class {
707
663
  *
708
664
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-AttValue
709
665
  */
710
- J() {
666
+ I() {
711
667
  let { c: scanner } = this;
712
- let quote = scanner.h();
668
+ let quote = scanner.m();
713
669
  if (quote !== '"' && quote !== "'") {
714
670
  return false;
715
671
  }
716
- scanner.g();
672
+ scanner.p();
717
673
  let chars;
718
674
  let isClosed = false;
719
675
  let value = emptyString2;
720
676
  let regex = quote === '"' ? attValueCharDoubleQuote : attValueCharSingleQuote;
721
- matchLoop:
722
- while (!scanner.z) {
723
- chars = scanner.G(regex);
724
- if (chars) {
725
- this.p(chars);
726
- value += chars.replace(attValueNormalizedWhitespace, " ");
727
- }
728
- switch (scanner.h()) {
729
- case quote:
730
- isClosed = true;
731
- break matchLoop;
732
- case "&":
733
- value += this.C();
734
- continue;
735
- case "<":
736
- throw this.a("Unescaped `<` is not allowed in an attribute value");
737
- case emptyString2:
738
- break matchLoop;
739
- }
677
+ matchLoop: while (!scanner.B) {
678
+ chars = scanner.x(regex);
679
+ if (chars) {
680
+ this.o(chars);
681
+ value += chars.replace(attValueNormalizedWhitespace, " ");
682
+ }
683
+ switch (scanner.m()) {
684
+ case quote:
685
+ isClosed = true;
686
+ break matchLoop;
687
+ case "&":
688
+ value += this.C();
689
+ continue;
690
+ case "<":
691
+ throw this.a("Unescaped `<` is not allowed in an attribute value");
692
+ default:
693
+ break matchLoop;
740
694
  }
695
+ }
741
696
  if (!isClosed) {
742
697
  throw this.a("Unclosed attribute");
743
698
  }
744
- scanner.g();
699
+ scanner.p();
745
700
  return value;
746
701
  }
747
702
  /**
@@ -750,18 +705,18 @@ var Parser = class {
750
705
  * @returns Whether a CDATA section was consumed.
751
706
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-cdata-sect
752
707
  */
753
- K() {
708
+ J() {
754
709
  let { c: scanner } = this;
755
710
  let startIndex = scanner.d;
756
711
  if (!scanner.b("<![CDATA[")) {
757
712
  return false;
758
713
  }
759
- let text = scanner.t("]]>");
760
- this.p(text);
714
+ let text = scanner.s("]]>");
715
+ this.o(text);
761
716
  if (!scanner.b("]]>")) {
762
717
  throw this.a("Unclosed CDATA section");
763
718
  }
764
- return this.f.preserveCdata ? this.j(new XmlCdata(normalizeLineBreaks(text)), startIndex) : this.x(text, startIndex);
719
+ return this.g.preserveCdata ? this.i(new XmlCdata(normalizeLineBreaks(text)), startIndex) : this.y(text, startIndex);
765
720
  }
766
721
  /**
767
722
  * Consumes character data if possible.
@@ -769,18 +724,18 @@ var Parser = class {
769
724
  * @returns Whether character data was consumed.
770
725
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#dt-chardata
771
726
  */
772
- L() {
727
+ K() {
773
728
  let { c: scanner } = this;
774
729
  let startIndex = scanner.d;
775
- let charData = scanner.A(endCharData);
730
+ let charData = scanner.x(endCharData);
776
731
  if (!charData) {
777
732
  return false;
778
733
  }
779
- this.p(charData);
780
- if (scanner.h(3) === "]]>") {
734
+ this.o(charData);
735
+ if (scanner.m(3) === "]]>") {
781
736
  throw this.a("Element content may not contain the CDATA section close delimiter `]]>`");
782
737
  }
783
- return this.x(charData, startIndex);
738
+ return this.y(charData, startIndex);
784
739
  }
785
740
  /**
786
741
  * Consumes a comment if possible.
@@ -794,15 +749,15 @@ var Parser = class {
794
749
  if (!scanner.b("<!--")) {
795
750
  return false;
796
751
  }
797
- let content = scanner.t("--");
798
- this.p(content);
752
+ let content = scanner.s("--");
753
+ this.o(content);
799
754
  if (!scanner.b("-->")) {
800
- if (scanner.h(2) === "--") {
755
+ if (scanner.m(2) === "--") {
801
756
  throw this.a("The string `--` isn't allowed inside a comment");
802
757
  }
803
758
  throw this.a("Unclosed comment");
804
759
  }
805
- return this.f.preserveComments ? this.j(new XmlComment(normalizeLineBreaks(content)), startIndex) : true;
760
+ return this.g.preserveComments ? this.i(new XmlComment(normalizeLineBreaks(content)), startIndex) : true;
806
761
  }
807
762
  /**
808
763
  * Consumes a reference in a content context if possible.
@@ -813,10 +768,10 @@ var Parser = class {
813
768
  * @returns Whether a reference was consumed.
814
769
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#entproc
815
770
  */
816
- M() {
771
+ L() {
817
772
  let startIndex = this.c.d;
818
773
  let ref = this.C();
819
- return ref ? this.x(ref, startIndex) : false;
774
+ return ref ? this.y(ref, startIndex) : false;
820
775
  }
821
776
  /**
822
777
  * Consumes a doctype declaration if possible.
@@ -827,13 +782,13 @@ var Parser = class {
827
782
  * @returns Whether a doctype declaration was consumed.
828
783
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#dtd
829
784
  */
830
- N() {
785
+ M() {
831
786
  let { c: scanner } = this;
832
787
  let startIndex = scanner.d;
833
788
  if (!scanner.b("<!DOCTYPE")) {
834
789
  return false;
835
790
  }
836
- let name = this.e() && this.r();
791
+ let name = this.e() && this.q();
837
792
  if (!name) {
838
793
  throw this.a("Expected a name");
839
794
  }
@@ -841,7 +796,7 @@ var Parser = class {
841
796
  let systemId;
842
797
  if (this.e()) {
843
798
  if (scanner.b("PUBLIC")) {
844
- publicId = this.e() && this.O();
799
+ publicId = this.e() && this.N();
845
800
  if (publicId === false) {
846
801
  throw this.a("Expected a public identifier");
847
802
  }
@@ -849,7 +804,7 @@ var Parser = class {
849
804
  }
850
805
  if (publicId !== void 0 || scanner.b("SYSTEM")) {
851
806
  this.e();
852
- systemId = this.s();
807
+ systemId = this.r();
853
808
  if (systemId === false) {
854
809
  throw this.a("Expected a system identifier");
855
810
  }
@@ -858,7 +813,7 @@ var Parser = class {
858
813
  }
859
814
  let internalSubset;
860
815
  if (scanner.b("[")) {
861
- internalSubset = scanner.A(/\][\x20\t\r\n]*>/);
816
+ internalSubset = scanner.x(/\][\x20\t\r\n]*>/);
862
817
  if (!scanner.b("]")) {
863
818
  throw this.a("Unclosed internal subset");
864
819
  }
@@ -867,7 +822,7 @@ var Parser = class {
867
822
  if (!scanner.b(">")) {
868
823
  throw this.a("Unclosed doctype declaration");
869
824
  }
870
- return this.f.preserveDocumentType ? this.j(new XmlDocumentType(name, publicId, systemId, internalSubset), startIndex) : true;
825
+ return this.g.preserveDocumentType ? this.i(new XmlDocumentType(name, publicId, systemId, internalSubset), startIndex) : true;
871
826
  }
872
827
  /**
873
828
  * Consumes an element if possible.
@@ -875,42 +830,42 @@ var Parser = class {
875
830
  * @returns Whether an element was consumed.
876
831
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-element
877
832
  */
878
- B() {
833
+ E() {
879
834
  let { c: scanner } = this;
880
835
  let startIndex = scanner.d;
881
836
  if (!scanner.b("<")) {
882
837
  return false;
883
838
  }
884
- let name = this.r();
839
+ let name = this.q();
885
840
  if (!name) {
886
- scanner.o(startIndex);
841
+ scanner.n(startIndex);
887
842
  return false;
888
843
  }
889
- let attributes = this.I();
844
+ let attributes = this.H();
890
845
  let isEmpty = !!scanner.b("/>");
891
846
  let element = new XmlElement(name, attributes);
892
- element.parent = this.l;
847
+ element.parent = this.j;
893
848
  if (!isEmpty) {
894
849
  if (!scanner.b(">")) {
895
850
  throw this.a(`Unclosed start tag for element \`${name}\``);
896
851
  }
897
- this.l = element;
852
+ this.j = element;
898
853
  do {
899
- this.L();
900
- } while (this.B() || this.M() || this.K() || this.E() || this.D());
854
+ this.K();
855
+ } while (this.E() || this.L() || this.J() || this.F() || this.D());
901
856
  let endTagMark = scanner.d;
902
857
  let endTagName;
903
- if (!scanner.b("</") || !(endTagName = this.r()) || endTagName !== name) {
904
- scanner.o(endTagMark);
858
+ if (!scanner.b("</") || !(endTagName = this.q()) || endTagName !== name) {
859
+ scanner.n(endTagMark);
905
860
  throw this.a(`Missing end tag for element ${name}`);
906
861
  }
907
862
  this.e();
908
863
  if (!scanner.b(">")) {
909
864
  throw this.a(`Unclosed end tag for element ${name}`);
910
865
  }
911
- this.l = element.parent;
866
+ this.j = element.parent;
912
867
  }
913
- return this.j(element, startIndex);
868
+ return this.i(element, startIndex);
914
869
  }
915
870
  /**
916
871
  * Consumes an `Eq` production if possible.
@@ -918,7 +873,7 @@ var Parser = class {
918
873
  * @returns Whether an `Eq` production was consumed.
919
874
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-Eq
920
875
  */
921
- u() {
876
+ t() {
922
877
  this.e();
923
878
  if (this.c.b("=")) {
924
879
  this.e();
@@ -932,8 +887,8 @@ var Parser = class {
932
887
  * @returns Whether anything was consumed.
933
888
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-Misc
934
889
  */
935
- w() {
936
- return this.D() || this.E() || this.e();
890
+ z() {
891
+ return this.D() || this.F() || this.e();
937
892
  }
938
893
  /**
939
894
  * Consumes one or more `Name` characters if possible.
@@ -941,8 +896,8 @@ var Parser = class {
941
896
  * @returns `Name` characters, or an empty string if none were consumed.
942
897
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-Name
943
898
  */
944
- r() {
945
- return isNameStartChar(this.c.h()) ? this.c.v(isNameChar) : emptyString2;
899
+ q() {
900
+ return isNameStartChar(this.c.m()) ? this.c.w(isNameChar) : emptyString2;
946
901
  }
947
902
  /**
948
903
  * Consumes a processing instruction if possible.
@@ -950,16 +905,16 @@ var Parser = class {
950
905
  * @returns Whether a processing instruction was consumed.
951
906
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-pi
952
907
  */
953
- E() {
908
+ F() {
954
909
  let { c: scanner } = this;
955
910
  let startIndex = scanner.d;
956
911
  if (!scanner.b("<?")) {
957
912
  return false;
958
913
  }
959
- let name = this.r();
914
+ let name = this.q();
960
915
  if (name) {
961
916
  if (name.toLowerCase() === "xml") {
962
- scanner.o(startIndex);
917
+ scanner.n(startIndex);
963
918
  throw this.a("XML declaration isn't allowed here");
964
919
  }
965
920
  } else {
@@ -967,16 +922,16 @@ var Parser = class {
967
922
  }
968
923
  if (!this.e()) {
969
924
  if (scanner.b("?>")) {
970
- return this.j(new XmlProcessingInstruction(name), startIndex);
925
+ return this.i(new XmlProcessingInstruction(name), startIndex);
971
926
  }
972
927
  throw this.a("Whitespace is required after a processing instruction name");
973
928
  }
974
- let content = scanner.t("?>");
975
- this.p(content);
929
+ let content = scanner.s("?>");
930
+ this.o(content);
976
931
  if (!scanner.b("?>")) {
977
932
  throw this.a("Unterminated processing instruction");
978
933
  }
979
- return this.j(new XmlProcessingInstruction(name, normalizeLineBreaks(content)), startIndex);
934
+ return this.i(new XmlProcessingInstruction(name, normalizeLineBreaks(content)), startIndex);
980
935
  }
981
936
  /**
982
937
  * Consumes a prolog if possible.
@@ -984,14 +939,14 @@ var Parser = class {
984
939
  * @returns Whether a prolog was consumed.
985
940
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-prolog-dtd
986
941
  */
987
- H() {
942
+ O() {
988
943
  let { c: scanner } = this;
989
944
  let startIndex = scanner.d;
990
945
  this.P();
991
- while (this.w()) {
946
+ while (this.z()) {
992
947
  }
993
- if (this.N()) {
994
- while (this.w()) {
948
+ if (this.M()) {
949
+ while (this.z()) {
995
950
  }
996
951
  }
997
952
  return startIndex < scanner.d;
@@ -1006,11 +961,11 @@ var Parser = class {
1006
961
  *
1007
962
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-PubidLiteral
1008
963
  */
1009
- O() {
964
+ N() {
1010
965
  let startIndex = this.c.d;
1011
- let value = this.s();
966
+ let value = this.r();
1012
967
  if (value !== false && !/^[-\x20\r\na-zA-Z0-9'()+,./:=?;!*#@$_%]*$/.test(value)) {
1013
- this.c.o(startIndex);
968
+ this.c.n(startIndex);
1014
969
  throw this.a("Invalid character in public identifier");
1015
970
  }
1016
971
  return value;
@@ -1032,8 +987,8 @@ var Parser = class {
1032
987
  if (!scanner.b("&")) {
1033
988
  return false;
1034
989
  }
1035
- let ref = scanner.v(isReferenceChar);
1036
- if (scanner.F() !== ";") {
990
+ let ref = scanner.w(isReferenceChar);
991
+ if (scanner.G() !== ";") {
1037
992
  throw this.a("Unterminated reference (a reference must end with `;`)");
1038
993
  }
1039
994
  let parsedValue;
@@ -1052,7 +1007,7 @@ var Parser = class {
1052
1007
  let {
1053
1008
  ignoreUndefinedEntities,
1054
1009
  resolveUndefinedEntity
1055
- } = this.f;
1010
+ } = this.g;
1056
1011
  let wrappedRef = `&${ref};`;
1057
1012
  if (resolveUndefinedEntity) {
1058
1013
  let resolvedValue = resolveUndefinedEntity(wrappedRef);
@@ -1067,7 +1022,7 @@ var Parser = class {
1067
1022
  if (ignoreUndefinedEntities) {
1068
1023
  return wrappedRef;
1069
1024
  }
1070
- scanner.o(-wrappedRef.length);
1025
+ scanner.n(-wrappedRef.length);
1071
1026
  throw this.a(`Named entity isn't defined: ${wrappedRef}`);
1072
1027
  }
1073
1028
  }
@@ -1086,14 +1041,14 @@ var Parser = class {
1086
1041
  *
1087
1042
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#NT-SystemLiteral
1088
1043
  */
1089
- s() {
1044
+ r() {
1090
1045
  let { c: scanner } = this;
1091
1046
  let quote = scanner.b('"') || scanner.b("'");
1092
1047
  if (!quote) {
1093
1048
  return false;
1094
1049
  }
1095
- let value = scanner.t(quote);
1096
- this.p(value);
1050
+ let value = scanner.s(quote);
1051
+ this.o(value);
1097
1052
  if (!scanner.b(quote)) {
1098
1053
  throw this.a("Missing end quote");
1099
1054
  }
@@ -1106,7 +1061,7 @@ var Parser = class {
1106
1061
  * @see https://www.w3.org/TR/2008/REC-xml-20081126/#white
1107
1062
  */
1108
1063
  e() {
1109
- return !!this.c.v(isWhitespace);
1064
+ return !!this.c.w(isWhitespace);
1110
1065
  }
1111
1066
  /**
1112
1067
  * Consumes an XML declaration if possible.
@@ -1123,7 +1078,7 @@ var Parser = class {
1123
1078
  if (!this.e()) {
1124
1079
  throw this.a("Invalid XML declaration");
1125
1080
  }
1126
- let version = !!scanner.b("version") && this.u() && this.s();
1081
+ let version = !!scanner.b("version") && this.t() && this.r();
1127
1082
  if (version === false) {
1128
1083
  throw this.a("XML version is missing or invalid");
1129
1084
  } else if (!/^1\.[0-9]+$/.test(version)) {
@@ -1132,11 +1087,14 @@ var Parser = class {
1132
1087
  let encoding;
1133
1088
  let standalone;
1134
1089
  if (this.e()) {
1135
- encoding = !!scanner.b("encoding") && this.u() && this.s();
1090
+ encoding = !!scanner.b("encoding") && this.t() && this.r();
1136
1091
  if (encoding) {
1092
+ if (!/^[A-Za-z][\w.-]*$/.test(encoding)) {
1093
+ throw this.a("Invalid character in encoding name");
1094
+ }
1137
1095
  this.e();
1138
1096
  }
1139
- standalone = !!scanner.b("standalone") && this.u() && this.s();
1097
+ standalone = !!scanner.b("standalone") && this.t() && this.r();
1140
1098
  if (standalone) {
1141
1099
  if (standalone !== "yes" && standalone !== "no") {
1142
1100
  throw this.a('Only "yes" and "no" are permitted as values of `standalone`');
@@ -1147,7 +1105,7 @@ var Parser = class {
1147
1105
  if (!scanner.b("?>")) {
1148
1106
  throw this.a("Invalid or unclosed XML declaration");
1149
1107
  }
1150
- return this.f.preserveXmlDeclaration ? this.j(new XmlDeclaration(
1108
+ return this.g.preserveXmlDeclaration ? this.i(new XmlDeclaration(
1151
1109
  version,
1152
1110
  encoding || void 0,
1153
1111
  standalone || void 0
@@ -1158,18 +1116,33 @@ var Parser = class {
1158
1116
  */
1159
1117
  a(message) {
1160
1118
  let { c: scanner } = this;
1161
- return new XmlError(message, scanner.d, scanner.m);
1119
+ return new XmlError(message, scanner.d, scanner.h);
1120
+ }
1121
+ /**
1122
+ * Parses the XML input.
1123
+ */
1124
+ parse() {
1125
+ this.c.b("\uFEFF");
1126
+ this.O();
1127
+ if (!this.E()) {
1128
+ throw this.a("Root element is missing or invalid");
1129
+ }
1130
+ while (this.z()) {
1131
+ }
1132
+ if (!this.c.B) {
1133
+ throw this.a("Extra content at the end of the document");
1134
+ }
1162
1135
  }
1163
1136
  /**
1164
1137
  * Throws an invalid character error if any character in the given _string_
1165
1138
  * isn't a valid XML character.
1166
1139
  */
1167
- p(string) {
1140
+ o(string) {
1168
1141
  let { length } = string;
1169
1142
  for (let i = 0; i < length; ++i) {
1170
1143
  let cp = string.codePointAt(i);
1171
1144
  if (!isXmlCodePoint(cp)) {
1172
- this.c.o(-([...string].length - i));
1145
+ this.c.n(-([...string].length - i));
1173
1146
  throw this.a("Invalid character");
1174
1147
  }
1175
1148
  if (cp > 65535) {