@depup/fast-xml-parser 5.5.11-depup.1 → 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/CHANGELOG.md +85 -0
- package/README.md +3 -3
- package/changes.json +4 -4
- package/lib/fxbuilder.min.js +1 -1
- package/lib/fxbuilder.min.js.map +1 -1
- package/lib/fxp.cjs +1 -1
- package/lib/fxp.d.cts +40 -11
- package/lib/fxp.min.js +1 -1
- package/lib/fxp.min.js.map +1 -1
- package/lib/fxparser.min.js +1 -1
- package/lib/fxparser.min.js.map +1 -1
- package/package.json +14 -14
- package/src/fxp.d.ts +52 -17
- package/src/xmlparser/DocTypeReader.js +32 -16
- package/src/xmlparser/OptionsBuilder.js +13 -8
- package/src/xmlparser/OrderedObjParser.js +82 -133
- package/src/xmlparser/XMLParser.js +2 -2
- package/src/xmlparser/node2json.js +4 -0
- package/src/xmlparser/xmlNode.js +14 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/fast-xml-parser",
|
|
3
|
-
"version": "5.
|
|
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",
|
|
@@ -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
|
-
"
|
|
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
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
94
|
+
"@nodable/entities": "^3.0.0",
|
|
95
|
+
"fast-xml-builder": "^1.3.1",
|
|
96
|
+
"is-unsafe": "^2.0.0",
|
|
97
|
+
"path-expression-matcher": "^1.6.2",
|
|
98
|
+
"strnum": "^2.4.2",
|
|
99
|
+
"xml-naming": "^0.3.0"
|
|
100
100
|
},
|
|
101
101
|
"depup": {
|
|
102
102
|
"changes": {
|
|
103
|
-
"
|
|
104
|
-
"from": "^1.
|
|
105
|
-
"to": "^1.
|
|
103
|
+
"fast-xml-builder": {
|
|
104
|
+
"from": "^1.2.0",
|
|
105
|
+
"to": "^1.3.1"
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"depsUpdated": 1,
|
|
109
109
|
"originalPackage": "fast-xml-parser",
|
|
110
|
-
"originalVersion": "5.
|
|
111
|
-
"processedAt": "2026-
|
|
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
|
@@ -66,20 +66,23 @@ export class Expression {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// ---------------------------------------------------------------------------
|
|
69
|
-
//
|
|
69
|
+
// MatcherView
|
|
70
70
|
// ---------------------------------------------------------------------------
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
* A live read-only view of a Matcher instance
|
|
73
|
+
* A lightweight, live read-only view of a Matcher instance.
|
|
74
74
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
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
|
|
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 →
|
|
145
|
-
type JPathOrMatcher = string |
|
|
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
|
-
|
|
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;
|
|
@@ -716,4 +749,6 @@ export class XMLBuilder {
|
|
|
716
749
|
export interface XMLMetaData {
|
|
717
750
|
/** The index, if available, of the character where the XML node began in the input stream. */
|
|
718
751
|
startIndex?: number;
|
|
752
|
+
/** The index, if available, of the character where the XML node ended in the input stream. */
|
|
753
|
+
endIndex?: number;
|
|
719
754
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { isName } from '
|
|
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;
|
|
@@ -19,8 +23,23 @@ export default class DocTypeReader {
|
|
|
19
23
|
i = i + 9;
|
|
20
24
|
let angleBracketsCount = 1;
|
|
21
25
|
let hasBody = false, comment = false;
|
|
26
|
+
let quoteChar = null; // tracks an open SYSTEM/PUBLIC literal before the '[' body
|
|
22
27
|
let exp = "";
|
|
23
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
|
+
|
|
24
43
|
if (xmlData[i] === '<' && !comment) { //Determine the tag type
|
|
25
44
|
if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
|
|
26
45
|
i += 7;
|
|
@@ -35,11 +54,8 @@ export default class DocTypeReader {
|
|
|
35
54
|
);
|
|
36
55
|
}
|
|
37
56
|
//const escaped = entityName.replace(/[.\-+*:]/g, '\\.');
|
|
38
|
-
const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
39
|
-
entities[entityName] =
|
|
40
|
-
regx: RegExp(`&${escaped};`, "g"),
|
|
41
|
-
val: val
|
|
42
|
-
};
|
|
57
|
+
//const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
58
|
+
entities[entityName] = val;
|
|
43
59
|
entityCount++;
|
|
44
60
|
}
|
|
45
61
|
}
|
|
@@ -78,7 +94,7 @@ export default class DocTypeReader {
|
|
|
78
94
|
exp += xmlData[i];
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
|
-
if (angleBracketsCount !== 0) {
|
|
97
|
+
if (quoteChar !== null || angleBracketsCount !== 0) {
|
|
82
98
|
throw new Error(`Unclosed DOCTYPE`);
|
|
83
99
|
}
|
|
84
100
|
} else {
|
|
@@ -106,7 +122,7 @@ export default class DocTypeReader {
|
|
|
106
122
|
}
|
|
107
123
|
let entityName = xmlData.substring(startIndex, i);
|
|
108
124
|
|
|
109
|
-
validateEntityName(entityName);
|
|
125
|
+
validateEntityName(entityName, { xmlVersion: this.xmlVersion });
|
|
110
126
|
|
|
111
127
|
// Skip whitespace after entity name
|
|
112
128
|
i = skipWhitespace(xmlData, i);
|
|
@@ -149,7 +165,7 @@ export default class DocTypeReader {
|
|
|
149
165
|
}
|
|
150
166
|
let notationName = xmlData.substring(startIndex, i);
|
|
151
167
|
|
|
152
|
-
!this.suppressValidationErr && validateEntityName(notationName);
|
|
168
|
+
!this.suppressValidationErr && validateEntityName(notationName, { xmlVersion: this.xmlVersion });
|
|
153
169
|
|
|
154
170
|
// Skip whitespace after notation name
|
|
155
171
|
i = skipWhitespace(xmlData, i);
|
|
@@ -229,7 +245,7 @@ export default class DocTypeReader {
|
|
|
229
245
|
let elementName = xmlData.substring(startIndex, i);
|
|
230
246
|
|
|
231
247
|
// Validate element name
|
|
232
|
-
if (!this.suppressValidationErr && !isName(elementName)) {
|
|
248
|
+
if (!this.suppressValidationErr && !isName(elementName, { xmlVersion: this.xmlVersion })) {
|
|
233
249
|
throw new Error(`Invalid element name: "${elementName}"`);
|
|
234
250
|
}
|
|
235
251
|
|
|
@@ -276,7 +292,7 @@ export default class DocTypeReader {
|
|
|
276
292
|
let elementName = xmlData.substring(startIndex, i);
|
|
277
293
|
|
|
278
294
|
// Validate element name
|
|
279
|
-
validateEntityName(elementName)
|
|
295
|
+
validateEntityName(elementName, { xmlVersion: this.xmlVersion })
|
|
280
296
|
|
|
281
297
|
// Skip whitespace after element name
|
|
282
298
|
i = skipWhitespace(xmlData, i);
|
|
@@ -289,7 +305,7 @@ export default class DocTypeReader {
|
|
|
289
305
|
let attributeName = xmlData.substring(startIndex, i);
|
|
290
306
|
|
|
291
307
|
// Validate attribute name
|
|
292
|
-
if (!validateEntityName(attributeName)) {
|
|
308
|
+
if (!validateEntityName(attributeName, { xmlVersion: this.xmlVersion })) {
|
|
293
309
|
throw new Error(`Invalid attribute name: "${attributeName}"`);
|
|
294
310
|
}
|
|
295
311
|
|
|
@@ -324,7 +340,7 @@ export default class DocTypeReader {
|
|
|
324
340
|
|
|
325
341
|
// Validate notation name
|
|
326
342
|
notation = notation.trim();
|
|
327
|
-
if (!validateEntityName(notation)) {
|
|
343
|
+
if (!validateEntityName(notation, { xmlVersion: this.xmlVersion })) {
|
|
328
344
|
throw new Error(`Invalid notation name: "${notation}"`);
|
|
329
345
|
}
|
|
330
346
|
|
|
@@ -402,8 +418,8 @@ function hasSeq(data, seq, i) {
|
|
|
402
418
|
return true;
|
|
403
419
|
}
|
|
404
420
|
|
|
405
|
-
function validateEntityName(name) {
|
|
406
|
-
if (isName(name))
|
|
421
|
+
function validateEntityName(name, xmlVersion) {
|
|
422
|
+
if (isName(name, { xmlVersion: xmlVersion }))
|
|
407
423
|
return name;
|
|
408
424
|
else
|
|
409
425
|
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:
|
|
95
|
-
maxTotalExpansions:
|
|
97
|
+
maxExpansionDepth: 10000,
|
|
98
|
+
maxTotalExpansions: Infinity,
|
|
96
99
|
maxExpandedLength: 100000,
|
|
97
|
-
maxEntityCount:
|
|
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)) {
|