@xmldom/xmldom 0.9.0-beta.9 → 0.9.1

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/lib/sax.js CHANGED
@@ -2,12 +2,15 @@
2
2
 
3
3
  var conventions = require('./conventions');
4
4
  var g = require('./grammar');
5
+ var errors = require('./errors');
5
6
 
6
7
  var isHTMLEscapableRawTextElement = conventions.isHTMLEscapableRawTextElement;
7
8
  var isHTMLMimeType = conventions.isHTMLMimeType;
8
9
  var isHTMLRawTextElement = conventions.isHTMLRawTextElement;
10
+ var hasOwn = conventions.hasOwn;
9
11
  var NAMESPACE = conventions.NAMESPACE;
10
- var ParseError = conventions.ParseError;
12
+ var ParseError = errors.ParseError;
13
+ var DOMException = errors.DOMException;
11
14
 
12
15
  //var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
13
16
 
@@ -28,14 +31,26 @@ XMLReader.prototype = {
28
31
  parse: function (source, defaultNSMap, entityMap) {
29
32
  var domBuilder = this.domBuilder;
30
33
  domBuilder.startDocument();
31
- _copy(defaultNSMap, (defaultNSMap = {}));
34
+ _copy(defaultNSMap, (defaultNSMap = Object.create(null)));
32
35
  parse(source, defaultNSMap, entityMap, domBuilder, this.errorHandler);
33
36
  domBuilder.endDocument();
34
37
  },
35
38
  };
36
39
 
40
+ /**
41
+ * Detecting everything that might be a reference,
42
+ * including those without ending `;`, since those are allowed in HTML.
43
+ * The entityReplacer takes care of verifying and transforming each occurrence,
44
+ * and reports to the errorHandler on those that are not OK,
45
+ * depending on the context.
46
+ */
47
+ var ENTITY_REG = /&#?\w+;?/g;
48
+
37
49
  function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
38
50
  var isHTML = isHTMLMimeType(domBuilder.mimeType);
51
+ if (source.indexOf(g.UNICODE_REPLACEMENT_CHARACTER) >= 0) {
52
+ return errorHandler.fatalError('Unicode replacement character detected, source encoding issues?');
53
+ }
39
54
 
40
55
  function fixedFromCharCode(code) {
41
56
  // String.prototype.fromCharCode does not supports
@@ -52,8 +67,18 @@ function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
52
67
  }
53
68
 
54
69
  function entityReplacer(a) {
55
- var k = a.slice(1, -1);
56
- if (Object.hasOwnProperty.call(entityMap, k)) {
70
+ var complete = a[a.length - 1] === ';' ? a : a + ';';
71
+ if (!isHTML && complete !== a) {
72
+ errorHandler.error('EntityRef: expecting ;');
73
+ return a;
74
+ }
75
+ var match = g.Reference.exec(complete);
76
+ if (!match || match[0].length !== complete.length) {
77
+ errorHandler.error('entity not matching Reference production: ' + a);
78
+ return a;
79
+ }
80
+ var k = complete.slice(1, -1);
81
+ if (hasOwn(entityMap, k)) {
57
82
  return entityMap[k];
58
83
  } else if (k.charAt(0) === '#') {
59
84
  return fixedFromCharCode(parseInt(k.substr(1).replace('x', '0x')));
@@ -66,7 +91,7 @@ function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
66
91
  function appendText(end) {
67
92
  //has some bugs
68
93
  if (end > start) {
69
- var xt = source.substring(start, end).replace(/&#?\w+;/g, entityReplacer);
94
+ var xt = source.substring(start, end).replace(ENTITY_REG, entityReplacer);
70
95
  locator && position(start);
71
96
  domBuilder.characters(xt, 0, end - start);
72
97
  start = end;
@@ -88,70 +113,83 @@ function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
88
113
  var locator = domBuilder.locator;
89
114
 
90
115
  var parseStack = [{ currentNSMap: defaultNSMapCopy }];
91
- var closeMap = {};
116
+ var unclosedTags = [];
92
117
  var start = 0;
93
118
  while (true) {
94
119
  try {
95
120
  var tagStart = source.indexOf('<', start);
96
121
  if (tagStart < 0) {
97
- if (!source.substr(start).match(/^\s*$/)) {
122
+ if (!isHTML && unclosedTags.length > 0) {
123
+ return errorHandler.fatalError('unclosed xml tag(s): ' + unclosedTags.join(', '));
124
+ }
125
+ if (!source.substring(start).match(/^\s*$/)) {
98
126
  var doc = domBuilder.doc;
99
127
  var text = doc.createTextNode(source.substr(start));
128
+ if (doc.documentElement) {
129
+ return errorHandler.error('Extra content at the end of the document');
130
+ }
100
131
  doc.appendChild(text);
101
132
  domBuilder.currentElement = text;
102
133
  }
103
134
  return;
104
135
  }
105
136
  if (tagStart > start) {
137
+ var fromSource = source.substring(start, tagStart);
138
+ if (!isHTML && unclosedTags.length === 0) {
139
+ fromSource = fromSource.replace(new RegExp(g.S_OPT.source, 'g'), '');
140
+ fromSource && errorHandler.error("Unexpected content outside root element: '" + fromSource + "'");
141
+ }
106
142
  appendText(tagStart);
107
143
  }
108
144
  switch (source.charAt(tagStart + 1)) {
109
145
  case '/':
110
- var config = parseStack.pop();
111
- var end = source.indexOf('>', tagStart + 3);
146
+ var end = source.indexOf('>', tagStart + 2);
112
147
  var tagNameRaw = source.substring(tagStart + 2, end > 0 ? end : undefined);
113
- var tagNameMatch = g.QName_group.exec(tagNameRaw);
114
- // for the root level the config does not contain the tagName
115
- var tagName =
116
- tagNameMatch && tagNameMatch[1] ? tagNameMatch[1] : config.tagName || domBuilder.doc.documentElement.tagName;
117
- if (end < 0) {
118
- errorHandler.error('end tag name: ' + tagName + ' is not complete');
119
- end = tagStart + 1 + tagName.length;
120
- } else if (tagNameRaw.match(/</) && !isHTML) {
121
- errorHandler.error('end tag name: ' + tagName + ' maybe not complete');
148
+ if (!tagNameRaw) {
149
+ return errorHandler.fatalError('end tag name missing');
150
+ }
151
+ var tagNameMatch = end > 0 && g.reg('^', g.QName_group, g.S_OPT, '$').exec(tagNameRaw);
152
+ if (!tagNameMatch) {
153
+ return errorHandler.fatalError('end tag name contains invalid characters: "' + tagNameRaw + '"');
154
+ }
155
+ if (!domBuilder.currentElement && !domBuilder.doc.documentElement) {
156
+ // not enough information to provide a helpful error message,
157
+ // but parsing will throw since there is no root element
158
+ return;
159
+ }
160
+ var currentTagName =
161
+ unclosedTags[unclosedTags.length - 1] ||
162
+ domBuilder.currentElement.tagName ||
163
+ domBuilder.doc.documentElement.tagName ||
164
+ '';
165
+ if (currentTagName !== tagNameMatch[1]) {
166
+ var tagNameLower = tagNameMatch[1].toLowerCase();
167
+ if (!isHTML || currentTagName.toLowerCase() !== tagNameLower) {
168
+ return errorHandler.fatalError('Opening and ending tag mismatch: "' + currentTagName + '" != "' + tagNameRaw + '"');
169
+ }
122
170
  }
171
+ var config = parseStack.pop();
172
+ unclosedTags.pop();
123
173
  var localNSMap = config.localNSMap;
124
- var endMatch = config.tagName == tagName;
125
- var endIgnoreCaseMach = endMatch || (config.tagName && config.tagName.toLowerCase() == tagName.toLowerCase());
126
- if (endIgnoreCaseMach) {
127
- domBuilder.endElement(config.uri, config.localName, tagName);
128
- if (localNSMap) {
129
- for (var prefix in localNSMap) {
130
- if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
131
- domBuilder.endPrefixMapping(prefix);
132
- }
174
+ domBuilder.endElement(config.uri, config.localName, currentTagName);
175
+ if (localNSMap) {
176
+ for (var prefix in localNSMap) {
177
+ if (hasOwn(localNSMap, prefix)) {
178
+ domBuilder.endPrefixMapping(prefix);
133
179
  }
134
180
  }
135
- if (!endMatch) {
136
- // No known test case
137
- return errorHandler.fatalError(
138
- 'end tag name: ' + tagName + ' is not match the current start tagName:' + config.tagName
139
- );
140
- }
141
- } else {
142
- parseStack.push(config);
143
181
  }
144
182
 
145
183
  end++;
146
184
  break;
147
- // end elment
185
+ // end element
148
186
  case '?': // <?...?>
149
187
  locator && position(tagStart);
150
188
  end = parseProcessingInstruction(source, tagStart, domBuilder, errorHandler);
151
189
  break;
152
190
  case '!': // <!doctype,<![CDATA,<!--
153
191
  locator && position(tagStart);
154
- end = parseDoctypeCommentOrCData(source, tagStart, domBuilder, errorHandler);
192
+ end = parseDoctypeCommentOrCData(source, tagStart, domBuilder, errorHandler, isHTML);
155
193
  break;
156
194
  default:
157
195
  locator && position(tagStart);
@@ -161,10 +199,11 @@ function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
161
199
  var end = parseElementStartPart(source, tagStart, el, currentNSMap, entityReplacer, errorHandler, isHTML);
162
200
  var len = el.length;
163
201
 
164
- if (!el.closed && fixSelfClosed(source, end, el.tagName, closeMap)) {
165
- el.closed = true;
166
- if (!isHTML) {
167
- errorHandler.warning('unclosed xml attribute');
202
+ if (!el.closed) {
203
+ if (isHTML && conventions.isHTMLVoidElement(el.tagName)) {
204
+ el.closed = true;
205
+ } else {
206
+ unclosedTags.push(el.tagName);
168
207
  }
169
208
  }
170
209
  if (locator && len) {
@@ -195,6 +234,8 @@ function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
195
234
  } catch (e) {
196
235
  if (e instanceof ParseError) {
197
236
  throw e;
237
+ } else if (e instanceof DOMException) {
238
+ throw new ParseError(e.name + ': ' + e.message, domBuilder.locator, e);
198
239
  }
199
240
  errorHandler.error('element parse error: ' + e);
200
241
  end = -1;
@@ -202,7 +243,7 @@ function parse(source, defaultNSMapCopy, entityMap, domBuilder, errorHandler) {
202
243
  if (end > start) {
203
244
  start = end;
204
245
  } else {
205
- //TODO: 这里有可能sax回退,有位置错误风险
246
+ //Possible sax fallback here, risk of positional error
206
247
  appendText(Math.max(tagStart, start) + 1);
207
248
  }
208
249
  }
@@ -215,8 +256,9 @@ function copyLocator(f, t) {
215
256
  }
216
257
 
217
258
  /**
218
- * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
219
- * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
259
+ * @returns
260
+ * end of the elementStartPart(end of elementEndPart for selfClosed el)
261
+ * @see {@link #appendElement}
220
262
  */
221
263
  function parseElementStartPart(source, start, el, currentNSMap, entityReplacer, errorHandler, isHTML) {
222
264
  /**
@@ -225,16 +267,19 @@ function parseElementStartPart(source, start, el, currentNSMap, entityReplacer,
225
267
  * @param {number} startIndex
226
268
  */
227
269
  function addAttribute(qname, value, startIndex) {
228
- if (el.attributeNames.hasOwnProperty(qname)) {
270
+ if (hasOwn(el.attributeNames, qname)) {
229
271
  return errorHandler.fatalError('Attribute ' + qname + ' redefined');
230
272
  }
273
+ if (!isHTML && value.indexOf('<') >= 0) {
274
+ return errorHandler.fatalError("Unescaped '<' not allowed in attributes values");
275
+ }
231
276
  el.addValue(
232
277
  qname,
233
278
  // @see https://www.w3.org/TR/xml/#AVNormalize
234
279
  // since the xmldom sax parser does not "interpret" DTD the following is not implemented:
235
280
  // - recursive replacement of (DTD) entity references
236
281
  // - trimming and collapsing multiple spaces into a single one for attributes that are not of type CDATA
237
- value.replace(/[\t\n\r]/g, ' ').replace(/&#?\w+;/g, entityReplacer),
282
+ value.replace(/[\t\n\r]/g, ' ').replace(ENTITY_REG, entityReplacer),
238
283
  startIndex
239
284
  );
240
285
  }
@@ -346,7 +391,9 @@ function parseElementStartPart(source, start, el, currentNSMap, entityReplacer,
346
391
  }
347
392
  break;
348
393
  case S_EQ:
349
- throw new Error('attribute value missed!!');
394
+ if (!isHTML) {
395
+ return errorHandler.fatalError('AttValue: \' or " expected');
396
+ }
350
397
  }
351
398
  return p;
352
399
  /*xml space '\x20' | #x9 | #xD | #xA; */
@@ -409,18 +456,17 @@ function parseElementStartPart(source, start, el, currentNSMap, entityReplacer,
409
456
  }
410
457
  }
411
458
  } //end outer switch
412
- //console.log('p++',p)
413
459
  p++;
414
460
  }
415
461
  }
416
462
 
417
463
  /**
418
- * @return true if has new namespace define
464
+ * @returns
465
+ * `true` if a new namespace has been defined.
419
466
  */
420
467
  function appendElement(el, domBuilder, currentNSMap) {
421
468
  var tagName = el.tagName;
422
469
  var localNSMap = null;
423
- //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
424
470
  var i = el.length;
425
471
  while (i--) {
426
472
  var a = el[i];
@@ -442,10 +488,8 @@ function appendElement(el, domBuilder, currentNSMap) {
442
488
  if (nsPrefix !== false) {
443
489
  //hack!!
444
490
  if (localNSMap == null) {
445
- localNSMap = {};
446
- //console.log(currentNSMap,0)
447
- _copy(currentNSMap, (currentNSMap = {}));
448
- //console.log(currentNSMap,1)
491
+ localNSMap = Object.create(null);
492
+ _copy(currentNSMap, (currentNSMap = Object.create(null)));
449
493
  }
450
494
  currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
451
495
  a.uri = NAMESPACE.XMLNS;
@@ -482,7 +526,7 @@ function appendElement(el, domBuilder, currentNSMap) {
482
526
  domBuilder.endElement(ns, localName, tagName);
483
527
  if (localNSMap) {
484
528
  for (prefix in localNSMap) {
485
- if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
529
+ if (hasOwn(localNSMap, prefix)) {
486
530
  domBuilder.endPrefixMapping(prefix);
487
531
  }
488
532
  }
@@ -506,7 +550,7 @@ function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, do
506
550
  var text = source.substring(elStartEnd + 1, elEndStart);
507
551
 
508
552
  if (isEscapableRaw) {
509
- text = text.replace(/&#?\w+;/g, entityReplacer);
553
+ text = text.replace(ENTITY_REG, entityReplacer);
510
554
  }
511
555
  domBuilder.characters(text, 0, text.length);
512
556
  return elEndStart;
@@ -514,25 +558,9 @@ function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, do
514
558
  return elStartEnd + 1;
515
559
  }
516
560
 
517
- function fixSelfClosed(source, elStartEnd, tagName, closeMap) {
518
- //if(tagName in closeMap){
519
- var pos = closeMap[tagName];
520
- if (pos == null) {
521
- //console.log(tagName)
522
- pos = source.lastIndexOf('</' + tagName + '>');
523
- if (pos < elStartEnd) {
524
- //忘记闭合
525
- pos = source.lastIndexOf('</' + tagName);
526
- }
527
- closeMap[tagName] = pos;
528
- }
529
- return pos < elStartEnd;
530
- //}
531
- }
532
-
533
561
  function _copy(source, target) {
534
562
  for (var n in source) {
535
- if (Object.prototype.hasOwnProperty.call(source, n)) {
563
+ if (hasOwn(source, n)) {
536
564
  target[n] = source[n];
537
565
  }
538
566
  }
@@ -540,23 +568,28 @@ function _copy(source, target) {
540
568
 
541
569
  /**
542
570
  * @typedef ParseUtils
543
- * @property {function(relativeIndex: number?): string | undefined} char provides look ahead access
544
- * to a singe character relative to the current index
545
- * @property {function(): number} getIndex provides read-only access to the current index
546
- * @property {function(reg: RegExp): string | null} getMatch applies the provided regular expression
547
- * enforcing that it starts at the current index and returns the complete matching string,
548
- * and moves the current index by the length of the matching string.
549
- * @property {function(): string} getSource provides read-only access to the complete source
550
- * @property {function(places: number?): void} skip moves the current index
551
- * by places (defaults to 1)
552
- * @property {function(): number} skipBlanks moves the current index by the amount of white space
553
- * that directly follows the current index and returns the amount of whitespace chars skipped (0..n),
554
- * or -1 if the end of the source was reached.
555
- * @property {function(): string} substringFromIndex creates a substring from the current index to the end of `source`
556
- * @property {function(compareWith: string): boolean} substringStartsWith checks if source contains `compareWith`,
557
- * starting from the current index
558
- *
559
- * @see parseUtils
571
+ * @property {function(relativeIndex: number?): string | undefined} char
572
+ * Provides look ahead access to a singe character relative to the current index.
573
+ * @property {function(): number} getIndex
574
+ * Provides read-only access to the current index.
575
+ * @property {function(reg: RegExp): string | null} getMatch
576
+ * Applies the provided regular expression enforcing that it starts at the current index and
577
+ * returns the complete matching string,
578
+ * and moves the current index by the length of the matching string.
579
+ * @property {function(): string} getSource
580
+ * Provides read-only access to the complete source.
581
+ * @property {function(places: number?): void} skip
582
+ * moves the current index by places (defaults to 1)
583
+ * @property {function(): number} skipBlanks
584
+ * Moves the current index by the amount of white space that directly follows the current index
585
+ * and returns the amount of whitespace chars skipped (0..n),
586
+ * or -1 if the end of the source was reached.
587
+ * @property {function(): string} substringFromIndex
588
+ * creates a substring from the current index to the end of `source`
589
+ * @property {function(compareWith: string): boolean} substringStartsWith
590
+ * Checks if source contains `compareWith`,
591
+ * starting from the current index.
592
+ * @see {@link parseUtils}
560
593
  */
561
594
 
562
595
  /**
@@ -656,8 +689,13 @@ function parseDoctypeInternalSubset(p, errorHandler) {
656
689
  if (p.char() === '[') {
657
690
  p.skip(1);
658
691
  var intSubsetStart = p.getIndex();
659
- p.skipBlanks();
660
692
  while (p.getIndex() < source.length) {
693
+ p.skipBlanks();
694
+ if (p.char() === ']') {
695
+ var internalSubset = source.substring(intSubsetStart, p.getIndex());
696
+ p.skip(1);
697
+ return internalSubset;
698
+ }
661
699
  var current = null;
662
700
  // Only in external subset
663
701
  // if (char() === '<' && char(1) === '!' && char(2) === '[') {
@@ -665,20 +703,20 @@ function parseDoctypeInternalSubset(p, errorHandler) {
665
703
  // } else
666
704
  if (p.char() === '<' && p.char(1) === '!') {
667
705
  switch (p.char(2)) {
668
- case 'E':
706
+ case 'E': // ELEMENT | ENTITY
669
707
  if (p.char(3) === 'L') {
670
708
  current = p.getMatch(g.elementdecl);
671
709
  } else if (p.char(3) === 'N') {
672
710
  current = p.getMatch(g.EntityDecl);
673
711
  }
674
712
  break;
675
- case 'A':
713
+ case 'A': // ATTRIBUTE
676
714
  current = p.getMatch(g.AttlistDecl);
677
715
  break;
678
- case 'N':
716
+ case 'N': // NOTATION
679
717
  current = p.getMatch(g.NotationDecl);
680
718
  break;
681
- case '-':
719
+ case '-': // COMMENT
682
720
  current = p.getMatch(g.Comment);
683
721
  break;
684
722
  }
@@ -692,13 +730,6 @@ function parseDoctypeInternalSubset(p, errorHandler) {
692
730
  if (!current) {
693
731
  return errorHandler.fatalError('Error in internal subset at position ' + p.getIndex());
694
732
  }
695
- p.skipBlanks();
696
- if (p.char() === ']') {
697
- var internalSubset = source.substring(intSubsetStart, p.getIndex());
698
- p.skip(1);
699
- return internalSubset;
700
- }
701
- p.skipBlanks();
702
733
  }
703
734
  return errorHandler.fatalError('doctype internal subset is not well-formed, missing ]');
704
735
  }
@@ -706,14 +737,20 @@ function parseDoctypeInternalSubset(p, errorHandler) {
706
737
 
707
738
  /**
708
739
  * Called when the parser encounters an element starting with '<!'.
709
- * @param {string} source the xml
710
- * @param {number} start the start index of the '<!'
740
+ *
741
+ * @param {string} source
742
+ * The xml.
743
+ * @param {number} start
744
+ * the start index of the '<!'
711
745
  * @param {DOMHandler} domBuilder
712
746
  * @param {DOMHandler} errorHandler
713
- * @returns {number|never} the end index of the element
714
- * @throws ParseError in case the element is not well-formed
747
+ * @param {boolean} isHTML
748
+ * @returns {number | never}
749
+ * The end index of the element.
750
+ * @throws {ParseError}
751
+ * In case the element is not well-formed.
715
752
  */
716
- function parseDoctypeCommentOrCData(source, start, domBuilder, errorHandler) {
753
+ function parseDoctypeCommentOrCData(source, start, domBuilder, errorHandler, isHTML) {
717
754
  var p = parseUtils(source, start);
718
755
 
719
756
  switch (p.char(2)) {
@@ -730,6 +767,9 @@ function parseDoctypeCommentOrCData(source, start, domBuilder, errorHandler) {
730
767
  // should be CDATA
731
768
  var cdata = p.getMatch(g.CDSect);
732
769
  if (cdata) {
770
+ if (!isHTML && !domBuilder.currentElement) {
771
+ return errorHandler.fatalError('CDATA outside of element');
772
+ }
733
773
  domBuilder.startCDATA();
734
774
  domBuilder.characters(cdata, g.CDATA_START.length, cdata.length - g.CDATA_START.length - g.CDATA_END.length);
735
775
  domBuilder.endCDATA();
@@ -739,13 +779,9 @@ function parseDoctypeCommentOrCData(source, start, domBuilder, errorHandler) {
739
779
  }
740
780
  case 'D': {
741
781
  // should be DOCTYPE
742
- var doctype = {
743
- name: undefined,
744
- publicId: undefined,
745
- systemId: undefined,
746
- internalSubset: undefined,
747
- };
748
-
782
+ if (domBuilder.doc && domBuilder.doc.documentElement) {
783
+ return errorHandler.fatalError('Doctype not allowed inside or after documentElement at position ' + p.getIndex());
784
+ }
749
785
  if (!p.substringStartsWith(g.DOCTYPE_DECL_START)) {
750
786
  return errorHandler.fatalError('Expected ' + g.DOCTYPE_DECL_START + ' at position ' + p.getIndex());
751
787
  }
@@ -754,6 +790,12 @@ function parseDoctypeCommentOrCData(source, start, domBuilder, errorHandler) {
754
790
  return errorHandler.fatalError('Expected whitespace after ' + g.DOCTYPE_DECL_START + ' at position ' + p.getIndex());
755
791
  }
756
792
 
793
+ var doctype = {
794
+ name: undefined,
795
+ publicId: undefined,
796
+ systemId: undefined,
797
+ internalSubset: undefined,
798
+ };
757
799
  // Parse the DOCTYPE name
758
800
  doctype.name = p.getMatch(g.Name);
759
801
  if (!doctype.name)
@@ -811,7 +853,7 @@ function parseProcessingInstruction(source, start, domBuilder, errorHandler) {
811
853
  }
812
854
 
813
855
  function ElementAttributes() {
814
- this.attributeNames = {};
856
+ this.attributeNames = Object.create(null);
815
857
  }
816
858
 
817
859
  ElementAttributes.prototype = {
package/package.json CHANGED
@@ -1,72 +1,75 @@
1
1
  {
2
- "name": "@xmldom/xmldom",
3
- "version": "0.9.0-beta.9",
4
- "description": "A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.",
5
- "keywords": [
6
- "w3c",
7
- "dom",
8
- "xml",
9
- "parser",
10
- "javascript",
11
- "DOMParser",
12
- "XMLSerializer",
13
- "ponyfill"
14
- ],
15
- "homepage": "https://github.com/xmldom/xmldom",
16
- "repository": {
17
- "type": "git",
18
- "url": "git://github.com/xmldom/xmldom.git"
19
- },
20
- "main": "lib/index.js",
21
- "types": "index.d.ts",
22
- "files": [
23
- "CHANGELOG.md",
24
- "LICENSE",
25
- "readme.md",
26
- "SECURITY.md",
27
- "index.d.ts",
28
- "lib"
29
- ],
30
- "scripts": {
31
- "lint": "eslint examples lib test",
32
- "format": "prettier --write examples lib test",
33
- "changelog": "auto-changelog --unreleased-only",
34
- "start": "nodemon --watch package.json --watch lib --watch test --exec 'npm --silent run test && npm --silent run lint'",
35
- "test": "jest",
36
- "test:types": "cd examples/typescript-node-es6 && ./pretest.sh 3 && ./pretest.sh 4 && ./pretest.sh 5 && node dist/index.js",
37
- "testrelease": "npm test && eslint lib",
38
- "version": "./changelog-has-version.sh",
39
- "release": "np --no-yarn --test-script testrelease"
40
- },
41
- "engines": {
42
- "node": ">=10.0.0"
43
- },
44
- "dependencies": {},
45
- "devDependencies": {
46
- "auto-changelog": "2.4.0",
47
- "eslint": "8.42.0",
48
- "eslint-config-prettier": "8.8.0",
49
- "eslint-plugin-anti-trojan-source": "1.1.1",
50
- "eslint-plugin-es5": "1.5.0",
51
- "eslint-plugin-node": "11.1.0",
52
- "eslint-plugin-prettier": "4.2.1",
53
- "get-stream": "6.0.1",
54
- "jest": "27.5.1",
55
- "nodemon": "2.0.22",
56
- "np": "7.7.0",
57
- "prettier": "2.8.8",
58
- "rxjs": "7.8.1",
59
- "xmltest": "1.5.0",
60
- "yauzl": "2.10.0"
61
- },
62
- "bugs": {
63
- "url": "https://github.com/xmldom/xmldom/issues"
64
- },
65
- "license": "MIT",
66
- "auto-changelog": {
67
- "prepend": true,
68
- "remote": "upstream",
69
- "tagPrefix": "",
70
- "template": "./auto-changelog.hbs"
71
- }
2
+ "name": "@xmldom/xmldom",
3
+ "version": "0.9.1",
4
+ "description": "A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.",
5
+ "keywords": [
6
+ "w3c",
7
+ "dom",
8
+ "xml",
9
+ "parser",
10
+ "javascript",
11
+ "DOMParser",
12
+ "XMLSerializer",
13
+ "ponyfill"
14
+ ],
15
+ "homepage": "https://github.com/xmldom/xmldom",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git://github.com/xmldom/xmldom.git"
19
+ },
20
+ "main": "lib/index.js",
21
+ "types": "index.d.ts",
22
+ "files": [
23
+ "CHANGELOG.md",
24
+ "LICENSE",
25
+ "readme.md",
26
+ "SECURITY.md",
27
+ "index.d.ts",
28
+ "lib"
29
+ ],
30
+ "scripts": {
31
+ "lint": "eslint examples lib test",
32
+ "format": "prettier --write examples lib test index.d.ts",
33
+ "changelog": "auto-changelog --unreleased-only",
34
+ "start": "nodemon --watch package.json --watch lib --watch test --exec 'npm --silent run test && npm --silent run lint'",
35
+ "test": "jest",
36
+ "fuzz": "jest --config=./jest.fuzz.config.js",
37
+ "test:types": "cd examples/typescript-node-es6 && ./pretest.sh 3 && ./pretest.sh 4 && ./pretest.sh 5 && node dist/index.js",
38
+ "testrelease": "npm test && eslint lib",
39
+ "version": "./changelog-has-version.sh",
40
+ "release": "np --no-yarn --test-script testrelease"
41
+ },
42
+ "engines": {
43
+ "node": ">=14.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@homer0/prettier-plugin-jsdoc": "9.0.2",
47
+ "@jazzer.js/core": "2.1.0",
48
+ "@jazzer.js/jest-runner": "2.1.0",
49
+ "auto-changelog": "2.4.0",
50
+ "eslint": "8.57.0",
51
+ "eslint-config-prettier": "9.1.0",
52
+ "eslint-plugin-anti-trojan-source": "1.1.1",
53
+ "eslint-plugin-es5": "1.5.0",
54
+ "eslint-plugin-n": "17.10.2",
55
+ "eslint-plugin-prettier": "5.2.1",
56
+ "get-stream": "6.0.1",
57
+ "jest": "29.7.0",
58
+ "nodemon": "3.1.4",
59
+ "np": "8.0.4",
60
+ "prettier": "3.3.3",
61
+ "rxjs": "7.8.1",
62
+ "xmltest": "2.0.1",
63
+ "yauzl": "3.1.3"
64
+ },
65
+ "bugs": {
66
+ "url": "https://github.com/xmldom/xmldom/issues"
67
+ },
68
+ "license": "MIT",
69
+ "auto-changelog": {
70
+ "prepend": true,
71
+ "remote": "origin",
72
+ "tagPrefix": "",
73
+ "template": "./auto-changelog.hbs"
74
+ }
72
75
  }