@btc-embedded/cdk-extensions 0.23.4 → 0.23.5
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/.jsii +5 -5
- package/CHANGELOG.md +7 -0
- package/assets/cli/catnip.js +154 -166
- package/lib/constructs/EventPipe.js +1 -1
- package/lib/constructs/ExportedService.js +1 -1
- package/lib/constructs/S3Bucket.js +1 -1
- package/lib/constructs/SecureRestApi.js +1 -1
- package/lib/constructs/SecureRestApiV2.js +1 -1
- package/lib/constructs/api-keys/ApiKeyClientAuthorization.js +1 -1
- package/lib/constructs/api-keys/ApiKeyManagement.js +1 -1
- package/lib/constructs/api-keys/ApiKeyPreTokenHandler.js +1 -1
- package/lib/constructs/api-keys/ApiKeyStore.js +1 -1
- package/lib/extensions/ApiGatewayExtension.js +1 -1
- package/lib/extensions/ApplicationContainer.js +1 -1
- package/lib/extensions/ApplicationLoadBalancerExtension.js +1 -1
- package/lib/extensions/ApplicationLoadBalancerExtensionV2.js +1 -1
- package/lib/extensions/CloudMapExtension.js +1 -1
- package/lib/extensions/DeactivatableServiceExtension.js +1 -1
- package/lib/extensions/DeploymentConfigExtension.js +1 -1
- package/lib/extensions/DocumentDbAccessExtension.js +1 -1
- package/lib/extensions/DomainEventMessagingExtension.js +1 -1
- package/lib/extensions/EfsMountExtension.js +1 -1
- package/lib/extensions/ExtraContainerExtension.js +1 -1
- package/lib/extensions/HTTPApiExtension.js +1 -1
- package/lib/extensions/LogExtension.js +1 -1
- package/lib/extensions/ModifyContainerDefinitionExtension.js +1 -1
- package/lib/extensions/ModifyTaskDefinitionExtension.js +1 -1
- package/lib/extensions/OpenIdExtension.js +1 -1
- package/lib/extensions/OpenTelemetryExtension.js +1 -1
- package/lib/extensions/PostgresDbAccessExtension.js +1 -1
- package/lib/extensions/SharedVolumeExtension.js +1 -1
- package/lib/extensions/TcpKeepAliveExtension.js +1 -1
- package/lib/platform/ApiGateway.js +1 -1
- package/lib/platform/ApiGatewayVpcLink.js +2 -2
- package/lib/platform/ApplicationLoadBalancer.js +1 -1
- package/lib/platform/ApplicationLoadBalancerV2.d.ts +1 -0
- package/lib/platform/ApplicationLoadBalancerV2.js +10 -3
- package/lib/platform/AuroraPostgresDB.js +2 -2
- package/lib/platform/BTCLogGroup.js +1 -1
- package/lib/platform/CognitoUserPool.js +2 -2
- package/lib/platform/DefaultUserPoolClients.js +1 -1
- package/lib/platform/DocumentDB.js +2 -2
- package/lib/platform/EcsCluster.js +1 -1
- package/lib/platform/EfsFileSystem.js +1 -1
- package/lib/platform/HostedZone.js +1 -1
- package/lib/platform/PrivateDnsNamespace.js +1 -1
- package/lib/platform/ResourceServer.js +1 -1
- package/lib/platform/Vpc.js +1 -1
- package/lib/platform/VpcV2.js +1 -1
- package/lib/stacks/ApplicationStack.js +1 -1
- package/lib/utils/BasePlatformStackResolver.js +1 -1
- package/lib/utils/StackParameter.js +1 -1
- package/node_modules/@nodable/entities/README.md +41 -0
- package/node_modules/@nodable/entities/package.json +54 -0
- package/node_modules/@nodable/entities/src/EntityDecoder.js +543 -0
- package/node_modules/@nodable/entities/src/EntityEncoder.js +194 -0
- package/node_modules/@nodable/entities/src/entities.js +1177 -0
- package/node_modules/@nodable/entities/src/entityTries.js +49 -0
- package/node_modules/@nodable/entities/src/index.d.ts +264 -0
- package/node_modules/@nodable/entities/src/index.js +29 -0
- package/node_modules/fast-xml-builder/CHANGELOG.md +40 -0
- package/node_modules/fast-xml-builder/LICENSE +21 -0
- package/node_modules/fast-xml-builder/README.md +74 -0
- package/node_modules/fast-xml-builder/lib/fxb.cjs +1 -0
- package/node_modules/fast-xml-builder/lib/fxb.d.cts +270 -0
- package/node_modules/fast-xml-builder/lib/fxb.min.js +2 -0
- package/node_modules/fast-xml-builder/lib/fxb.min.js.map +1 -0
- package/node_modules/fast-xml-builder/package.json +81 -0
- package/node_modules/fast-xml-builder/src/fxb.d.ts +270 -0
- package/node_modules/fast-xml-builder/src/fxb.js +599 -0
- package/node_modules/fast-xml-builder/src/ignoreAttributes.js +18 -0
- package/node_modules/fast-xml-builder/src/orderedJs2Xml.js +359 -0
- package/node_modules/fast-xml-builder/src/util.js +16 -0
- package/node_modules/fast-xml-parser/CHANGELOG.md +165 -0
- package/node_modules/fast-xml-parser/README.md +21 -44
- package/node_modules/fast-xml-parser/lib/fxbuilder.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxbuilder.min.js.map +1 -1
- package/node_modules/fast-xml-parser/lib/fxp.cjs +1 -1
- package/node_modules/fast-xml-parser/lib/fxp.d.cts +343 -31
- package/node_modules/fast-xml-parser/lib/fxp.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxp.min.js.map +1 -1
- package/node_modules/fast-xml-parser/lib/fxparser.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxparser.min.js.map +1 -1
- package/node_modules/fast-xml-parser/lib/fxvalidator.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxvalidator.min.js.map +1 -1
- package/node_modules/fast-xml-parser/package.json +13 -8
- package/node_modules/fast-xml-parser/src/fxp.d.ts +335 -30
- package/node_modules/fast-xml-parser/src/fxp.js +1 -1
- package/node_modules/fast-xml-parser/src/util.js +18 -25
- package/node_modules/fast-xml-parser/src/v6/EntitiesParser.js +89 -87
- package/node_modules/fast-xml-parser/src/v6/OptionsBuilder.js +10 -10
- package/node_modules/fast-xml-parser/src/v6/OutputBuilders/BaseOutputBuilder.js +23 -23
- package/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsArrBuilder.js +29 -29
- package/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsMinArrBuilder.js +1 -1
- package/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsObjBuilder.js +39 -39
- package/node_modules/fast-xml-parser/src/v6/OutputBuilders/ParserOptionsBuilder.js +21 -21
- package/node_modules/fast-xml-parser/src/v6/XMLParser.js +22 -22
- package/node_modules/fast-xml-parser/src/v6/valueParsers/EntitiesParser.js +85 -85
- package/node_modules/fast-xml-parser/src/validator.js +34 -34
- package/node_modules/fast-xml-parser/src/xmlbuilder/json2xml.js +5 -284
- package/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js +335 -293
- package/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js +160 -43
- package/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js +540 -308
- package/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js +26 -26
- package/node_modules/fast-xml-parser/src/xmlparser/node2json.js +99 -41
- package/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js +10 -10
- package/node_modules/path-expression-matcher/LICENSE +21 -0
- package/node_modules/path-expression-matcher/README.md +872 -0
- package/node_modules/path-expression-matcher/lib/pem.cjs +1 -0
- package/node_modules/path-expression-matcher/lib/pem.d.cts +634 -0
- package/node_modules/path-expression-matcher/lib/pem.min.js +2 -0
- package/node_modules/path-expression-matcher/lib/pem.min.js.map +1 -0
- package/node_modules/path-expression-matcher/package.json +78 -0
- package/node_modules/path-expression-matcher/src/Expression.js +232 -0
- package/node_modules/path-expression-matcher/src/ExpressionSet.js +209 -0
- package/node_modules/path-expression-matcher/src/Matcher.js +570 -0
- package/node_modules/path-expression-matcher/src/index.d.ts +523 -0
- package/node_modules/path-expression-matcher/src/index.js +29 -0
- package/node_modules/strnum/CHANGELOG.md +12 -2
- package/node_modules/strnum/README.md +1 -0
- package/node_modules/strnum/package.json +5 -4
- package/node_modules/strnum/strnum.js +99 -65
- package/node_modules/xml-naming/README.md +189 -0
- package/node_modules/xml-naming/package.json +54 -0
- package/node_modules/xml-naming/src/index.d.ts +74 -0
- package/node_modules/xml-naming/src/index.js +270 -0
- package/package.json +3 -2
- package/renovate.json5 +1 -0
- package/node_modules/fast-xml-parser/src/xmlbuilder/orderedJs2Xml.js +0 -134
- package/node_modules/strnum/.github/SECURITY.md +0 -5
- package/node_modules/strnum/.vscode/launch.json +0 -25
- package/node_modules/strnum/algo.stflow +0 -84
- package/node_modules/strnum/strnum.test.js +0 -173
- package/node_modules/strnum/test.js +0 -9
- /package/node_modules/{fast-xml-parser/src/xmlbuilder → fast-xml-builder/src}/prettifyJs2Xml.js +0 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { Expression, Matcher } from 'path-expression-matcher';
|
|
2
|
+
import { safeComment, safeCdata, escapeAttribute } from "./util.js";
|
|
3
|
+
import { qName } from 'xml-naming';
|
|
4
|
+
|
|
5
|
+
const EOL = "\n";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Detect XML version from the first element of the ordered array input.
|
|
9
|
+
* The first element must be a ?xml processing instruction with a version attribute.
|
|
10
|
+
* Returns '1.0' if not found.
|
|
11
|
+
*
|
|
12
|
+
* @param {array} jArray
|
|
13
|
+
* @param {object} options
|
|
14
|
+
*/
|
|
15
|
+
function detectXmlVersionFromArray(jArray, options) {
|
|
16
|
+
if (!Array.isArray(jArray) || jArray.length === 0) return '1.0';
|
|
17
|
+
const first = jArray[0];
|
|
18
|
+
const firstKey = propName(first);
|
|
19
|
+
if (firstKey === '?xml') {
|
|
20
|
+
const attrs = first[':@'];
|
|
21
|
+
if (attrs) {
|
|
22
|
+
const versionKey = options.attributeNamePrefix + 'version';
|
|
23
|
+
if (attrs[versionKey]) return attrs[versionKey];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return '1.0';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a tag or attribute name through sanitizeName if configured.
|
|
31
|
+
* Validation via xml-naming's qName is performed first; the sanitizeName
|
|
32
|
+
* callback is invoked only when the name is invalid. If sanitizeName is
|
|
33
|
+
* false (default), no validation occurs and the name is used as-is.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} name - raw name from the JS object
|
|
36
|
+
* @param {boolean} isAttribute - true when resolving an attribute name
|
|
37
|
+
* @param {object} options
|
|
38
|
+
* @param {Matcher} matcher - current matcher state (readonly from callback perspective)
|
|
39
|
+
* @param {string} xmlVersion - '1.0' or '1.1', forwarded to xml-naming
|
|
40
|
+
*/
|
|
41
|
+
function resolveTagName(name, isAttribute, options, matcher, xmlVersion) {
|
|
42
|
+
if (!options.sanitizeName) return name;
|
|
43
|
+
if (qName(name, { xmlVersion })) return name;
|
|
44
|
+
return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {array} jArray
|
|
49
|
+
* @param {any} options
|
|
50
|
+
* @returns
|
|
51
|
+
*/
|
|
52
|
+
export default function toXml(jArray, options) {
|
|
53
|
+
let indentation = "";
|
|
54
|
+
if (options.format) {
|
|
55
|
+
indentation = EOL;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Pre-compile stopNode expressions for pattern matching
|
|
59
|
+
const stopNodeExpressions = [];
|
|
60
|
+
if (options.stopNodes && Array.isArray(options.stopNodes)) {
|
|
61
|
+
for (let i = 0; i < options.stopNodes.length; i++) {
|
|
62
|
+
const node = options.stopNodes[i];
|
|
63
|
+
if (typeof node === 'string') {
|
|
64
|
+
stopNodeExpressions.push(new Expression(node));
|
|
65
|
+
} else if (node instanceof Expression) {
|
|
66
|
+
stopNodeExpressions.push(node);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Detect XML version for use in name validation
|
|
72
|
+
const xmlVersion = detectXmlVersionFromArray(jArray, options);
|
|
73
|
+
|
|
74
|
+
// Initialize matcher for path tracking
|
|
75
|
+
const matcher = new Matcher();
|
|
76
|
+
|
|
77
|
+
return arrToStr(jArray, options, indentation, matcher, stopNodeExpressions, xmlVersion);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function arrToStr(arr, options, indentation, matcher, stopNodeExpressions, xmlVersion) {
|
|
81
|
+
let xmlStr = "";
|
|
82
|
+
let isPreviousElementTag = false;
|
|
83
|
+
|
|
84
|
+
if (options.maxNestedTags && matcher.getDepth() > options.maxNestedTags) {
|
|
85
|
+
throw new Error("Maximum nested tags exceeded");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!Array.isArray(arr)) {
|
|
89
|
+
// Non-array values (e.g. string tag values) should be treated as text content
|
|
90
|
+
if (arr !== undefined && arr !== null) {
|
|
91
|
+
let text = arr.toString();
|
|
92
|
+
text = replaceEntitiesValue(text, options);
|
|
93
|
+
return text;
|
|
94
|
+
}
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < arr.length; i++) {
|
|
99
|
+
const tagObj = arr[i];
|
|
100
|
+
const rawTagName = propName(tagObj);
|
|
101
|
+
if (rawTagName === undefined) continue;
|
|
102
|
+
|
|
103
|
+
// Special names are exempt from sanitizeName: internal conventions and PI tags
|
|
104
|
+
// are not user-supplied XML element names.
|
|
105
|
+
const isSpecialName = rawTagName === options.textNodeName
|
|
106
|
+
|| rawTagName === options.cdataPropName
|
|
107
|
+
|| rawTagName === options.commentPropName
|
|
108
|
+
|| rawTagName[0] === '?';
|
|
109
|
+
|
|
110
|
+
// Resolve tag name (may transform it; may throw for invalid names)
|
|
111
|
+
const tagName = isSpecialName
|
|
112
|
+
? rawTagName
|
|
113
|
+
: resolveTagName(rawTagName, false, options, matcher, xmlVersion);
|
|
114
|
+
|
|
115
|
+
// Extract attributes from ":@" property
|
|
116
|
+
const attrValues = extractAttributeValues(tagObj[":@"], options);
|
|
117
|
+
|
|
118
|
+
// Push resolved tag to matcher WITH attributes
|
|
119
|
+
matcher.push(tagName, attrValues);
|
|
120
|
+
|
|
121
|
+
// Check if this is a stop node using Expression matching
|
|
122
|
+
const isStopNode = checkStopNode(matcher, stopNodeExpressions);
|
|
123
|
+
|
|
124
|
+
if (tagName === options.textNodeName) {
|
|
125
|
+
let tagText = tagObj[rawTagName];
|
|
126
|
+
if (!isStopNode) {
|
|
127
|
+
tagText = options.tagValueProcessor(tagName, tagText);
|
|
128
|
+
tagText = replaceEntitiesValue(tagText, options);
|
|
129
|
+
}
|
|
130
|
+
if (isPreviousElementTag) {
|
|
131
|
+
xmlStr += indentation;
|
|
132
|
+
}
|
|
133
|
+
xmlStr += tagText;
|
|
134
|
+
isPreviousElementTag = false;
|
|
135
|
+
matcher.pop();
|
|
136
|
+
continue;
|
|
137
|
+
} else if (tagName === options.cdataPropName) {
|
|
138
|
+
if (isPreviousElementTag) {
|
|
139
|
+
xmlStr += indentation;
|
|
140
|
+
}
|
|
141
|
+
const val = tagObj[rawTagName][0][options.textNodeName];
|
|
142
|
+
const safeVal = safeCdata(val);
|
|
143
|
+
xmlStr += `<![CDATA[${safeVal}]]>`;
|
|
144
|
+
isPreviousElementTag = false;
|
|
145
|
+
matcher.pop();
|
|
146
|
+
continue;
|
|
147
|
+
} else if (tagName === options.commentPropName) {
|
|
148
|
+
const val = tagObj[rawTagName][0][options.textNodeName];
|
|
149
|
+
const safeVal = safeComment(val);
|
|
150
|
+
xmlStr += indentation + `<!--${safeVal}-->`;
|
|
151
|
+
isPreviousElementTag = true;
|
|
152
|
+
matcher.pop();
|
|
153
|
+
continue;
|
|
154
|
+
} else if (tagName[0] === "?") {
|
|
155
|
+
const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, xmlVersion);
|
|
156
|
+
const tempInd = tagName === "?xml" ? "" : indentation;
|
|
157
|
+
// Text node content on PI/XML declaration tags is intentionally ignored.
|
|
158
|
+
// Only attributes are valid on these tags per the XML spec.
|
|
159
|
+
xmlStr += tempInd + `<${tagName}${attStr}?>`;
|
|
160
|
+
isPreviousElementTag = true;
|
|
161
|
+
matcher.pop();
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let newIdentation = indentation;
|
|
166
|
+
if (newIdentation !== "") {
|
|
167
|
+
newIdentation += options.indentBy;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Pass isStopNode to attr_to_str so attributes are also not processed for stopNodes
|
|
171
|
+
const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, xmlVersion);
|
|
172
|
+
const tagStart = indentation + `<${tagName}${attStr}`;
|
|
173
|
+
|
|
174
|
+
// If this is a stopNode, get raw content without processing
|
|
175
|
+
let tagValue;
|
|
176
|
+
if (isStopNode) {
|
|
177
|
+
tagValue = getRawContent(tagObj[rawTagName], options);
|
|
178
|
+
} else {
|
|
179
|
+
tagValue = arrToStr(tagObj[rawTagName], options, newIdentation, matcher, stopNodeExpressions, xmlVersion);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (options.unpairedTags.indexOf(tagName) !== -1) {
|
|
183
|
+
if (options.suppressUnpairedNode) xmlStr += tagStart + ">";
|
|
184
|
+
else xmlStr += tagStart + "/>";
|
|
185
|
+
} else if ((!tagValue || tagValue.length === 0) && options.suppressEmptyNode) {
|
|
186
|
+
xmlStr += tagStart + "/>";
|
|
187
|
+
} else if (tagValue && tagValue.endsWith(">")) {
|
|
188
|
+
xmlStr += tagStart + `>${tagValue}${indentation}</${tagName}>`;
|
|
189
|
+
} else {
|
|
190
|
+
xmlStr += tagStart + ">";
|
|
191
|
+
if (tagValue && indentation !== "" && (tagValue.includes("/>") || tagValue.includes("</"))) {
|
|
192
|
+
xmlStr += indentation + options.indentBy + tagValue + indentation;
|
|
193
|
+
} else {
|
|
194
|
+
xmlStr += tagValue;
|
|
195
|
+
}
|
|
196
|
+
xmlStr += `</${tagName}>`;
|
|
197
|
+
}
|
|
198
|
+
isPreviousElementTag = true;
|
|
199
|
+
|
|
200
|
+
// Pop tag from matcher
|
|
201
|
+
matcher.pop();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return xmlStr;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Extract attribute values from the ":@" object and return as plain object
|
|
209
|
+
* for passing to matcher.push()
|
|
210
|
+
*/
|
|
211
|
+
function extractAttributeValues(attrMap, options) {
|
|
212
|
+
if (!attrMap || options.ignoreAttributes) return null;
|
|
213
|
+
|
|
214
|
+
const attrValues = {};
|
|
215
|
+
let hasAttrs = false;
|
|
216
|
+
|
|
217
|
+
for (let attr in attrMap) {
|
|
218
|
+
if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
|
|
219
|
+
// Remove the attribute prefix to get clean attribute name
|
|
220
|
+
const cleanAttrName = attr.startsWith(options.attributeNamePrefix)
|
|
221
|
+
? attr.substr(options.attributeNamePrefix.length)
|
|
222
|
+
: attr;
|
|
223
|
+
attrValues[cleanAttrName] = escapeAttribute(attrMap[attr]);
|
|
224
|
+
hasAttrs = true;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return hasAttrs ? attrValues : null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Extract raw content from a stopNode without any processing
|
|
232
|
+
* This preserves the content exactly as-is, including special characters
|
|
233
|
+
*/
|
|
234
|
+
function getRawContent(arr, options) {
|
|
235
|
+
if (!Array.isArray(arr)) {
|
|
236
|
+
// Non-array values return as-is
|
|
237
|
+
if (arr !== undefined && arr !== null) {
|
|
238
|
+
return arr.toString();
|
|
239
|
+
}
|
|
240
|
+
return "";
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let content = "";
|
|
244
|
+
for (let i = 0; i < arr.length; i++) {
|
|
245
|
+
const item = arr[i];
|
|
246
|
+
const tagName = propName(item);
|
|
247
|
+
|
|
248
|
+
if (tagName === options.textNodeName) {
|
|
249
|
+
// Raw text content - NO processing, NO entity replacement
|
|
250
|
+
content += item[tagName];
|
|
251
|
+
} else if (tagName === options.cdataPropName) {
|
|
252
|
+
// CDATA content
|
|
253
|
+
content += item[tagName][0][options.textNodeName];
|
|
254
|
+
} else if (tagName === options.commentPropName) {
|
|
255
|
+
// Comment content
|
|
256
|
+
content += item[tagName][0][options.textNodeName];
|
|
257
|
+
} else if (tagName && tagName[0] === "?") {
|
|
258
|
+
// Processing instruction - skip for stopNodes
|
|
259
|
+
continue;
|
|
260
|
+
} else if (tagName) {
|
|
261
|
+
// Nested tags within stopNode — no sanitizeName, content is raw
|
|
262
|
+
const attStr = attr_to_str_raw(item[":@"], options);
|
|
263
|
+
const nestedContent = getRawContent(item[tagName], options);
|
|
264
|
+
|
|
265
|
+
if (!nestedContent || nestedContent.length === 0) {
|
|
266
|
+
content += `<${tagName}${attStr}/>`;
|
|
267
|
+
} else {
|
|
268
|
+
content += `<${tagName}${attStr}>${nestedContent}</${tagName}>`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return content;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Build attribute string for stopNodes - NO entity replacement
|
|
277
|
+
*/
|
|
278
|
+
function attr_to_str_raw(attrMap, options) {
|
|
279
|
+
let attrStr = "";
|
|
280
|
+
if (attrMap && !options.ignoreAttributes) {
|
|
281
|
+
for (let attr in attrMap) {
|
|
282
|
+
if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
|
|
283
|
+
// For stopNodes, use raw value without processing
|
|
284
|
+
let attrVal = attrMap[attr];
|
|
285
|
+
if (attrVal === true && options.suppressBooleanAttributes) {
|
|
286
|
+
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
|
|
287
|
+
} else {
|
|
288
|
+
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${escapeAttribute(attrVal)}"`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return attrStr;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function propName(obj) {
|
|
296
|
+
const keys = Object.keys(obj);
|
|
297
|
+
for (let i = 0; i < keys.length; i++) {
|
|
298
|
+
const key = keys[i];
|
|
299
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
300
|
+
if (key !== ":@") return key;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Build attribute string, resolving attribute names through sanitizeName when configured.
|
|
306
|
+
* Accepts matcher so the callback has path context.
|
|
307
|
+
*/
|
|
308
|
+
function attr_to_str(attrMap, options, isStopNode, matcher, xmlVersion) {
|
|
309
|
+
let attrStr = "";
|
|
310
|
+
if (attrMap && !options.ignoreAttributes) {
|
|
311
|
+
for (let attr in attrMap) {
|
|
312
|
+
if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue;
|
|
313
|
+
|
|
314
|
+
// Strip prefix to get the clean XML attribute name, then optionally sanitize it
|
|
315
|
+
const cleanAttrName = attr.substr(options.attributeNamePrefix.length);
|
|
316
|
+
const resolvedAttrName = isStopNode
|
|
317
|
+
? cleanAttrName // stopNodes are raw — skip sanitizeName for attr names too
|
|
318
|
+
: resolveTagName(cleanAttrName, true, options, matcher, xmlVersion);
|
|
319
|
+
|
|
320
|
+
let attrVal;
|
|
321
|
+
if (isStopNode) {
|
|
322
|
+
// For stopNodes, use raw value without any processing
|
|
323
|
+
attrVal = attrMap[attr];
|
|
324
|
+
} else {
|
|
325
|
+
// Normal processing: apply attributeValueProcessor and entity replacement
|
|
326
|
+
attrVal = options.attributeValueProcessor(attr, attrMap[attr]);
|
|
327
|
+
attrVal = replaceEntitiesValue(attrVal, options);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (attrVal === true && options.suppressBooleanAttributes) {
|
|
331
|
+
attrStr += ` ${resolvedAttrName}`;
|
|
332
|
+
} else {
|
|
333
|
+
attrStr += ` ${resolvedAttrName}="${escapeAttribute(attrVal)}"`;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return attrStr;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function checkStopNode(matcher, stopNodeExpressions) {
|
|
341
|
+
if (!stopNodeExpressions || stopNodeExpressions.length === 0) return false;
|
|
342
|
+
|
|
343
|
+
for (let i = 0; i < stopNodeExpressions.length; i++) {
|
|
344
|
+
if (matcher.matches(stopNodeExpressions[i])) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function replaceEntitiesValue(textValue, options) {
|
|
352
|
+
if (textValue && textValue.length > 0 && options.processEntities) {
|
|
353
|
+
for (let i = 0; i < options.entities.length; i++) {
|
|
354
|
+
const entity = options.entities[i];
|
|
355
|
+
textValue = textValue.replace(entity.regex, entity.val);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return textValue;
|
|
359
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export function safeComment(val) {
|
|
4
|
+
return String(val)
|
|
5
|
+
.replace(/--/g, '- -') // -- is illegal anywhere in comment content
|
|
6
|
+
.replace(/--/g, '- -') // handle the scenario when 2 consiucative dashes appears
|
|
7
|
+
.replace(/-$/, '- '); // trailing - would form -- with the closing -->
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function safeCdata(val) {
|
|
11
|
+
return String(val).replace(/\]\]>/g, ']]]]><)
|
|
17
|
+
- update XML Builder to 1.1.7
|
|
18
|
+
- mark addEntity deprecated
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
**5.7.2 / 2026-04-25**
|
|
22
|
+
- allow numerical external entity for backward compatibility
|
|
23
|
+
- fix #705: attributesGroupName working with preserveOrder
|
|
24
|
+
- fix #817: stackoverflow when tag expression is very long
|
|
25
|
+
|
|
26
|
+
**5.7.1 / 2026-04-20**
|
|
27
|
+
- fix typo in CJS typing file
|
|
28
|
+
|
|
29
|
+
**5.7.0 / 2026-04-17**
|
|
30
|
+
- Use `@nodable/entities` v2.1.0
|
|
31
|
+
- breaking changes
|
|
32
|
+
- single entity scan. You're not allowed to user entity value to form another entity name.
|
|
33
|
+
- you cant add numeric external entity
|
|
34
|
+
- entity error message when expantion limit is crossed might change
|
|
35
|
+
- typings are updated for new options related to process entity
|
|
36
|
+
- please follow documentation of `@nodable/entities` for more detail.
|
|
37
|
+
- performance
|
|
38
|
+
- if processEntities is false, then there should not be impact on performance.
|
|
39
|
+
- if processEntities is true, but you dont pass entity decoder separately then performance may degrade by approx 8-10%
|
|
40
|
+
- if processEntities is true, and you pass entity decoder separately
|
|
41
|
+
- if no entity then performance should be same as before
|
|
42
|
+
- if there are entities then performance should be increased from past versions
|
|
43
|
+
- ignoreAttributes is not required to be set to set xml version for NCR entity value
|
|
44
|
+
- update 'fast-xml-builder' to sanitize malicious CDATA and comment's content
|
|
45
|
+
|
|
46
|
+
**5.6.0 / 2026-04-15**
|
|
47
|
+
- fix: entity replacement for numeric entities
|
|
48
|
+
- use @nodable/entities to replace entities
|
|
49
|
+
- this may change some error messages related to entities expansion limit or inavlid use
|
|
50
|
+
- post check would be exposed in future version
|
|
51
|
+
|
|
52
|
+
**5.5.12 / 2026-04-13**
|
|
53
|
+
- Performance Improvement: update path-expression-matcher
|
|
54
|
+
- use proxy pattern than Proxy class
|
|
55
|
+
|
|
56
|
+
**5.5.11 / 2026-04-08**
|
|
57
|
+
- Performance Improvement
|
|
58
|
+
- integrate ExpressionSet for stopNodes
|
|
59
|
+
|
|
60
|
+
**5.5.10 / 2026-04-03**
|
|
61
|
+
- increase default entity explansion limit as many projects demand for that
|
|
62
|
+
- performance improvement
|
|
63
|
+
- reduce calls to toString
|
|
64
|
+
- early return when entities are not present
|
|
65
|
+
- prepare rawAttrsForMatcher only if user sets `jPath: false`
|
|
66
|
+
|
|
67
|
+
**5.5.9 / 2026-03-23**
|
|
68
|
+
- combine typing files
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
**4.5.5 / 2026-03-22**
|
|
72
|
+
|
|
73
|
+
apply fixes from v5 (legacy maintenance branch v4-maintenance)
|
|
74
|
+
|
|
75
|
+
- support maxEntityCount
|
|
76
|
+
- support onDangerousProperty
|
|
77
|
+
- support maxNestedTags
|
|
78
|
+
- handle prototype pollution
|
|
79
|
+
- fix incorrect entity name replacement
|
|
80
|
+
- fix incorrect condition for entity expansion
|
|
81
|
+
|
|
82
|
+
**5.5.8 / 2026-03-20**
|
|
83
|
+
- pass read only matcher in callback
|
|
84
|
+
|
|
85
|
+
**5.5.7 / 2026-03-19**
|
|
86
|
+
- fix: entity expansion limits
|
|
87
|
+
- update strnum package to 2.2.0
|
|
88
|
+
|
|
89
|
+
**5.5.6 / 2026-03-16**
|
|
90
|
+
- update builder dependency
|
|
91
|
+
- fix incorrect regex to replace \. in entity name
|
|
92
|
+
- fix check for entitiy expansion for lastEntities and html entities too
|
|
93
|
+
|
|
94
|
+
**5.5.5 / 2026-03-13**
|
|
95
|
+
- sanitize dangerous tag or attribute name
|
|
96
|
+
- error on critical property name
|
|
97
|
+
- support onDangerousProperty option
|
|
98
|
+
|
|
99
|
+
**5.5.4 / 2026-03-13**
|
|
100
|
+
- declare Matcher & Expression as unknown so user is not forced to install path-expression-matcher
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
**5.5.3 / 2026-03-11**
|
|
104
|
+
- upgrade builder
|
|
105
|
+
|
|
106
|
+
**5.5.2 / 2026-03-11**
|
|
107
|
+
- update dependency to fix typings
|
|
108
|
+
|
|
109
|
+
**5.5.1 / 2026-03-10**
|
|
110
|
+
- fix dependency
|
|
111
|
+
|
|
112
|
+
**5.5.0 / 2026-03-10**
|
|
113
|
+
- support path-expression-matcher
|
|
114
|
+
- fix: stopNode should not be parsed
|
|
115
|
+
- performance improvement for stopNode checking
|
|
116
|
+
|
|
117
|
+
**5.4.2 / 2026-03-03**
|
|
118
|
+
- support maxEntityCount option
|
|
119
|
+
|
|
120
|
+
**5.4.1 / 2026-02-25**
|
|
121
|
+
- fix (#785) unpairedTag node should not have tag content
|
|
122
|
+
|
|
123
|
+
**5.4.0 / 2026-02-25**
|
|
124
|
+
- migrate to fast-xml-builder
|
|
125
|
+
|
|
126
|
+
**5.3.9 / 2026-02-25**
|
|
127
|
+
- support strictReservedNames
|
|
128
|
+
|
|
129
|
+
**5.3.8 / 2026-02-25**
|
|
130
|
+
- support maxNestedTags
|
|
131
|
+
- handle non-array input for XML builder when preserveOrder is true (By [Angelo Coetzee](https://github.com/Angelopvtac))
|
|
132
|
+
- save use of js properies
|
|
133
|
+
|
|
134
|
+
**5.3.7 / 2026-02-20**
|
|
135
|
+
- fix typings for CJS (By [Corentin Girard](https://github.com/Drarig29))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
**5.3.6 / 2026-02-14**
|
|
140
|
+
- Improve security and performance of entity processing
|
|
141
|
+
- new options `maxEntitySize`, `maxExpansionDepth`, `maxTotalExpansions`, `maxExpandedLength`, `allowedTags`,`tagFilter`
|
|
142
|
+
- fast return when no edtity is present
|
|
143
|
+
- improvement replacement logic to reduce number of calls
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
**5.3.5 / 2026-02-08**
|
|
147
|
+
- fix: Escape regex char in entity name
|
|
148
|
+
- update strnum to 2.1.2
|
|
149
|
+
- add missing exports in CJS typings
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
**5.3.4 / 2026-01-30**
|
|
153
|
+
- fix: handle HTML numeric and hex entities when out of range
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
**5.3.3 / 2025-12-12**
|
|
157
|
+
- fix #775: transformTagName with allowBooleanAttributes adds an unnecessary attribute
|
|
158
|
+
|
|
159
|
+
**5.3.2 / 2025-11-14**
|
|
160
|
+
- fix for import statement for v6
|
|
161
|
+
|
|
162
|
+
**5.3.1 / 2025-11-03**
|
|
163
|
+
- Performance improvement for stopNodes (By [Maciek Lamberski](https://github.com/macieklamberski))
|
|
164
|
+
|
|
165
|
+
**5.3.0 / 2025-10-03**
|
|
166
|
+
- Use `Uint8Array` in place of `Buffer` in Parser
|
|
167
|
+
|
|
3
168
|
**5.2.5 / 2025-06-08**
|
|
4
169
|
- Inform user to use [fxp-cli](https://github.com/NaturalIntelligence/fxp-cli) instead of in-built CLI feature
|
|
5
170
|
- Export typings for direct use
|
|
@@ -7,21 +7,28 @@ Validate XML, Parse XML to JS Object, or Build XML from JS Object without C/C++
|
|
|
7
7
|
<img align="right" src="static/img/fxp_logo.png" width="180px" alt="FXP logo"/>
|
|
8
8
|
|
|
9
9
|
* Validate XML data syntactically. Use [detailed-xml-validator](https://github.com/NaturalIntelligence/detailed-xml-validator/) to verify business rules.
|
|
10
|
-
* Parse XML to JS
|
|
10
|
+
* Parse XML to JS Objects and vice versa
|
|
11
11
|
* Common JS, ESM, and browser compatible
|
|
12
12
|
* Faster than any other pure JS implementation.
|
|
13
13
|
|
|
14
14
|
It can handle big files (tested up to 100mb). XML Entities, HTML entities, and DOCTYPE entites are supported. Unpaired tags (Eg `<br>` in HTML), stop nodes (Eg `<script>` in HTML) are supported. It can also preserve Order of tags in JS object
|
|
15
15
|
|
|
16
|
+
> [Flexible-XML-Parser](https://github.com/nodable/flexible-xml-parser) is 2 times faster than this library and allows to deal with incomplete XML/HTML. Output is highly customizable. Build whatever you want. So if you're fine with some extra configuration then try it out.
|
|
17
|
+
|
|
16
18
|
---
|
|
17
19
|
# Your Support, Our Motivation
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
Please join [Discord community](https://discord.gg/X4Qp9u6Vz) for pre release announcements and discussions. This will prevent us to release breaking changes.
|
|
22
|
+
|
|
23
|
+
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
<a href="https://github.com/solothought/flowgger"> <img src="static/img/flowgger_h.webp" alt="Flowgger Logging Framework" /></a>
|
|
25
|
+
<!-- ## Try out our New Thoughts
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
- WishIn - You need it if negative thoughts take over all the time <br>
|
|
28
|
+
<a href="https://play.google.com/store/apps/details?id=com.solothought.wishin"> <img src="https://solothought.com/products/assets/images/wishin/YouTubeThumbnail.png" width="500px"/> </a>
|
|
29
|
+
- **Flowgger**: 90% less logs size and 90% less debugging time<br>
|
|
30
|
+
<a href="https://github.com/solothought/flowgger"> <img src="static/img/flowgger_h.webp" alt="Flowgger Logging Framework" width="300px"/></a>
|
|
31
|
+
- [Text2Chart](https://solothought.com/text2chart/flow): interactive flow chart out of simple text. -->
|
|
25
32
|
|
|
26
33
|
## Financial Support
|
|
27
34
|
|
|
@@ -33,37 +40,10 @@ Sponsor this project
|
|
|
33
40
|
<a href="https://opencollective.com/fast-xml-parser/donate" target="_blank">
|
|
34
41
|
<img src="https://opencollective.com/fast-xml-parser/donate/button@2x.png?color=blue" width=180 />
|
|
35
42
|
</a>
|
|
36
|
-
<a href="https://paypal.me/naturalintelligence"> <img src="static/img/support_paypal.svg" alt="donate button" width="180"/></a>
|
|
37
43
|
<br>
|
|
38
44
|
<br>
|
|
39
45
|
<br>
|
|
40
46
|
|
|
41
|
-
<!--
|
|
42
|
-
### Current Sponsors
|
|
43
|
-
|
|
44
|
-
Check the complete list at [ThankYouBackers](https://github.com/NaturalIntelligence/ThankYouBackers) for our sponsors and supporters.
|
|
45
|
-
|
|
46
|
-
Through Github
|
|
47
|
-
|
|
48
|
-
<a href="https://github.com/skunkteam" target="_blank"><img src="https://avatars.githubusercontent.com/u/46373671?s=60" width="60px"></a>
|
|
49
|
-
<a href="https://github.com/getsentry" target="_blank"><img src="https://avatars.githubusercontent.com/u/1396951?s=60" width="60px"></a>
|
|
50
|
-
|
|
51
|
-
Through OpenCollective
|
|
52
|
-
|
|
53
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/0/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/0/avatar.svg"></a>
|
|
54
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/1/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/1/avatar.svg"></a>
|
|
55
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/2/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/2/avatar.svg"></a>
|
|
56
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/3/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/3/avatar.svg"></a>
|
|
57
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/4/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/4/avatar.svg"></a>
|
|
58
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/5/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/5/avatar.svg"></a>
|
|
59
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/6/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/6/avatar.svg"></a>
|
|
60
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/7/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/7/avatar.svg"></a>
|
|
61
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/8/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/8/avatar.svg"></a>
|
|
62
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/9/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/9/avatar.svg"></a>
|
|
63
|
-
-->
|
|
64
|
-
|
|
65
|
-

|
|
66
|
-
|
|
67
47
|
> This is a donation. No goods or services are expected in return. Any requests for refunds for those purposes will be rejected.
|
|
68
48
|
|
|
69
49
|
## Users
|
|
@@ -151,26 +131,23 @@ Bundle size
|
|
|
151
131
|
<a href="./docs/v3/docs.md">documents</a>
|
|
152
132
|
</td>
|
|
153
133
|
<td><ol>
|
|
154
|
-
<li><a href="./docs/v4/1.GettingStarted.md">Getting Started</a></li>
|
|
155
|
-
<li><a href="./docs/v4/2.XMLparseOptions.md">XML Parser</a></li>
|
|
156
|
-
<li><a href="./docs/v4/3.XMLBuilder.md">XML Builder</a></li>
|
|
157
|
-
<li><a href="./docs/v4/4.XMLValidator.md">XML Validator</a></li>
|
|
158
|
-
<li><a href="./docs/v4/5.Entities.md">Entities</a></li>
|
|
159
|
-
<li><a href="./docs/v4/6.HTMLParsing.md">HTML Document Parsing</a></li>
|
|
160
|
-
<li><a href="./docs/v4/7.PITags.md">PI Tag processing</a></li>
|
|
134
|
+
<li><a href="./docs/v4,v5/1.GettingStarted.md">Getting Started</a></li>
|
|
135
|
+
<li><a href="./docs/v4,v5/2.XMLparseOptions.md">XML Parser</a></li>
|
|
136
|
+
<li><a href="./docs/v4,v5/3.XMLBuilder.md">XML Builder</a></li>
|
|
137
|
+
<li><a href="./docs/v4,v5/4.XMLValidator.md">XML Validator</a></li>
|
|
138
|
+
<li><a href="./docs/v4,v5/5.Entities.md">Entities</a></li>
|
|
139
|
+
<li><a href="./docs/v4,v5/6.HTMLParsing.md">HTML Document Parsing</a></li>
|
|
140
|
+
<li><a href="./docs/v4,v5/7.PITags.md">PI Tag processing</a></li>
|
|
141
|
+
<li><a href="./docs/v4,v5/8.PathExpression.md">Path Expression</a></li>
|
|
161
142
|
</ol></td>
|
|
162
143
|
<td><ol>
|
|
163
144
|
<li></li><a href="./docs/v6/1.GettingStarted.md">Getting Started</a></li>
|
|
164
|
-
<li><a href="./docs/v6/2.Features.md">Features</a></li>
|
|
165
|
-
<li><a href="./docs/v6/3.Options.md">Options</a></li>
|
|
166
|
-
<li><a href="./docs/v6/4.OutputBuilders.md">Output Builders</a></li>
|
|
167
|
-
<li><a href="./docs/v6/5.ValueParsers.md">Value Parsers</a></li>
|
|
168
145
|
</ol></td>
|
|
169
146
|
</tr>
|
|
170
147
|
</table>
|
|
171
148
|
|
|
172
149
|
**note**:
|
|
173
|
-
- Version 6 is released with version 4 for experimental use. Based on
|
|
150
|
+
- Version 6 is released with version 4 for experimental use. Based on its demand, it'll be developed and the features can be different in final release.
|
|
174
151
|
- Version 5 has the same functionalities as version 4.
|
|
175
152
|
|
|
176
153
|
## Performance
|