@depup/fast-xml-parser 5.5.11-depup.1 → 5.10.1-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.5.11-depup.1",
3
+ "version": "5.10.1-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",
@@ -23,13 +23,11 @@
23
23
  "test": "c8 --reporter=lcov --reporter=text jasmine spec/*spec.js",
24
24
  "test-types": "tsc --noEmit spec/typings/typings-test.ts",
25
25
  "unit": "jasmine",
26
- "coverage": "nyc report --reporter html --reporter text -t .nyc_output --report-dir .nyc_output/summary",
27
26
  "perf": "node ./benchmark/perfTest3.js",
28
27
  "lint": "eslint src/**/*.js spec/**/*.js benchmark/**/*.js",
29
28
  "bundle": "webpack --config webpack.cjs.config.js",
30
29
  "prettier": "prettier --write src/**/*.js",
31
- "checkReadiness": "publish-please --dry-run",
32
- "publish-please": "publish-please"
30
+ "preversion": "npm test"
33
31
  },
34
32
  "bin": {
35
33
  "fxparser": "src/cli/cli.js"
@@ -75,14 +73,13 @@
75
73
  "@babel/plugin-transform-runtime": "^7.13.10",
76
74
  "@babel/preset-env": "^7.13.10",
77
75
  "@babel/register": "^7.13.8",
76
+ "@byspec/xml": "^0.1.0",
78
77
  "@types/node": "20",
79
78
  "babel-loader": "^8.2.2",
80
79
  "c8": "^10.1.3",
81
80
  "eslint": "^8.3.0",
82
- "he": "^1.2.0",
83
81
  "jasmine": "^5.6.0",
84
82
  "prettier": "^3.5.1",
85
- "publish-please": "^5.5.2",
86
83
  "typescript": "5",
87
84
  "webpack": "^5.64.4",
88
85
  "webpack-cli": "^4.9.1"
@@ -94,21 +91,24 @@
94
91
  }
95
92
  ],
96
93
  "dependencies": {
97
- "fast-xml-builder": "^1.1.4",
98
- "path-expression-matcher": "^1.5.0",
99
- "strnum": "^2.2.3"
94
+ "@nodable/entities": "^3.0.0",
95
+ "fast-xml-builder": "^1.3.0",
96
+ "is-unsafe": "^2.0.0",
97
+ "path-expression-matcher": "^1.6.2",
98
+ "strnum": "^2.4.1",
99
+ "xml-naming": "^0.3.0"
100
100
  },
101
101
  "depup": {
102
102
  "changes": {
103
- "path-expression-matcher": {
104
- "from": "^1.4.0",
105
- "to": "^1.5.0"
103
+ "fast-xml-builder": {
104
+ "from": "^1.2.0",
105
+ "to": "^1.3.0"
106
106
  }
107
107
  },
108
108
  "depsUpdated": 1,
109
109
  "originalPackage": "fast-xml-parser",
110
- "originalVersion": "5.5.11",
111
- "processedAt": "2026-04-10T05:04:43.827Z",
110
+ "originalVersion": "5.10.1",
111
+ "processedAt": "2026-07-21T16:14:33.562Z",
112
112
  "smokeTest": "passed"
113
113
  }
114
114
  }
package/src/fxp.d.ts CHANGED
@@ -66,20 +66,23 @@ export class Expression {
66
66
  }
67
67
 
68
68
  // ---------------------------------------------------------------------------
69
- // ReadonlyMatcher
69
+ // MatcherView
70
70
  // ---------------------------------------------------------------------------
71
71
 
72
72
  /**
73
- * A live read-only view of a Matcher instance, returned by Matcher.readOnly.
73
+ * A lightweight, live read-only view of a Matcher instance.
74
74
  *
75
- * All query and inspection methods work normally and always reflect the current
76
- * state of the underlying matcher. State-mutating methods (`push`, `pop`,
77
- * `reset`, `updateCurrent`, `restore`) are not present calling them on the
78
- * underlying Proxy throws a `TypeError` at runtime.
75
+ * Returned by `Matcher.readOnly()`. The same instance is reused across every
76
+ * callback invocation no allocation overhead per call. Reads directly from
77
+ * the parent Matcher's internal state so it always reflects the current parser
78
+ * position with no copying or freezing.
79
+ *
80
+ * Mutation methods (`push`, `pop`, `reset`, `updateCurrent`, `restore`) are
81
+ * simply absent — misuse is caught at compile time by TypeScript.
79
82
  *
80
83
  * This is the type received by all FXP user callbacks when `jPath: false`.
81
84
  */
82
- export interface ReadonlyMatcher {
85
+ export class MatcherView {
83
86
  readonly separator: string;
84
87
 
85
88
  /** Check if current path matches an Expression. */
@@ -111,14 +114,14 @@ export interface ReadonlyMatcher {
111
114
 
112
115
  /** Current path as an array of tag names. */
113
116
  toArray(): string[];
114
-
115
- /**
116
- * Create a snapshot of the current state.
117
- * The snapshot can be passed to the real Matcher.restore if needed.
118
- */
119
- snapshot(): MatcherSnapshot;
120
117
  }
121
118
 
119
+ /**
120
+ * @deprecated Use {@link MatcherView} instead.
121
+ * Alias kept for backward compatibility.
122
+ */
123
+ export type ReadonlyMatcher = MatcherView;
124
+
122
125
  /** Internal node structure — exposed via snapshot only. */
123
126
  export interface PathNode {
124
127
  tag: string;
@@ -141,8 +144,8 @@ export interface MatcherSnapshot {
141
144
  **********************************************************************/
142
145
 
143
146
  // jPath: true → string
144
- // jPath: false → ReadonlyMatcher
145
- type JPathOrMatcher = string | ReadonlyMatcher;
147
+ // jPath: false → MatcherView
148
+ type JPathOrMatcher = string | MatcherView;
146
149
  type JPathOrExpression = string | Expression;
147
150
 
148
151
  export type ProcessEntitiesOptions = {
@@ -208,6 +211,14 @@ export type ProcessEntitiesOptions = {
208
211
  tagFilter?: ((tagName: string, jPathOrMatcher: JPathOrMatcher) => boolean) | null;
209
212
  };
210
213
 
214
+ export type EntityDecoderOptions = {
215
+ setExternalEntities: (entities: Record<string, string>) => void;
216
+ addInputEntities: (entities: Record<string, string>) => void;
217
+ reset: () => void;
218
+ decode: (text: string) => string;
219
+ setXmlVersion: (version: string) => void;
220
+ }
221
+
211
222
  export type X2jOptions = {
212
223
  /**
213
224
  * Preserve the order of tags in resulting JS object
@@ -394,9 +405,14 @@ export type X2jOptions = {
394
405
  * Whether to process HTML entities
395
406
  *
396
407
  * Defaults to `false`
408
+ * @deprecated Use `entityDecoder` instead
397
409
  */
398
410
  htmlEntities?: boolean;
399
411
 
412
+ /**
413
+ * Custom entity decoder
414
+ */
415
+ entityDecoder?: EntityDecoderOptions;
400
416
  /**
401
417
  * Whether to ignore the declaration tag from output
402
418
  *
@@ -487,7 +503,9 @@ export type strnumOptions = {
487
503
  hex: boolean;
488
504
  leadingZeros: boolean,
489
505
  skipLike?: RegExp,
490
- eNotation?: boolean
506
+ eNotation?: boolean,
507
+ infinity?: string,
508
+ unicode?: boolean
491
509
  }
492
510
 
493
511
  export type validationOptions = {
@@ -680,11 +698,19 @@ export type ValidationError = {
680
698
 
681
699
  export class XMLParser {
682
700
  constructor(options?: X2jOptions);
683
- parse(xmlData: string | Uint8Array, validationOptions?: validationOptions | boolean): any;
701
+
702
+ parse(xmlData: string | Uint8Array): any;
703
+ /**
704
+ * @deprecated The `validationOptions` parameter is deprecated.
705
+ * Use the `fast-xml-validator` package instead for XML validation.
706
+ * @see https://www.npmjs.com/package/fast-xml-validator
707
+ */
708
+ parse(xmlData: string | Uint8Array, validationOptions: validationOptions | boolean): any;
684
709
  /**
685
710
  * Add Entity which is not by default supported by this library
686
711
  * @param entityIdentifier {string} Eg: 'ent' for &ent;
687
712
  * @param entityValue {string} Eg: '\r'
713
+ * @deprecated Use `entityDecoder` instead
688
714
  */
689
715
  addEntity(entityIdentifier: string, entityValue: string): void;
690
716
 
@@ -701,9 +727,16 @@ export class XMLParser {
701
727
  static getMetaDataSymbol(): Symbol;
702
728
  }
703
729
 
730
+ /**
731
+ * @deprecated Use fast-xml-validator instead
732
+ * @see https://www.npmjs.com/package/fast-xml-validator
733
+ */
704
734
  export class XMLValidator {
705
735
  static validate(xmlData: string, options?: validationOptions): true | ValidationError;
706
736
  }
737
+ /**
738
+ * @deprecated Use npm package 'fast-xml-builder' instead
739
+ */
707
740
  export class XMLBuilder {
708
741
  constructor(options?: XmlBuilderOptions);
709
742
  build(jObj: any): string;
@@ -1,11 +1,15 @@
1
- import { isName } from '../util.js';
1
+ import { qName as isName } from 'xml-naming';
2
2
 
3
3
  export default class DocTypeReader {
4
- constructor(options) {
4
+ constructor(options, xmlVersion) {
5
5
  this.suppressValidationErr = !options;
6
6
  this.options = options;
7
+ this.xmlVersion = xmlVersion || 1.0;
7
8
  }
8
9
 
10
+ setXmlVersion(xmlVersion = 1.0) {
11
+ this.xmlVersion = xmlVersion;
12
+ }
9
13
  readDocType(xmlData, i) {
10
14
  const entities = Object.create(null);
11
15
  let entityCount = 0;
@@ -35,11 +39,8 @@ export default class DocTypeReader {
35
39
  );
36
40
  }
37
41
  //const escaped = entityName.replace(/[.\-+*:]/g, '\\.');
38
- const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
39
- entities[entityName] = {
40
- regx: RegExp(`&${escaped};`, "g"),
41
- val: val
42
- };
42
+ //const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
43
+ entities[entityName] = val;
43
44
  entityCount++;
44
45
  }
45
46
  }
@@ -106,7 +107,7 @@ export default class DocTypeReader {
106
107
  }
107
108
  let entityName = xmlData.substring(startIndex, i);
108
109
 
109
- validateEntityName(entityName);
110
+ validateEntityName(entityName, { xmlVersion: this.xmlVersion });
110
111
 
111
112
  // Skip whitespace after entity name
112
113
  i = skipWhitespace(xmlData, i);
@@ -149,7 +150,7 @@ export default class DocTypeReader {
149
150
  }
150
151
  let notationName = xmlData.substring(startIndex, i);
151
152
 
152
- !this.suppressValidationErr && validateEntityName(notationName);
153
+ !this.suppressValidationErr && validateEntityName(notationName, { xmlVersion: this.xmlVersion });
153
154
 
154
155
  // Skip whitespace after notation name
155
156
  i = skipWhitespace(xmlData, i);
@@ -229,7 +230,7 @@ export default class DocTypeReader {
229
230
  let elementName = xmlData.substring(startIndex, i);
230
231
 
231
232
  // Validate element name
232
- if (!this.suppressValidationErr && !isName(elementName)) {
233
+ if (!this.suppressValidationErr && !isName(elementName, { xmlVersion: this.xmlVersion })) {
233
234
  throw new Error(`Invalid element name: "${elementName}"`);
234
235
  }
235
236
 
@@ -276,7 +277,7 @@ export default class DocTypeReader {
276
277
  let elementName = xmlData.substring(startIndex, i);
277
278
 
278
279
  // Validate element name
279
- validateEntityName(elementName)
280
+ validateEntityName(elementName, { xmlVersion: this.xmlVersion })
280
281
 
281
282
  // Skip whitespace after element name
282
283
  i = skipWhitespace(xmlData, i);
@@ -289,7 +290,7 @@ export default class DocTypeReader {
289
290
  let attributeName = xmlData.substring(startIndex, i);
290
291
 
291
292
  // Validate attribute name
292
- if (!validateEntityName(attributeName)) {
293
+ if (!validateEntityName(attributeName, { xmlVersion: this.xmlVersion })) {
293
294
  throw new Error(`Invalid attribute name: "${attributeName}"`);
294
295
  }
295
296
 
@@ -324,7 +325,7 @@ export default class DocTypeReader {
324
325
 
325
326
  // Validate notation name
326
327
  notation = notation.trim();
327
- if (!validateEntityName(notation)) {
328
+ if (!validateEntityName(notation, { xmlVersion: this.xmlVersion })) {
328
329
  throw new Error(`Invalid notation name: "${notation}"`);
329
330
  }
330
331
 
@@ -402,8 +403,8 @@ function hasSeq(data, seq, i) {
402
403
  return true;
403
404
  }
404
405
 
405
- function validateEntityName(name) {
406
- if (isName(name))
406
+ function validateEntityName(name, xmlVersion) {
407
+ if (isName(name, { xmlVersion: xmlVersion }))
407
408
  return name;
408
409
  else
409
410
  throw new Error(`Invalid entity name ${name}`);
@@ -1,4 +1,5 @@
1
1
  import { DANGEROUS_PROPERTY_NAMES, criticalProperties } from "../util.js";
2
+ import { COMMON_HTML, CURRENCY } from '@nodable/entities';
2
3
 
3
4
  const defaultOnDangerousProperty = (name) => {
4
5
  if (DANGEROUS_PROPERTY_NAMES.includes(name)) {
@@ -24,7 +25,8 @@ export const defaultOptions = {
24
25
  numberParseOptions: {
25
26
  hex: true,
26
27
  leadingZeros: true,
27
- eNotation: true
28
+ eNotation: true,
29
+ unicode: false
28
30
  },
29
31
  tagValueProcessor: function (tagName, val) {
30
32
  return val;
@@ -39,6 +41,7 @@ export const defaultOptions = {
39
41
  unpairedTags: [],
40
42
  processEntities: true,
41
43
  htmlEntities: false,
44
+ entityDecoder: null,
42
45
  ignoreDeclaration: false,
43
46
  ignorePiTags: false,
44
47
  transformTagName: false,
@@ -85,18 +88,19 @@ function validatePropertyName(propertyName, optionName) {
85
88
  * @param {boolean|object} value
86
89
  * @returns {object} Always returns normalized object
87
90
  */
88
- function normalizeProcessEntities(value) {
91
+ function normalizeProcessEntities(value, htmlEntities) {
89
92
  // Boolean backward compatibility
90
93
  if (typeof value === 'boolean') {
91
94
  return {
92
95
  enabled: value, // true or false
93
96
  maxEntitySize: 10000,
94
- maxExpansionDepth: 10,
95
- maxTotalExpansions: 1000,
97
+ maxExpansionDepth: 10000,
98
+ maxTotalExpansions: Infinity,
96
99
  maxExpandedLength: 100000,
97
- maxEntityCount: 100,
100
+ maxEntityCount: 1000,
98
101
  allowedTags: null,
99
- tagFilter: null
102
+ tagFilter: null,
103
+ appliesTo: "all",
100
104
  };
101
105
  }
102
106
 
@@ -110,7 +114,8 @@ function normalizeProcessEntities(value) {
110
114
  maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 100000),
111
115
  maxEntityCount: Math.max(1, value.maxEntityCount ?? 1000),
112
116
  allowedTags: value.allowedTags ?? null,
113
- tagFilter: value.tagFilter ?? null
117
+ tagFilter: value.tagFilter ?? null,
118
+ appliesTo: value.appliesTo ?? "all",
114
119
  };
115
120
  }
116
121
 
@@ -141,7 +146,7 @@ export const buildOptions = function (options) {
141
146
  }
142
147
 
143
148
  // Always normalize processEntities for backward compatibility and validation
144
- built.processEntities = normalizeProcessEntities(built.processEntities);
149
+ built.processEntities = normalizeProcessEntities(built.processEntities, built.htmlEntities);
145
150
  built.unpairedTagsSet = new Set(built.unpairedTags);
146
151
  // Convert old-style stopNodes for backward compatibility
147
152
  if (built.stopNodes && Array.isArray(built.stopNodes)) {