@depup/fast-xml-parser 5.10.1-depup.0 → 5.11.0-depup.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/fast-xml-parser",
3
- "version": "5.10.1-depup.0",
3
+ "version": "5.11.0-depup.0",
4
4
  "description": "Validate XML, Parse XML, Build XML without C/C++ based libraries (with updated dependencies)",
5
5
  "main": "./lib/fxp.cjs",
6
6
  "type": "module",
@@ -92,23 +92,23 @@
92
92
  ],
93
93
  "dependencies": {
94
94
  "@nodable/entities": "^3.0.0",
95
- "fast-xml-builder": "^1.3.0",
95
+ "fast-xml-builder": "^1.3.1",
96
96
  "is-unsafe": "^2.0.0",
97
97
  "path-expression-matcher": "^1.6.2",
98
- "strnum": "^2.4.1",
98
+ "strnum": "^2.4.2",
99
99
  "xml-naming": "^0.3.0"
100
100
  },
101
101
  "depup": {
102
102
  "changes": {
103
103
  "fast-xml-builder": {
104
104
  "from": "^1.2.0",
105
- "to": "^1.3.0"
105
+ "to": "^1.3.1"
106
106
  }
107
107
  },
108
108
  "depsUpdated": 1,
109
109
  "originalPackage": "fast-xml-parser",
110
- "originalVersion": "5.10.1",
111
- "processedAt": "2026-07-21T16:14:33.562Z",
110
+ "originalVersion": "5.11.0",
111
+ "processedAt": "2026-08-16T08:07:19.703Z",
112
112
  "smokeTest": "passed"
113
113
  }
114
114
  }
package/src/fxp.d.ts CHANGED
@@ -749,4 +749,6 @@ export class XMLBuilder {
749
749
  export interface XMLMetaData {
750
750
  /** The index, if available, of the character where the XML node began in the input stream. */
751
751
  startIndex?: number;
752
+ /** The index, if available, of the character where the XML node ended in the input stream. */
753
+ endIndex?: number;
752
754
  }
@@ -23,8 +23,23 @@ export default class DocTypeReader {
23
23
  i = i + 9;
24
24
  let angleBracketsCount = 1;
25
25
  let hasBody = false, comment = false;
26
+ let quoteChar = null; // tracks an open SYSTEM/PUBLIC literal before the '[' body
26
27
  let exp = "";
27
28
  for (; i < xmlData.length; i++) {
29
+ // Inside a quoted external-identifier literal — XML allows '<'
30
+ // and '>' as plain data here, so they must not be interpreted
31
+ // as DOCTYPE structure until the matching quote closes.
32
+ if (quoteChar !== null) {
33
+ if (xmlData[i] === quoteChar) quoteChar = null;
34
+ exp += xmlData[i];
35
+ continue;
36
+ }
37
+ if (!hasBody && !comment && (xmlData[i] === '"' || xmlData[i] === "'")) {
38
+ quoteChar = xmlData[i];
39
+ exp += xmlData[i];
40
+ continue;
41
+ }
42
+
28
43
  if (xmlData[i] === '<' && !comment) { //Determine the tag type
29
44
  if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
30
45
  i += 7;
@@ -79,7 +94,7 @@ export default class DocTypeReader {
79
94
  exp += xmlData[i];
80
95
  }
81
96
  }
82
- if (angleBracketsCount !== 0) {
97
+ if (quoteChar !== null || angleBracketsCount !== 0) {
83
98
  throw new Error(`Unclosed DOCTYPE`);
84
99
  }
85
100
  } else {
@@ -336,7 +336,12 @@ const parseXml = function (xmlData) {
336
336
  this.matcher.pop();
337
337
  this.isCurrentNodeStopNode = false; // Reset flag when closing tag
338
338
 
339
- currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope
339
+ //a closing tag with no matching opening tag leaves the stack empty
340
+ currentNode = this.tagsNodeStack.pop() || xmlObj;//avoid recursion, set the parent tag scope
341
+
342
+ if (options.captureMetaData && currentNode) {
343
+ currentNode.addEndIndex(closeIndex + 1);
344
+ }
340
345
  textData = "";
341
346
  i = closeIndex;
342
347
  } else if (c1 === 63) { //'?'
@@ -362,6 +367,11 @@ const parseXml = function (xmlData) {
362
367
  childNode[":@"] = attsMap
363
368
  }
364
369
  this.addChild(currentNode, childNode, this.readonlyMatcher, i);
370
+
371
+ if (options.captureMetaData) {
372
+ // closeIndex points at '?' of the closing '?>'
373
+ currentNode.addEndIndex(tagData.closeIndex + 2);
374
+ }
365
375
  }
366
376
 
367
377
 
@@ -526,6 +536,10 @@ const parseXml = function (xmlData) {
526
536
  this.isCurrentNodeStopNode = false; // Reset flag
527
537
 
528
538
  this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
539
+
540
+ if (options.captureMetaData) {
541
+ currentNode.addEndIndex(i + 1);
542
+ }
529
543
  } else {
530
544
  //selfClosing tag
531
545
  if (isSelfClosing) {
@@ -536,6 +550,10 @@ const parseXml = function (xmlData) {
536
550
  childNode[":@"] = prefixedAttrs;
537
551
  }
538
552
  this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
553
+
554
+ if (options.captureMetaData) {
555
+ currentNode.addEndIndex(closeIndex + 1);
556
+ }
539
557
  this.matcher.pop(); // Pop self-closing tag
540
558
  this.isCurrentNodeStopNode = false; // Reset flag
541
559
  }
@@ -545,6 +563,10 @@ const parseXml = function (xmlData) {
545
563
  childNode[":@"] = prefixedAttrs;
546
564
  }
547
565
  this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
566
+
567
+ if (options.captureMetaData) {
568
+ currentNode.addEndIndex(result.closeIndex + 1);
569
+ }
548
570
  this.matcher.pop(); // Pop unpaired tag
549
571
  this.isCurrentNodeStopNode = false; // Reset flag
550
572
  i = result.closeIndex;
@@ -27,12 +27,26 @@ export default class XmlNode {
27
27
  this.child.push({ [node.tagname]: node.child });
28
28
  }
29
29
  // if requested, add the startIndex
30
+ this.addStartIndex(startIndex);
31
+ }
32
+
33
+ addStartIndex(startIndex) {
30
34
  if (startIndex !== undefined) {
31
35
  // Note: for now we just overwrite the metadata. If we had more complex metadata,
32
36
  // we might need to do an object append here: metadata = { ...metadata, startIndex }
33
37
  this.child[this.child.length - 1][METADATA_SYMBOL] = { startIndex };
34
38
  }
35
39
  }
40
+
41
+ addEndIndex(endIndex) {
42
+ const lastChild = this.child[this.child.length - 1];
43
+ // endIndex is write-once: when updateTag drops a node, the last child is a
44
+ // previously completed sibling whose endIndex must not be overwritten
45
+ if (lastChild !== undefined && lastChild[METADATA_SYMBOL] !== undefined
46
+ && lastChild[METADATA_SYMBOL].endIndex === undefined) {
47
+ lastChild[METADATA_SYMBOL].endIndex = endIndex;
48
+ }
49
+ }
36
50
  /** symbol used for metadata */
37
51
  static getMetaDataSymbol() {
38
52
  return METADATA_SYMBOL;