@btc-embedded/cdk-extensions 0.23.3 → 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 +41 -41
- package/CHANGELOG.md +14 -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 +5 -4
- 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,599 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
//parse Empty Node as self closing node
|
|
3
|
+
import buildFromOrderedJs from './orderedJs2Xml.js';
|
|
4
|
+
import getIgnoreAttributesFn from "./ignoreAttributes.js";
|
|
5
|
+
import { Expression, Matcher } from 'path-expression-matcher';
|
|
6
|
+
import { safeComment, safeCdata, escapeAttribute } from './util.js';
|
|
7
|
+
import { qName } from 'xml-naming';
|
|
8
|
+
|
|
9
|
+
const defaultOptions = {
|
|
10
|
+
attributeNamePrefix: '@_',
|
|
11
|
+
attributesGroupName: false,
|
|
12
|
+
textNodeName: '#text',
|
|
13
|
+
ignoreAttributes: true,
|
|
14
|
+
cdataPropName: false,
|
|
15
|
+
format: false,
|
|
16
|
+
indentBy: ' ',
|
|
17
|
+
suppressEmptyNode: false,
|
|
18
|
+
suppressUnpairedNode: true,
|
|
19
|
+
suppressBooleanAttributes: true,
|
|
20
|
+
tagValueProcessor: function (key, a) {
|
|
21
|
+
return a;
|
|
22
|
+
},
|
|
23
|
+
attributeValueProcessor: function (attrName, a) {
|
|
24
|
+
return a;
|
|
25
|
+
},
|
|
26
|
+
preserveOrder: false,
|
|
27
|
+
commentPropName: false,
|
|
28
|
+
unpairedTags: [],
|
|
29
|
+
entities: [
|
|
30
|
+
{ regex: new RegExp("&", "g"), val: "&" },//it must be on top
|
|
31
|
+
{ regex: new RegExp(">", "g"), val: ">" },
|
|
32
|
+
{ regex: new RegExp("<", "g"), val: "<" },
|
|
33
|
+
{ regex: new RegExp("\'", "g"), val: "'" },
|
|
34
|
+
{ regex: new RegExp("\"", "g"), val: """ }
|
|
35
|
+
],
|
|
36
|
+
processEntities: true,
|
|
37
|
+
stopNodes: [],
|
|
38
|
+
// transformTagName: false,
|
|
39
|
+
// transformAttributeName: false,
|
|
40
|
+
oneListGroup: false,
|
|
41
|
+
maxNestedTags: 100,
|
|
42
|
+
jPath: true, // When true, callbacks receive string jPath; when false, receive Matcher instance
|
|
43
|
+
sanitizeName: false // false = allow all names as-is (default, backward-compatible).
|
|
44
|
+
// Set to a function (name, { isAttribute, matcher }) => string to
|
|
45
|
+
// validate/sanitize tag and attribute names. Throw inside the function
|
|
46
|
+
// to reject an invalid name.
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default function Builder(options) {
|
|
50
|
+
this.options = Object.assign({}, defaultOptions, options);
|
|
51
|
+
|
|
52
|
+
// Convert old-style stopNodes for backward compatibility
|
|
53
|
+
// Old syntax: "*.tag" meant "tag anywhere in tree"
|
|
54
|
+
// New syntax: "..tag" means "tag anywhere in tree"
|
|
55
|
+
if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
|
|
56
|
+
this.options.stopNodes = this.options.stopNodes.map(node => {
|
|
57
|
+
if (typeof node === 'string' && node.startsWith('*.')) {
|
|
58
|
+
// Convert old wildcard syntax to deep wildcard
|
|
59
|
+
return '..' + node.substring(2);
|
|
60
|
+
}
|
|
61
|
+
return node;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Pre-compile stopNode expressions for pattern matching
|
|
66
|
+
this.stopNodeExpressions = [];
|
|
67
|
+
if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
|
|
68
|
+
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
|
69
|
+
const node = this.options.stopNodes[i];
|
|
70
|
+
if (typeof node === 'string') {
|
|
71
|
+
this.stopNodeExpressions.push(new Expression(node));
|
|
72
|
+
} else if (node instanceof Expression) {
|
|
73
|
+
this.stopNodeExpressions.push(node);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (this.options.ignoreAttributes === true || this.options.attributesGroupName) {
|
|
79
|
+
this.isAttribute = function (/*a*/) {
|
|
80
|
+
return false;
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
|
|
84
|
+
this.attrPrefixLen = this.options.attributeNamePrefix.length;
|
|
85
|
+
this.isAttribute = isAttribute;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.processTextOrObjNode = processTextOrObjNode
|
|
89
|
+
|
|
90
|
+
if (this.options.format) {
|
|
91
|
+
this.indentate = indentate;
|
|
92
|
+
this.tagEndChar = '>\n';
|
|
93
|
+
this.newLine = '\n';
|
|
94
|
+
} else {
|
|
95
|
+
this.indentate = function () {
|
|
96
|
+
return '';
|
|
97
|
+
};
|
|
98
|
+
this.tagEndChar = '>';
|
|
99
|
+
this.newLine = '';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Detect XML version from the ?xml declaration at the root of a plain-object input.
|
|
105
|
+
* Checks both attributesGroupName and flat attribute forms.
|
|
106
|
+
* Returns '1.0' if no declaration is found.
|
|
107
|
+
*/
|
|
108
|
+
function detectXmlVersionFromObj(jObj, options) {
|
|
109
|
+
const decl = jObj['?xml'];
|
|
110
|
+
if (decl && typeof decl === 'object') {
|
|
111
|
+
// attributesGroupName path e.g. { '$$': { '@_version': '1.1' } }
|
|
112
|
+
if (options.attributesGroupName && decl[options.attributesGroupName]) {
|
|
113
|
+
const v = decl[options.attributesGroupName][options.attributeNamePrefix + 'version'];
|
|
114
|
+
if (v) return v;
|
|
115
|
+
}
|
|
116
|
+
// flat attribute path e.g. { '@_version': '1.1' }
|
|
117
|
+
const v = decl[options.attributeNamePrefix + 'version'];
|
|
118
|
+
if (v) return v;
|
|
119
|
+
}
|
|
120
|
+
return '1.0';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolve a tag or attribute name through sanitizeName if configured.
|
|
125
|
+
* Validation via xml-naming's qName is performed first; the sanitizeName
|
|
126
|
+
* callback is invoked only when the name is invalid. If sanitizeName is
|
|
127
|
+
* false (default), no validation occurs and the name is used as-is.
|
|
128
|
+
*
|
|
129
|
+
* @param {string} name - raw name from the JS object
|
|
130
|
+
* @param {boolean} isAttribute - true when resolving an attribute name
|
|
131
|
+
* @param {object} options
|
|
132
|
+
* @param {Matcher} matcher - current matcher state (readonly from callback perspective)
|
|
133
|
+
* @param {string} xmlVersion - '1.0' or '1.1', forwarded to xml-naming
|
|
134
|
+
*/
|
|
135
|
+
function resolveTagName(name, isAttribute, options, matcher, xmlVersion) {
|
|
136
|
+
if (!options.sanitizeName) return name;
|
|
137
|
+
if (qName(name, { xmlVersion })) return name;
|
|
138
|
+
return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Builder.prototype.build = function (jObj) {
|
|
142
|
+
if (this.options.preserveOrder) {
|
|
143
|
+
return buildFromOrderedJs(jObj, this.options);
|
|
144
|
+
} else {
|
|
145
|
+
if (Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1) {
|
|
146
|
+
jObj = {
|
|
147
|
+
[this.options.arrayNodeName]: jObj
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Initialize matcher for path tracking
|
|
151
|
+
const matcher = new Matcher();
|
|
152
|
+
const xmlVersion = detectXmlVersionFromObj(jObj, this.options);
|
|
153
|
+
return this.j2x(jObj, 0, matcher, xmlVersion).val;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
Builder.prototype.j2x = function (jObj, level, matcher, xmlVersion) {
|
|
158
|
+
let attrStr = '';
|
|
159
|
+
let val = '';
|
|
160
|
+
if (this.options.maxNestedTags && matcher.getDepth() >= this.options.maxNestedTags) {
|
|
161
|
+
throw new Error("Maximum nested tags exceeded");
|
|
162
|
+
}
|
|
163
|
+
// Get jPath based on option: string for backward compatibility, or Matcher for new features
|
|
164
|
+
const jPath = this.options.jPath ? matcher.toString() : matcher;
|
|
165
|
+
|
|
166
|
+
// Check if current node is a stopNode (will be used for attribute encoding)
|
|
167
|
+
const isCurrentStopNode = this.checkStopNode(matcher);
|
|
168
|
+
|
|
169
|
+
for (let key in jObj) {
|
|
170
|
+
if (!Object.prototype.hasOwnProperty.call(jObj, key)) continue;
|
|
171
|
+
|
|
172
|
+
// Resolve the key through sanitizeName before any use.
|
|
173
|
+
// Special keys (textNodeName, cdataPropName, commentPropName, attributeNamePrefix,
|
|
174
|
+
// attributesGroupName, "?" PI tags) are exempt — they are builder-internal conventions,
|
|
175
|
+
// not user-supplied XML names.
|
|
176
|
+
const isSpecialKey = key === this.options.textNodeName
|
|
177
|
+
|| key === this.options.cdataPropName
|
|
178
|
+
|| key === this.options.commentPropName
|
|
179
|
+
|| (this.options.attributesGroupName && key === this.options.attributesGroupName)
|
|
180
|
+
|| this.isAttribute(key)
|
|
181
|
+
|| key[0] === '?';
|
|
182
|
+
|
|
183
|
+
const resolvedKey = isSpecialKey
|
|
184
|
+
? key
|
|
185
|
+
: resolveTagName(key, false, this.options, matcher, xmlVersion);
|
|
186
|
+
|
|
187
|
+
if (typeof jObj[key] === 'undefined') {
|
|
188
|
+
// supress undefined node only if it is not an attribute
|
|
189
|
+
if (this.isAttribute(key)) {
|
|
190
|
+
val += '';
|
|
191
|
+
}
|
|
192
|
+
} else if (jObj[key] === null) {
|
|
193
|
+
// null attribute should be ignored by the attribute list, but should not cause the tag closing
|
|
194
|
+
if (this.isAttribute(key)) {
|
|
195
|
+
val += '';
|
|
196
|
+
} else if (resolvedKey === this.options.cdataPropName || resolvedKey === this.options.commentPropName) {
|
|
197
|
+
val += '';
|
|
198
|
+
} else if (resolvedKey[0] === '?') {
|
|
199
|
+
val += this.indentate(level) + '<' + resolvedKey + '?' + this.tagEndChar;
|
|
200
|
+
} else {
|
|
201
|
+
val += this.indentate(level) + '<' + resolvedKey + '/' + this.tagEndChar;
|
|
202
|
+
}
|
|
203
|
+
} else if (jObj[key] instanceof Date) {
|
|
204
|
+
val += this.buildTextValNode(jObj[key], resolvedKey, '', level, matcher);
|
|
205
|
+
} else if (typeof jObj[key] !== 'object') {
|
|
206
|
+
//premitive type
|
|
207
|
+
const attr = this.isAttribute(key);
|
|
208
|
+
if (attr && !this.ignoreAttributesFn(attr, jPath)) {
|
|
209
|
+
// Resolve the attribute name through sanitizeName
|
|
210
|
+
const resolvedAttr = resolveTagName(attr, true, this.options, matcher, xmlVersion);
|
|
211
|
+
attrStr += this.buildAttrPairStr(resolvedAttr, '' + jObj[key], isCurrentStopNode);
|
|
212
|
+
} else if (!attr) {
|
|
213
|
+
//tag value
|
|
214
|
+
if (key === this.options.textNodeName) {
|
|
215
|
+
let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
|
|
216
|
+
val += this.replaceEntitiesValue(newval);
|
|
217
|
+
} else {
|
|
218
|
+
// Check if this is a stopNode before building
|
|
219
|
+
matcher.push(resolvedKey);
|
|
220
|
+
const isStopNode = this.checkStopNode(matcher);
|
|
221
|
+
matcher.pop();
|
|
222
|
+
|
|
223
|
+
if (isStopNode) {
|
|
224
|
+
// Build as raw content without encoding
|
|
225
|
+
const textValue = '' + jObj[key];
|
|
226
|
+
if (textValue === '') {
|
|
227
|
+
val += this.indentate(level) + '<' + resolvedKey + this.closeTag(resolvedKey) + this.tagEndChar;
|
|
228
|
+
} else {
|
|
229
|
+
val += this.indentate(level) + '<' + resolvedKey + '>' + textValue + '</' + resolvedKey + this.tagEndChar;
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
val += this.buildTextValNode(jObj[key], resolvedKey, '', level, matcher);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
} else if (Array.isArray(jObj[key])) {
|
|
237
|
+
//repeated nodes
|
|
238
|
+
const arrLen = jObj[key].length;
|
|
239
|
+
let listTagVal = "";
|
|
240
|
+
let listTagAttr = "";
|
|
241
|
+
for (let j = 0; j < arrLen; j++) {
|
|
242
|
+
const item = jObj[key][j];
|
|
243
|
+
if (typeof item === 'undefined') {
|
|
244
|
+
// supress undefined node
|
|
245
|
+
} else if (item === null) {
|
|
246
|
+
if (resolvedKey[0] === "?") val += this.indentate(level) + '<' + resolvedKey + '?' + this.tagEndChar;
|
|
247
|
+
else val += this.indentate(level) + '<' + resolvedKey + '/' + this.tagEndChar;
|
|
248
|
+
} else if (typeof item === 'object') {
|
|
249
|
+
if (this.options.oneListGroup) {
|
|
250
|
+
// Push tag to matcher before recursive call
|
|
251
|
+
matcher.push(resolvedKey);
|
|
252
|
+
const result = this.j2x(item, level + 1, matcher, xmlVersion);
|
|
253
|
+
// Pop tag from matcher after recursive call
|
|
254
|
+
matcher.pop();
|
|
255
|
+
|
|
256
|
+
listTagVal += result.val;
|
|
257
|
+
if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) {
|
|
258
|
+
listTagAttr += result.attrStr
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
listTagVal += this.processTextOrObjNode(item, resolvedKey, level, matcher, xmlVersion)
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
if (this.options.oneListGroup) {
|
|
265
|
+
let textValue = this.options.tagValueProcessor(resolvedKey, item);
|
|
266
|
+
textValue = this.replaceEntitiesValue(textValue);
|
|
267
|
+
listTagVal += textValue;
|
|
268
|
+
} else {
|
|
269
|
+
// Check if this is a stopNode before building
|
|
270
|
+
matcher.push(resolvedKey);
|
|
271
|
+
const isStopNode = this.checkStopNode(matcher);
|
|
272
|
+
matcher.pop();
|
|
273
|
+
|
|
274
|
+
if (isStopNode) {
|
|
275
|
+
// Build as raw content without encoding
|
|
276
|
+
const textValue = '' + item;
|
|
277
|
+
if (textValue === '') {
|
|
278
|
+
listTagVal += this.indentate(level) + '<' + resolvedKey + this.closeTag(resolvedKey) + this.tagEndChar;
|
|
279
|
+
} else {
|
|
280
|
+
listTagVal += this.indentate(level) + '<' + resolvedKey + '>' + textValue + '</' + resolvedKey + this.tagEndChar;
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
listTagVal += this.buildTextValNode(item, resolvedKey, '', level, matcher);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (this.options.oneListGroup) {
|
|
289
|
+
listTagVal = this.buildObjectNode(listTagVal, resolvedKey, listTagAttr, level);
|
|
290
|
+
}
|
|
291
|
+
val += listTagVal;
|
|
292
|
+
} else {
|
|
293
|
+
//nested node
|
|
294
|
+
if (this.options.attributesGroupName && key === this.options.attributesGroupName) {
|
|
295
|
+
const Ks = Object.keys(jObj[key]);
|
|
296
|
+
const L = Ks.length;
|
|
297
|
+
for (let j = 0; j < L; j++) {
|
|
298
|
+
// Resolve attribute names inside attributesGroupName
|
|
299
|
+
const resolvedAttr = resolveTagName(Ks[j], true, this.options, matcher, xmlVersion);
|
|
300
|
+
attrStr += this.buildAttrPairStr(resolvedAttr, '' + jObj[key][Ks[j]], isCurrentStopNode);
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
val += this.processTextOrObjNode(jObj[key], resolvedKey, level, matcher, xmlVersion)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { attrStr: attrStr, val: val };
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
Builder.prototype.buildAttrPairStr = function (attrName, val, isStopNode) {
|
|
311
|
+
if (!isStopNode) {
|
|
312
|
+
val = this.options.attributeValueProcessor(attrName, '' + val);
|
|
313
|
+
val = this.replaceEntitiesValue(val);
|
|
314
|
+
}
|
|
315
|
+
if (this.options.suppressBooleanAttributes && val === "true") {
|
|
316
|
+
return ' ' + attrName;
|
|
317
|
+
} else return ' ' + attrName + '="' + escapeAttribute(val) + '"';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function processTextOrObjNode(object, key, level, matcher, xmlVersion) {
|
|
321
|
+
// Extract attributes to pass to matcher
|
|
322
|
+
const attrValues = this.extractAttributes(object);
|
|
323
|
+
|
|
324
|
+
// Push tag to matcher before recursion WITH attributes
|
|
325
|
+
matcher.push(key, attrValues);
|
|
326
|
+
|
|
327
|
+
// Check if this entire node is a stopNode
|
|
328
|
+
const isStopNode = this.checkStopNode(matcher);
|
|
329
|
+
|
|
330
|
+
if (isStopNode) {
|
|
331
|
+
// For stopNodes, build raw content without entity encoding
|
|
332
|
+
const rawContent = this.buildRawContent(object);
|
|
333
|
+
const attrStr = this.buildAttributesForStopNode(object);
|
|
334
|
+
matcher.pop();
|
|
335
|
+
return this.buildObjectNode(rawContent, key, attrStr, level);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const result = this.j2x(object, level + 1, matcher, xmlVersion);
|
|
339
|
+
// Pop tag from matcher after recursion
|
|
340
|
+
matcher.pop();
|
|
341
|
+
|
|
342
|
+
// PI/XML-declaration tags must never emit text content — route through
|
|
343
|
+
// buildTextValNode which correctly ignores the text node for "?" tags.
|
|
344
|
+
if (key[0] === '?') {
|
|
345
|
+
return this.buildTextValNode('', key, result.attrStr, level, matcher);
|
|
346
|
+
} else if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
|
347
|
+
return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level, matcher);
|
|
348
|
+
} else {
|
|
349
|
+
return this.buildObjectNode(result.val, key, result.attrStr, level);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Helper method to extract attributes from an object
|
|
354
|
+
Builder.prototype.extractAttributes = function (obj) {
|
|
355
|
+
if (!obj || typeof obj !== 'object') return null;
|
|
356
|
+
|
|
357
|
+
const attrValues = {};
|
|
358
|
+
let hasAttrs = false;
|
|
359
|
+
|
|
360
|
+
// Check for attributesGroupName (when attributes are grouped)
|
|
361
|
+
if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
|
|
362
|
+
const attrGroup = obj[this.options.attributesGroupName];
|
|
363
|
+
for (let attrKey in attrGroup) {
|
|
364
|
+
if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
|
|
365
|
+
// Remove attribute prefix if present
|
|
366
|
+
const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
|
|
367
|
+
? attrKey.substring(this.options.attributeNamePrefix.length)
|
|
368
|
+
: attrKey;
|
|
369
|
+
attrValues[cleanKey] = escapeAttribute(attrGroup[attrKey]);
|
|
370
|
+
hasAttrs = true;
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
// Look for individual attributes (prefixed with attributeNamePrefix)
|
|
374
|
+
for (let key in obj) {
|
|
375
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
376
|
+
const attr = this.isAttribute(key);
|
|
377
|
+
if (attr) {
|
|
378
|
+
attrValues[attr] = escapeAttribute(obj[key]);
|
|
379
|
+
hasAttrs = true;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return hasAttrs ? attrValues : null;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// Build raw content for stopNode without entity encoding
|
|
388
|
+
Builder.prototype.buildRawContent = function (obj) {
|
|
389
|
+
if (typeof obj === 'string') {
|
|
390
|
+
return obj; // Already a string, return as-is
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
394
|
+
return String(obj);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Check if this is a stopNode data from parser: { "#text": "raw xml", "@_attr": "val" }
|
|
398
|
+
if (obj[this.options.textNodeName] !== undefined) {
|
|
399
|
+
return obj[this.options.textNodeName]; // Return raw text without encoding
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Build raw XML from nested structure
|
|
403
|
+
let content = '';
|
|
404
|
+
|
|
405
|
+
for (let key in obj) {
|
|
406
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
407
|
+
|
|
408
|
+
// Skip attributes
|
|
409
|
+
if (this.isAttribute(key)) continue;
|
|
410
|
+
if (this.options.attributesGroupName && key === this.options.attributesGroupName) continue;
|
|
411
|
+
|
|
412
|
+
const value = obj[key];
|
|
413
|
+
|
|
414
|
+
if (key === this.options.textNodeName) {
|
|
415
|
+
content += value; // Raw text
|
|
416
|
+
} else if (Array.isArray(value)) {
|
|
417
|
+
// Array of same tag
|
|
418
|
+
for (let item of value) {
|
|
419
|
+
if (typeof item === 'string' || typeof item === 'number') {
|
|
420
|
+
content += `<${key}>${item}</${key}>`;
|
|
421
|
+
} else if (typeof item === 'object' && item !== null) {
|
|
422
|
+
const nestedContent = this.buildRawContent(item);
|
|
423
|
+
const nestedAttrs = this.buildAttributesForStopNode(item);
|
|
424
|
+
if (nestedContent === '') {
|
|
425
|
+
content += `<${key}${nestedAttrs}/>`;
|
|
426
|
+
} else {
|
|
427
|
+
content += `<${key}${nestedAttrs}>${nestedContent}</${key}>`;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
432
|
+
// Nested object
|
|
433
|
+
const nestedContent = this.buildRawContent(value);
|
|
434
|
+
const nestedAttrs = this.buildAttributesForStopNode(value);
|
|
435
|
+
if (nestedContent === '') {
|
|
436
|
+
content += `<${key}${nestedAttrs}/>`;
|
|
437
|
+
} else {
|
|
438
|
+
content += `<${key}${nestedAttrs}>${nestedContent}</${key}>`;
|
|
439
|
+
}
|
|
440
|
+
} else {
|
|
441
|
+
// Primitive value
|
|
442
|
+
content += `<${key}>${value}</${key}>`;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return content;
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// Build attribute string for stopNode (no entity encoding)
|
|
450
|
+
Builder.prototype.buildAttributesForStopNode = function (obj) {
|
|
451
|
+
if (!obj || typeof obj !== 'object') return '';
|
|
452
|
+
|
|
453
|
+
let attrStr = '';
|
|
454
|
+
|
|
455
|
+
// Check for attributesGroupName (when attributes are grouped)
|
|
456
|
+
if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
|
|
457
|
+
const attrGroup = obj[this.options.attributesGroupName];
|
|
458
|
+
for (let attrKey in attrGroup) {
|
|
459
|
+
if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
|
|
460
|
+
const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
|
|
461
|
+
? attrKey.substring(this.options.attributeNamePrefix.length)
|
|
462
|
+
: attrKey;
|
|
463
|
+
const val = attrGroup[attrKey];
|
|
464
|
+
if (val === true && this.options.suppressBooleanAttributes) {
|
|
465
|
+
attrStr += ' ' + cleanKey;
|
|
466
|
+
} else {
|
|
467
|
+
attrStr += ' ' + cleanKey + '="' + val + '"'; // No encoding for stopNode
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
// Look for individual attributes
|
|
472
|
+
for (let key in obj) {
|
|
473
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
474
|
+
const attr = this.isAttribute(key);
|
|
475
|
+
if (attr) {
|
|
476
|
+
const val = obj[key];
|
|
477
|
+
if (val === true && this.options.suppressBooleanAttributes) {
|
|
478
|
+
attrStr += ' ' + attr;
|
|
479
|
+
} else {
|
|
480
|
+
attrStr += ' ' + attr + '="' + val + '"'; // No encoding for stopNode
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return attrStr;
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
Builder.prototype.buildObjectNode = function (val, key, attrStr, level) {
|
|
490
|
+
if (val === "") {
|
|
491
|
+
if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
|
492
|
+
else {
|
|
493
|
+
return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
|
|
494
|
+
}
|
|
495
|
+
} else if (key[0] === "?") {
|
|
496
|
+
// PI/XML-declaration tags never have body content — treat them like empty.
|
|
497
|
+
return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
|
498
|
+
} else {
|
|
499
|
+
let tagEndExp = '</' + key + this.tagEndChar;
|
|
500
|
+
let piClosingChar = "";
|
|
501
|
+
|
|
502
|
+
if (key[0] === "?") {
|
|
503
|
+
piClosingChar = "?";
|
|
504
|
+
tagEndExp = "";
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// attrStr is an empty string in case the attribute came as undefined or null
|
|
508
|
+
if ((attrStr || attrStr === '') && val.indexOf('<') === -1) {
|
|
509
|
+
return (this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp);
|
|
510
|
+
} else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) {
|
|
511
|
+
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
|
512
|
+
} else {
|
|
513
|
+
return (
|
|
514
|
+
this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
|
|
515
|
+
val +
|
|
516
|
+
this.indentate(level) + tagEndExp);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
Builder.prototype.closeTag = function (key) {
|
|
522
|
+
let closeTag = "";
|
|
523
|
+
if (this.options.unpairedTags.indexOf(key) !== -1) { //unpaired
|
|
524
|
+
if (!this.options.suppressUnpairedNode) closeTag = "/"
|
|
525
|
+
} else if (this.options.suppressEmptyNode) { //empty
|
|
526
|
+
closeTag = "/";
|
|
527
|
+
} else {
|
|
528
|
+
closeTag = `></${key}`
|
|
529
|
+
}
|
|
530
|
+
return closeTag;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
Builder.prototype.checkStopNode = function (matcher) {
|
|
534
|
+
if (!this.stopNodeExpressions || this.stopNodeExpressions.length === 0) return false;
|
|
535
|
+
|
|
536
|
+
for (let i = 0; i < this.stopNodeExpressions.length; i++) {
|
|
537
|
+
if (matcher.matches(this.stopNodeExpressions[i])) {
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function buildEmptyObjNode(val, key, attrStr, level) {
|
|
545
|
+
if (val !== '') {
|
|
546
|
+
return this.buildObjectNode(val, key, attrStr, level);
|
|
547
|
+
} else {
|
|
548
|
+
if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
|
549
|
+
else {
|
|
550
|
+
return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
Builder.prototype.buildTextValNode = function (val, key, attrStr, level, matcher) {
|
|
556
|
+
if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
|
|
557
|
+
const safeVal = safeCdata(val);
|
|
558
|
+
return this.indentate(level) + `<![CDATA[${safeVal}]]>` + this.newLine;
|
|
559
|
+
} else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
|
|
560
|
+
const safeVal = safeComment(val);
|
|
561
|
+
return this.indentate(level) + `<!--${safeVal}-->` + this.newLine;
|
|
562
|
+
} else if (key[0] === "?") {//PI tag
|
|
563
|
+
return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
|
564
|
+
} else {
|
|
565
|
+
// Normal processing: apply tagValueProcessor and entity replacement
|
|
566
|
+
let textValue = this.options.tagValueProcessor(key, val);
|
|
567
|
+
textValue = this.replaceEntitiesValue(textValue);
|
|
568
|
+
|
|
569
|
+
if (textValue === '') {
|
|
570
|
+
return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
|
|
571
|
+
} else {
|
|
572
|
+
return this.indentate(level) + '<' + key + attrStr + '>' +
|
|
573
|
+
textValue +
|
|
574
|
+
'</' + key + this.tagEndChar;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
Builder.prototype.replaceEntitiesValue = function (textValue) {
|
|
580
|
+
if (textValue && textValue.length > 0 && this.options.processEntities) {
|
|
581
|
+
for (let i = 0; i < this.options.entities.length; i++) {
|
|
582
|
+
const entity = this.options.entities[i];
|
|
583
|
+
textValue = textValue.replace(entity.regex, entity.val);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return textValue;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function indentate(level) {
|
|
590
|
+
return this.options.indentBy.repeat(level);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function isAttribute(name /*, options*/) {
|
|
594
|
+
if (name.startsWith(this.options.attributeNamePrefix) && name !== this.options.textNodeName) {
|
|
595
|
+
return name.substr(this.attrPrefixLen);
|
|
596
|
+
} else {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default function getIgnoreAttributesFn(ignoreAttributes) {
|
|
2
|
+
if (typeof ignoreAttributes === 'function') {
|
|
3
|
+
return ignoreAttributes
|
|
4
|
+
}
|
|
5
|
+
if (Array.isArray(ignoreAttributes)) {
|
|
6
|
+
return (attrName) => {
|
|
7
|
+
for (const pattern of ignoreAttributes) {
|
|
8
|
+
if (typeof pattern === 'string' && attrName === pattern) {
|
|
9
|
+
return true
|
|
10
|
+
}
|
|
11
|
+
if (pattern instanceof RegExp && pattern.test(attrName)) {
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return () => false
|
|
18
|
+
}
|