@jjrawlins/cdk-diff-pr-github-action 1.9.6 → 1.9.8
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 +4 -4
- package/cdkdiffprgithubaction/go.mod +1 -1
- package/cdkdiffprgithubaction/jsii/jsii.go +2 -2
- package/cdkdiffprgithubaction/version +1 -1
- package/lib/CdkDiffIamTemplate.js +2 -2
- package/lib/CdkDiffIamTemplateStackSet.js +2 -2
- package/lib/CdkDiffStackWorkflow.js +1 -1
- package/lib/CdkDriftDetectionWorkflow.js +1 -1
- package/lib/CdkDriftIamTemplate.js +2 -2
- package/node_modules/@aws-sdk/client-cloudformation/package.json +12 -12
- package/node_modules/@aws-sdk/core/dist-cjs/index.js +4 -0
- package/node_modules/@aws-sdk/core/dist-cjs/submodules/protocols/index.js +4 -0
- package/node_modules/@aws-sdk/core/dist-es/submodules/protocols/index.js +2 -0
- package/node_modules/@aws-sdk/core/dist-es/submodules/protocols/query/AwsEc2QueryProtocol.js +3 -0
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/index.d.ts +2 -0
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/query/AwsEc2QueryProtocol.d.ts +4 -0
- package/node_modules/@aws-sdk/core/dist-types/submodules/protocols/query/QuerySerializerSettings.d.ts +3 -0
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/index.d.ts +2 -0
- package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/protocols/query/AwsEc2QueryProtocol.d.ts +1 -0
- package/node_modules/@aws-sdk/core/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
- package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
- package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
- package/node_modules/@aws-sdk/middleware-user-agent/package.json +3 -3
- package/node_modules/@aws-sdk/nested-clients/package.json +10 -10
- package/node_modules/@aws-sdk/token-providers/package.json +3 -3
- package/node_modules/@aws-sdk/util-user-agent-node/package.json +2 -2
- package/node_modules/@smithy/util-waiter/dist-cjs/index.js +1 -1
- package/node_modules/@smithy/util-waiter/dist-es/poller.js +1 -1
- package/node_modules/@smithy/util-waiter/package.json +1 -1
- package/node_modules/fast-xml-builder/README.md +1 -1
- package/node_modules/fast-xml-builder/lib/fxb.cjs +1 -0
- package/node_modules/fast-xml-builder/lib/fxb.d.cts +6 -1
- 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 +7 -5
- package/node_modules/fast-xml-builder/src/fxb.d.ts +8 -2
- package/node_modules/fast-xml-builder/src/fxb.js +262 -21
- package/node_modules/fast-xml-builder/src/orderedJs2Xml.js +161 -18
- package/node_modules/path-expression-matcher/LICENSE +21 -0
- package/node_modules/path-expression-matcher/README.md +635 -0
- package/node_modules/path-expression-matcher/package.json +52 -0
- package/node_modules/path-expression-matcher/src/Expression.js +232 -0
- package/node_modules/path-expression-matcher/src/Matcher.js +414 -0
- package/node_modules/path-expression-matcher/src/index.js +28 -0
- package/package.json +3 -3
- package/node_modules/fast-xml-builder/lib/builder.cjs +0 -1
- package/node_modules/fast-xml-builder/lib/builder.min.js +0 -2
- package/node_modules/fast-xml-builder/lib/builder.min.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-xml-builder",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Build XML from JSON without C/C++ based libraries",
|
|
5
5
|
"main": "./lib/fxb.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -59,14 +59,14 @@
|
|
|
59
59
|
"babel-loader": "^8.2.2",
|
|
60
60
|
"c8": "^10.1.3",
|
|
61
61
|
"eslint": "^8.3.0",
|
|
62
|
+
"fast-xml-parser": "^5.3.9",
|
|
63
|
+
"he": "^1.2.0",
|
|
62
64
|
"jasmine": "^5.6.0",
|
|
63
65
|
"prettier": "^3.5.1",
|
|
64
66
|
"publish-please": "^5.5.2",
|
|
65
67
|
"typescript": "5",
|
|
66
68
|
"webpack": "^5.64.4",
|
|
67
|
-
"webpack-cli": "^4.9.1"
|
|
68
|
-
"fast-xml-parser": "^5.3.9",
|
|
69
|
-
"he": "^1.2.0"
|
|
69
|
+
"webpack-cli": "^4.9.1"
|
|
70
70
|
},
|
|
71
71
|
"funding": [
|
|
72
72
|
{
|
|
@@ -74,5 +74,7 @@
|
|
|
74
74
|
"url": "https://github.com/sponsors/NaturalIntelligence"
|
|
75
75
|
}
|
|
76
76
|
],
|
|
77
|
-
"dependencies": {
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"path-expression-matcher": "^1.1.2"
|
|
79
|
+
}
|
|
78
80
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Expression } from 'path-expression-matcher';
|
|
2
|
+
|
|
1
3
|
export type XmlBuilderOptions = {
|
|
2
4
|
/**
|
|
3
5
|
* Give a prefix to the attribute name in the resulting JS object
|
|
@@ -109,9 +111,13 @@ export type XmlBuilderOptions = {
|
|
|
109
111
|
/**
|
|
110
112
|
* Nodes to stop parsing at
|
|
111
113
|
*
|
|
114
|
+
* Accepts string patterns or Expression objects from path-expression-matcher
|
|
115
|
+
*
|
|
116
|
+
* String patterns starting with "*." are automatically converted to ".." for backward compatibility
|
|
117
|
+
*
|
|
112
118
|
* Defaults to `[]`
|
|
113
119
|
*/
|
|
114
|
-
stopNodes?: string[];
|
|
120
|
+
stopNodes?: (string | Expression)[];
|
|
115
121
|
|
|
116
122
|
/**
|
|
117
123
|
* Control how tag value should be parsed. Called only if tag value is not empty
|
|
@@ -153,4 +159,4 @@ export type XmlBuilderOptions = {
|
|
|
153
159
|
export class XMLBuilder {
|
|
154
160
|
constructor(options?: XmlBuilderOptions);
|
|
155
161
|
build(jObj: any): string;
|
|
156
|
-
}
|
|
162
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
//parse Empty Node as self closing node
|
|
3
3
|
import buildFromOrderedJs from './orderedJs2Xml.js';
|
|
4
4
|
import getIgnoreAttributesFn from "./ignoreAttributes.js";
|
|
5
|
+
import { Expression, Matcher } from 'path-expression-matcher';
|
|
5
6
|
|
|
6
7
|
const defaultOptions = {
|
|
7
8
|
attributeNamePrefix: '@_',
|
|
@@ -34,11 +35,39 @@ const defaultOptions = {
|
|
|
34
35
|
stopNodes: [],
|
|
35
36
|
// transformTagName: false,
|
|
36
37
|
// transformAttributeName: false,
|
|
37
|
-
oneListGroup: false
|
|
38
|
+
oneListGroup: false,
|
|
39
|
+
jPath: true // When true, callbacks receive string jPath; when false, receive Matcher instance
|
|
38
40
|
};
|
|
39
41
|
|
|
40
42
|
export default function Builder(options) {
|
|
41
43
|
this.options = Object.assign({}, defaultOptions, options);
|
|
44
|
+
|
|
45
|
+
// Convert old-style stopNodes for backward compatibility
|
|
46
|
+
// Old syntax: "*.tag" meant "tag anywhere in tree"
|
|
47
|
+
// New syntax: "..tag" means "tag anywhere in tree"
|
|
48
|
+
if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
|
|
49
|
+
this.options.stopNodes = this.options.stopNodes.map(node => {
|
|
50
|
+
if (typeof node === 'string' && node.startsWith('*.')) {
|
|
51
|
+
// Convert old wildcard syntax to deep wildcard
|
|
52
|
+
return '..' + node.substring(2);
|
|
53
|
+
}
|
|
54
|
+
return node;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Pre-compile stopNode expressions for pattern matching
|
|
59
|
+
this.stopNodeExpressions = [];
|
|
60
|
+
if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) {
|
|
61
|
+
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
|
62
|
+
const node = this.options.stopNodes[i];
|
|
63
|
+
if (typeof node === 'string') {
|
|
64
|
+
this.stopNodeExpressions.push(new Expression(node));
|
|
65
|
+
} else if (node instanceof Expression) {
|
|
66
|
+
this.stopNodeExpressions.push(node);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
42
71
|
if (this.options.ignoreAttributes === true || this.options.attributesGroupName) {
|
|
43
72
|
this.isAttribute = function (/*a*/) {
|
|
44
73
|
return false;
|
|
@@ -73,14 +102,22 @@ Builder.prototype.build = function (jObj) {
|
|
|
73
102
|
[this.options.arrayNodeName]: jObj
|
|
74
103
|
}
|
|
75
104
|
}
|
|
76
|
-
|
|
105
|
+
// Initialize matcher for path tracking
|
|
106
|
+
const matcher = new Matcher();
|
|
107
|
+
return this.j2x(jObj, 0, matcher).val;
|
|
77
108
|
}
|
|
78
109
|
};
|
|
79
110
|
|
|
80
|
-
Builder.prototype.j2x = function (jObj, level,
|
|
111
|
+
Builder.prototype.j2x = function (jObj, level, matcher) {
|
|
81
112
|
let attrStr = '';
|
|
82
113
|
let val = '';
|
|
83
|
-
|
|
114
|
+
|
|
115
|
+
// Get jPath based on option: string for backward compatibility, or Matcher for new features
|
|
116
|
+
const jPath = this.options.jPath ? matcher.toString() : matcher;
|
|
117
|
+
|
|
118
|
+
// Check if current node is a stopNode (will be used for attribute encoding)
|
|
119
|
+
const isCurrentStopNode = this.checkStopNode(matcher);
|
|
120
|
+
|
|
84
121
|
for (let key in jObj) {
|
|
85
122
|
if (!Object.prototype.hasOwnProperty.call(jObj, key)) continue;
|
|
86
123
|
if (typeof jObj[key] === 'undefined') {
|
|
@@ -101,19 +138,34 @@ Builder.prototype.j2x = function (jObj, level, ajPath) {
|
|
|
101
138
|
}
|
|
102
139
|
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
103
140
|
} else if (jObj[key] instanceof Date) {
|
|
104
|
-
val += this.buildTextValNode(jObj[key], key, '', level);
|
|
141
|
+
val += this.buildTextValNode(jObj[key], key, '', level, matcher);
|
|
105
142
|
} else if (typeof jObj[key] !== 'object') {
|
|
106
143
|
//premitive type
|
|
107
144
|
const attr = this.isAttribute(key);
|
|
108
145
|
if (attr && !this.ignoreAttributesFn(attr, jPath)) {
|
|
109
|
-
attrStr += this.buildAttrPairStr(attr, '' + jObj[key]);
|
|
146
|
+
attrStr += this.buildAttrPairStr(attr, '' + jObj[key], isCurrentStopNode);
|
|
110
147
|
} else if (!attr) {
|
|
111
148
|
//tag value
|
|
112
149
|
if (key === this.options.textNodeName) {
|
|
113
150
|
let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
|
|
114
151
|
val += this.replaceEntitiesValue(newval);
|
|
115
152
|
} else {
|
|
116
|
-
|
|
153
|
+
// Check if this is a stopNode before building
|
|
154
|
+
matcher.push(key);
|
|
155
|
+
const isStopNode = this.checkStopNode(matcher);
|
|
156
|
+
matcher.pop();
|
|
157
|
+
|
|
158
|
+
if (isStopNode) {
|
|
159
|
+
// Build as raw content without encoding
|
|
160
|
+
const textValue = '' + jObj[key];
|
|
161
|
+
if (textValue === '') {
|
|
162
|
+
val += this.indentate(level) + '<' + key + this.closeTag(key) + this.tagEndChar;
|
|
163
|
+
} else {
|
|
164
|
+
val += this.indentate(level) + '<' + key + '>' + textValue + '</' + key + this.tagEndChar;
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
val += this.buildTextValNode(jObj[key], key, '', level, matcher);
|
|
168
|
+
}
|
|
117
169
|
}
|
|
118
170
|
}
|
|
119
171
|
} else if (Array.isArray(jObj[key])) {
|
|
@@ -131,13 +183,18 @@ Builder.prototype.j2x = function (jObj, level, ajPath) {
|
|
|
131
183
|
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
132
184
|
} else if (typeof item === 'object') {
|
|
133
185
|
if (this.options.oneListGroup) {
|
|
134
|
-
|
|
186
|
+
// Push tag to matcher before recursive call
|
|
187
|
+
matcher.push(key);
|
|
188
|
+
const result = this.j2x(item, level + 1, matcher);
|
|
189
|
+
// Pop tag from matcher after recursive call
|
|
190
|
+
matcher.pop();
|
|
191
|
+
|
|
135
192
|
listTagVal += result.val;
|
|
136
193
|
if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) {
|
|
137
194
|
listTagAttr += result.attrStr
|
|
138
195
|
}
|
|
139
196
|
} else {
|
|
140
|
-
listTagVal += this.processTextOrObjNode(item, key, level,
|
|
197
|
+
listTagVal += this.processTextOrObjNode(item, key, level, matcher)
|
|
141
198
|
}
|
|
142
199
|
} else {
|
|
143
200
|
if (this.options.oneListGroup) {
|
|
@@ -145,7 +202,22 @@ Builder.prototype.j2x = function (jObj, level, ajPath) {
|
|
|
145
202
|
textValue = this.replaceEntitiesValue(textValue);
|
|
146
203
|
listTagVal += textValue;
|
|
147
204
|
} else {
|
|
148
|
-
|
|
205
|
+
// Check if this is a stopNode before building
|
|
206
|
+
matcher.push(key);
|
|
207
|
+
const isStopNode = this.checkStopNode(matcher);
|
|
208
|
+
matcher.pop();
|
|
209
|
+
|
|
210
|
+
if (isStopNode) {
|
|
211
|
+
// Build as raw content without encoding
|
|
212
|
+
const textValue = '' + item;
|
|
213
|
+
if (textValue === '') {
|
|
214
|
+
listTagVal += this.indentate(level) + '<' + key + this.closeTag(key) + this.tagEndChar;
|
|
215
|
+
} else {
|
|
216
|
+
listTagVal += this.indentate(level) + '<' + key + '>' + textValue + '</' + key + this.tagEndChar;
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
listTagVal += this.buildTextValNode(item, key, '', level, matcher);
|
|
220
|
+
}
|
|
149
221
|
}
|
|
150
222
|
}
|
|
151
223
|
}
|
|
@@ -159,33 +231,191 @@ Builder.prototype.j2x = function (jObj, level, ajPath) {
|
|
|
159
231
|
const Ks = Object.keys(jObj[key]);
|
|
160
232
|
const L = Ks.length;
|
|
161
233
|
for (let j = 0; j < L; j++) {
|
|
162
|
-
attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]]);
|
|
234
|
+
attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]], isCurrentStopNode);
|
|
163
235
|
}
|
|
164
236
|
} else {
|
|
165
|
-
val += this.processTextOrObjNode(jObj[key], key, level,
|
|
237
|
+
val += this.processTextOrObjNode(jObj[key], key, level, matcher)
|
|
166
238
|
}
|
|
167
239
|
}
|
|
168
240
|
}
|
|
169
241
|
return { attrStr: attrStr, val: val };
|
|
170
242
|
};
|
|
171
243
|
|
|
172
|
-
Builder.prototype.buildAttrPairStr = function (attrName, val) {
|
|
173
|
-
|
|
174
|
-
|
|
244
|
+
Builder.prototype.buildAttrPairStr = function (attrName, val, isStopNode) {
|
|
245
|
+
if (!isStopNode) {
|
|
246
|
+
val = this.options.attributeValueProcessor(attrName, '' + val);
|
|
247
|
+
val = this.replaceEntitiesValue(val);
|
|
248
|
+
}
|
|
175
249
|
if (this.options.suppressBooleanAttributes && val === "true") {
|
|
176
250
|
return ' ' + attrName;
|
|
177
251
|
} else return ' ' + attrName + '="' + val + '"';
|
|
178
252
|
}
|
|
179
253
|
|
|
180
|
-
function processTextOrObjNode(object, key, level,
|
|
181
|
-
|
|
254
|
+
function processTextOrObjNode(object, key, level, matcher) {
|
|
255
|
+
// Extract attributes to pass to matcher
|
|
256
|
+
const attrValues = this.extractAttributes(object);
|
|
257
|
+
|
|
258
|
+
// Push tag to matcher before recursion WITH attributes
|
|
259
|
+
matcher.push(key, attrValues);
|
|
260
|
+
|
|
261
|
+
// Check if this entire node is a stopNode
|
|
262
|
+
const isStopNode = this.checkStopNode(matcher);
|
|
263
|
+
|
|
264
|
+
if (isStopNode) {
|
|
265
|
+
// For stopNodes, build raw content without entity encoding
|
|
266
|
+
const rawContent = this.buildRawContent(object);
|
|
267
|
+
const attrStr = this.buildAttributesForStopNode(object);
|
|
268
|
+
matcher.pop();
|
|
269
|
+
return this.buildObjectNode(rawContent, key, attrStr, level);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const result = this.j2x(object, level + 1, matcher);
|
|
273
|
+
// Pop tag from matcher after recursion
|
|
274
|
+
matcher.pop();
|
|
275
|
+
|
|
182
276
|
if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
|
183
|
-
return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level);
|
|
277
|
+
return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level, matcher);
|
|
184
278
|
} else {
|
|
185
279
|
return this.buildObjectNode(result.val, key, result.attrStr, level);
|
|
186
280
|
}
|
|
187
281
|
}
|
|
188
282
|
|
|
283
|
+
// Helper method to extract attributes from an object
|
|
284
|
+
Builder.prototype.extractAttributes = function (obj) {
|
|
285
|
+
if (!obj || typeof obj !== 'object') return null;
|
|
286
|
+
|
|
287
|
+
const attrValues = {};
|
|
288
|
+
let hasAttrs = false;
|
|
289
|
+
|
|
290
|
+
// Check for attributesGroupName (when attributes are grouped)
|
|
291
|
+
if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
|
|
292
|
+
const attrGroup = obj[this.options.attributesGroupName];
|
|
293
|
+
for (let attrKey in attrGroup) {
|
|
294
|
+
if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
|
|
295
|
+
// Remove attribute prefix if present
|
|
296
|
+
const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
|
|
297
|
+
? attrKey.substring(this.options.attributeNamePrefix.length)
|
|
298
|
+
: attrKey;
|
|
299
|
+
attrValues[cleanKey] = attrGroup[attrKey];
|
|
300
|
+
hasAttrs = true;
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
// Look for individual attributes (prefixed with attributeNamePrefix)
|
|
304
|
+
for (let key in obj) {
|
|
305
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
306
|
+
const attr = this.isAttribute(key);
|
|
307
|
+
if (attr) {
|
|
308
|
+
attrValues[attr] = obj[key];
|
|
309
|
+
hasAttrs = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return hasAttrs ? attrValues : null;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// Build raw content for stopNode without entity encoding
|
|
318
|
+
Builder.prototype.buildRawContent = function (obj) {
|
|
319
|
+
if (typeof obj === 'string') {
|
|
320
|
+
return obj; // Already a string, return as-is
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
324
|
+
return String(obj);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Check if this is a stopNode data from parser: { "#text": "raw xml", "@_attr": "val" }
|
|
328
|
+
if (obj[this.options.textNodeName] !== undefined) {
|
|
329
|
+
return obj[this.options.textNodeName]; // Return raw text without encoding
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Build raw XML from nested structure
|
|
333
|
+
let content = '';
|
|
334
|
+
|
|
335
|
+
for (let key in obj) {
|
|
336
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
337
|
+
|
|
338
|
+
// Skip attributes
|
|
339
|
+
if (this.isAttribute(key)) continue;
|
|
340
|
+
if (this.options.attributesGroupName && key === this.options.attributesGroupName) continue;
|
|
341
|
+
|
|
342
|
+
const value = obj[key];
|
|
343
|
+
|
|
344
|
+
if (key === this.options.textNodeName) {
|
|
345
|
+
content += value; // Raw text
|
|
346
|
+
} else if (Array.isArray(value)) {
|
|
347
|
+
// Array of same tag
|
|
348
|
+
for (let item of value) {
|
|
349
|
+
if (typeof item === 'string' || typeof item === 'number') {
|
|
350
|
+
content += `<${key}>${item}</${key}>`;
|
|
351
|
+
} else if (typeof item === 'object' && item !== null) {
|
|
352
|
+
const nestedContent = this.buildRawContent(item);
|
|
353
|
+
const nestedAttrs = this.buildAttributesForStopNode(item);
|
|
354
|
+
if (nestedContent === '') {
|
|
355
|
+
content += `<${key}${nestedAttrs}/>`;
|
|
356
|
+
} else {
|
|
357
|
+
content += `<${key}${nestedAttrs}>${nestedContent}</${key}>`;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
362
|
+
// Nested object
|
|
363
|
+
const nestedContent = this.buildRawContent(value);
|
|
364
|
+
const nestedAttrs = this.buildAttributesForStopNode(value);
|
|
365
|
+
if (nestedContent === '') {
|
|
366
|
+
content += `<${key}${nestedAttrs}/>`;
|
|
367
|
+
} else {
|
|
368
|
+
content += `<${key}${nestedAttrs}>${nestedContent}</${key}>`;
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
// Primitive value
|
|
372
|
+
content += `<${key}>${value}</${key}>`;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return content;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// Build attribute string for stopNode (no entity encoding)
|
|
380
|
+
Builder.prototype.buildAttributesForStopNode = function (obj) {
|
|
381
|
+
if (!obj || typeof obj !== 'object') return '';
|
|
382
|
+
|
|
383
|
+
let attrStr = '';
|
|
384
|
+
|
|
385
|
+
// Check for attributesGroupName (when attributes are grouped)
|
|
386
|
+
if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) {
|
|
387
|
+
const attrGroup = obj[this.options.attributesGroupName];
|
|
388
|
+
for (let attrKey in attrGroup) {
|
|
389
|
+
if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue;
|
|
390
|
+
const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix)
|
|
391
|
+
? attrKey.substring(this.options.attributeNamePrefix.length)
|
|
392
|
+
: attrKey;
|
|
393
|
+
const val = attrGroup[attrKey];
|
|
394
|
+
if (val === true && this.options.suppressBooleanAttributes) {
|
|
395
|
+
attrStr += ' ' + cleanKey;
|
|
396
|
+
} else {
|
|
397
|
+
attrStr += ' ' + cleanKey + '="' + val + '"'; // No encoding for stopNode
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
// Look for individual attributes
|
|
402
|
+
for (let key in obj) {
|
|
403
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
|
|
404
|
+
const attr = this.isAttribute(key);
|
|
405
|
+
if (attr) {
|
|
406
|
+
const val = obj[key];
|
|
407
|
+
if (val === true && this.options.suppressBooleanAttributes) {
|
|
408
|
+
attrStr += ' ' + attr;
|
|
409
|
+
} else {
|
|
410
|
+
attrStr += ' ' + attr + '="' + val + '"'; // No encoding for stopNode
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return attrStr;
|
|
417
|
+
};
|
|
418
|
+
|
|
189
419
|
Builder.prototype.buildObjectNode = function (val, key, attrStr, level) {
|
|
190
420
|
if (val === "") {
|
|
191
421
|
if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
|
@@ -228,6 +458,17 @@ Builder.prototype.closeTag = function (key) {
|
|
|
228
458
|
return closeTag;
|
|
229
459
|
}
|
|
230
460
|
|
|
461
|
+
Builder.prototype.checkStopNode = function (matcher) {
|
|
462
|
+
if (!this.stopNodeExpressions || this.stopNodeExpressions.length === 0) return false;
|
|
463
|
+
|
|
464
|
+
for (let i = 0; i < this.stopNodeExpressions.length; i++) {
|
|
465
|
+
if (matcher.matches(this.stopNodeExpressions[i])) {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
|
|
231
472
|
function buildEmptyObjNode(val, key, attrStr, level) {
|
|
232
473
|
if (val !== '') {
|
|
233
474
|
return this.buildObjectNode(val, key, attrStr, level);
|
|
@@ -240,7 +481,7 @@ function buildEmptyObjNode(val, key, attrStr, level) {
|
|
|
240
481
|
}
|
|
241
482
|
}
|
|
242
483
|
|
|
243
|
-
Builder.prototype.buildTextValNode = function (val, key, attrStr, level) {
|
|
484
|
+
Builder.prototype.buildTextValNode = function (val, key, attrStr, level, matcher) {
|
|
244
485
|
if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
|
|
245
486
|
return this.indentate(level) + `<![CDATA[${val}]]>` + this.newLine;
|
|
246
487
|
} else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
|
|
@@ -248,6 +489,7 @@ Builder.prototype.buildTextValNode = function (val, key, attrStr, level) {
|
|
|
248
489
|
} else if (key[0] === "?") {//PI tag
|
|
249
490
|
return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar;
|
|
250
491
|
} else {
|
|
492
|
+
// Normal processing: apply tagValueProcessor and entity replacement
|
|
251
493
|
let textValue = this.options.tagValueProcessor(key, val);
|
|
252
494
|
textValue = this.replaceEntitiesValue(textValue);
|
|
253
495
|
|
|
@@ -281,5 +523,4 @@ function isAttribute(name /*, options*/) {
|
|
|
281
523
|
} else {
|
|
282
524
|
return false;
|
|
283
525
|
}
|
|
284
|
-
}
|
|
285
|
-
|
|
526
|
+
}
|