@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.
Files changed (135) hide show
  1. package/.jsii +41 -41
  2. package/CHANGELOG.md +14 -0
  3. package/assets/cli/catnip.js +154 -166
  4. package/lib/constructs/EventPipe.js +1 -1
  5. package/lib/constructs/ExportedService.js +1 -1
  6. package/lib/constructs/S3Bucket.js +1 -1
  7. package/lib/constructs/SecureRestApi.js +1 -1
  8. package/lib/constructs/SecureRestApiV2.js +1 -1
  9. package/lib/constructs/api-keys/ApiKeyClientAuthorization.js +1 -1
  10. package/lib/constructs/api-keys/ApiKeyManagement.js +1 -1
  11. package/lib/constructs/api-keys/ApiKeyPreTokenHandler.js +1 -1
  12. package/lib/constructs/api-keys/ApiKeyStore.js +1 -1
  13. package/lib/extensions/ApiGatewayExtension.js +1 -1
  14. package/lib/extensions/ApplicationContainer.js +1 -1
  15. package/lib/extensions/ApplicationLoadBalancerExtension.js +1 -1
  16. package/lib/extensions/ApplicationLoadBalancerExtensionV2.js +1 -1
  17. package/lib/extensions/CloudMapExtension.js +1 -1
  18. package/lib/extensions/DeactivatableServiceExtension.js +1 -1
  19. package/lib/extensions/DeploymentConfigExtension.js +1 -1
  20. package/lib/extensions/DocumentDbAccessExtension.js +1 -1
  21. package/lib/extensions/DomainEventMessagingExtension.js +1 -1
  22. package/lib/extensions/EfsMountExtension.js +1 -1
  23. package/lib/extensions/ExtraContainerExtension.js +1 -1
  24. package/lib/extensions/HTTPApiExtension.js +1 -1
  25. package/lib/extensions/LogExtension.js +1 -1
  26. package/lib/extensions/ModifyContainerDefinitionExtension.js +1 -1
  27. package/lib/extensions/ModifyTaskDefinitionExtension.js +1 -1
  28. package/lib/extensions/OpenIdExtension.js +1 -1
  29. package/lib/extensions/OpenTelemetryExtension.js +1 -1
  30. package/lib/extensions/PostgresDbAccessExtension.js +1 -1
  31. package/lib/extensions/SharedVolumeExtension.js +1 -1
  32. package/lib/extensions/TcpKeepAliveExtension.js +1 -1
  33. package/lib/platform/ApiGateway.js +1 -1
  34. package/lib/platform/ApiGatewayVpcLink.js +2 -2
  35. package/lib/platform/ApplicationLoadBalancer.js +1 -1
  36. package/lib/platform/ApplicationLoadBalancerV2.d.ts +1 -0
  37. package/lib/platform/ApplicationLoadBalancerV2.js +10 -3
  38. package/lib/platform/AuroraPostgresDB.js +5 -4
  39. package/lib/platform/BTCLogGroup.js +1 -1
  40. package/lib/platform/CognitoUserPool.js +2 -2
  41. package/lib/platform/DefaultUserPoolClients.js +1 -1
  42. package/lib/platform/DocumentDB.js +2 -2
  43. package/lib/platform/EcsCluster.js +1 -1
  44. package/lib/platform/EfsFileSystem.js +1 -1
  45. package/lib/platform/HostedZone.js +1 -1
  46. package/lib/platform/PrivateDnsNamespace.js +1 -1
  47. package/lib/platform/ResourceServer.js +1 -1
  48. package/lib/platform/Vpc.js +1 -1
  49. package/lib/platform/VpcV2.js +1 -1
  50. package/lib/stacks/ApplicationStack.js +1 -1
  51. package/lib/utils/BasePlatformStackResolver.js +1 -1
  52. package/lib/utils/StackParameter.js +1 -1
  53. package/node_modules/@nodable/entities/README.md +41 -0
  54. package/node_modules/@nodable/entities/package.json +54 -0
  55. package/node_modules/@nodable/entities/src/EntityDecoder.js +543 -0
  56. package/node_modules/@nodable/entities/src/EntityEncoder.js +194 -0
  57. package/node_modules/@nodable/entities/src/entities.js +1177 -0
  58. package/node_modules/@nodable/entities/src/entityTries.js +49 -0
  59. package/node_modules/@nodable/entities/src/index.d.ts +264 -0
  60. package/node_modules/@nodable/entities/src/index.js +29 -0
  61. package/node_modules/fast-xml-builder/CHANGELOG.md +40 -0
  62. package/node_modules/fast-xml-builder/LICENSE +21 -0
  63. package/node_modules/fast-xml-builder/README.md +74 -0
  64. package/node_modules/fast-xml-builder/lib/fxb.cjs +1 -0
  65. package/node_modules/fast-xml-builder/lib/fxb.d.cts +270 -0
  66. package/node_modules/fast-xml-builder/lib/fxb.min.js +2 -0
  67. package/node_modules/fast-xml-builder/lib/fxb.min.js.map +1 -0
  68. package/node_modules/fast-xml-builder/package.json +81 -0
  69. package/node_modules/fast-xml-builder/src/fxb.d.ts +270 -0
  70. package/node_modules/fast-xml-builder/src/fxb.js +599 -0
  71. package/node_modules/fast-xml-builder/src/ignoreAttributes.js +18 -0
  72. package/node_modules/fast-xml-builder/src/orderedJs2Xml.js +359 -0
  73. package/node_modules/fast-xml-builder/src/util.js +16 -0
  74. package/node_modules/fast-xml-parser/CHANGELOG.md +165 -0
  75. package/node_modules/fast-xml-parser/README.md +21 -44
  76. package/node_modules/fast-xml-parser/lib/fxbuilder.min.js +1 -1
  77. package/node_modules/fast-xml-parser/lib/fxbuilder.min.js.map +1 -1
  78. package/node_modules/fast-xml-parser/lib/fxp.cjs +1 -1
  79. package/node_modules/fast-xml-parser/lib/fxp.d.cts +343 -31
  80. package/node_modules/fast-xml-parser/lib/fxp.min.js +1 -1
  81. package/node_modules/fast-xml-parser/lib/fxp.min.js.map +1 -1
  82. package/node_modules/fast-xml-parser/lib/fxparser.min.js +1 -1
  83. package/node_modules/fast-xml-parser/lib/fxparser.min.js.map +1 -1
  84. package/node_modules/fast-xml-parser/lib/fxvalidator.min.js +1 -1
  85. package/node_modules/fast-xml-parser/lib/fxvalidator.min.js.map +1 -1
  86. package/node_modules/fast-xml-parser/package.json +13 -8
  87. package/node_modules/fast-xml-parser/src/fxp.d.ts +335 -30
  88. package/node_modules/fast-xml-parser/src/fxp.js +1 -1
  89. package/node_modules/fast-xml-parser/src/util.js +18 -25
  90. package/node_modules/fast-xml-parser/src/v6/EntitiesParser.js +89 -87
  91. package/node_modules/fast-xml-parser/src/v6/OptionsBuilder.js +10 -10
  92. package/node_modules/fast-xml-parser/src/v6/OutputBuilders/BaseOutputBuilder.js +23 -23
  93. package/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsArrBuilder.js +29 -29
  94. package/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsMinArrBuilder.js +1 -1
  95. package/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsObjBuilder.js +39 -39
  96. package/node_modules/fast-xml-parser/src/v6/OutputBuilders/ParserOptionsBuilder.js +21 -21
  97. package/node_modules/fast-xml-parser/src/v6/XMLParser.js +22 -22
  98. package/node_modules/fast-xml-parser/src/v6/valueParsers/EntitiesParser.js +85 -85
  99. package/node_modules/fast-xml-parser/src/validator.js +34 -34
  100. package/node_modules/fast-xml-parser/src/xmlbuilder/json2xml.js +5 -284
  101. package/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js +335 -293
  102. package/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js +160 -43
  103. package/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js +540 -308
  104. package/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js +26 -26
  105. package/node_modules/fast-xml-parser/src/xmlparser/node2json.js +99 -41
  106. package/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js +10 -10
  107. package/node_modules/path-expression-matcher/LICENSE +21 -0
  108. package/node_modules/path-expression-matcher/README.md +872 -0
  109. package/node_modules/path-expression-matcher/lib/pem.cjs +1 -0
  110. package/node_modules/path-expression-matcher/lib/pem.d.cts +634 -0
  111. package/node_modules/path-expression-matcher/lib/pem.min.js +2 -0
  112. package/node_modules/path-expression-matcher/lib/pem.min.js.map +1 -0
  113. package/node_modules/path-expression-matcher/package.json +78 -0
  114. package/node_modules/path-expression-matcher/src/Expression.js +232 -0
  115. package/node_modules/path-expression-matcher/src/ExpressionSet.js +209 -0
  116. package/node_modules/path-expression-matcher/src/Matcher.js +570 -0
  117. package/node_modules/path-expression-matcher/src/index.d.ts +523 -0
  118. package/node_modules/path-expression-matcher/src/index.js +29 -0
  119. package/node_modules/strnum/CHANGELOG.md +12 -2
  120. package/node_modules/strnum/README.md +1 -0
  121. package/node_modules/strnum/package.json +5 -4
  122. package/node_modules/strnum/strnum.js +99 -65
  123. package/node_modules/xml-naming/README.md +189 -0
  124. package/node_modules/xml-naming/package.json +54 -0
  125. package/node_modules/xml-naming/src/index.d.ts +74 -0
  126. package/node_modules/xml-naming/src/index.js +270 -0
  127. package/package.json +3 -2
  128. package/renovate.json5 +1 -0
  129. package/node_modules/fast-xml-parser/src/xmlbuilder/orderedJs2Xml.js +0 -134
  130. package/node_modules/strnum/.github/SECURITY.md +0 -5
  131. package/node_modules/strnum/.vscode/launch.json +0 -25
  132. package/node_modules/strnum/algo.stflow +0 -84
  133. package/node_modules/strnum/strnum.test.js +0 -173
  134. package/node_modules/strnum/test.js +0 -9
  135. /package/node_modules/{fast-xml-parser/src/xmlbuilder → fast-xml-builder/src}/prettifyJs2Xml.js +0 -0
@@ -0,0 +1,49 @@
1
+ // entityTries.js
2
+ // Builds integer-keyed tries so the decoder never allocates a string object
3
+ // during lookup — every key is a plain charCode number.
4
+ //
5
+ // trie1: Map<code0, entity>
6
+ // trie2: Map<code0, Map<code1, entity>>
7
+ // trie3: Map<code0, Map<code1, Map<code2, entity>>>
8
+
9
+ import { ALL_ENTITIES } from './entities.js';
10
+
11
+ // Reverse map: character sequence → "&name;"
12
+ const CHAR_TO_ENTITY = new Map();
13
+ for (const [name, chars] of Object.entries(ALL_ENTITIES)) {
14
+ CHAR_TO_ENTITY.set(chars, `&${name};`);
15
+ }
16
+
17
+ export const trie1 = new Map(); // code0 → entity string
18
+ export const trie2 = new Map(); // code0 → Map → entity string
19
+ export const trie3 = new Map(); // code0 → Map → Map → entity string
20
+
21
+ for (const [chars, entity] of CHAR_TO_ENTITY) {
22
+ const len = chars.length;
23
+
24
+ if (len === 1) {
25
+ const c0 = chars.charCodeAt(0);
26
+ // Keep shortest match only if no longer match already claimed this code
27
+ // (longer matches are inserted in the same pass so we just overwrite —
28
+ // trie1 is only consulted after trie2/trie3 both miss, so no conflict)
29
+ trie1.set(c0, entity);
30
+
31
+ } else if (len === 2) {
32
+ const c0 = chars.charCodeAt(0);
33
+ const c1 = chars.charCodeAt(1);
34
+ let inner = trie2.get(c0);
35
+ if (inner === undefined) { inner = new Map(); trie2.set(c0, inner); }
36
+ inner.set(c1, entity);
37
+
38
+ } else if (len === 3) {
39
+ const c0 = chars.charCodeAt(0);
40
+ const c1 = chars.charCodeAt(1);
41
+ const c2 = chars.charCodeAt(2);
42
+ let mid = trie3.get(c0);
43
+ if (mid === undefined) { mid = new Map(); trie3.set(c0, mid); }
44
+ let inner = mid.get(c1);
45
+ if (inner === undefined) { inner = new Map(); mid.set(c1, inner); }
46
+ inner.set(c2, entity);
47
+ }
48
+ // HTML5 has no named entity whose character sequence is longer than 3 chars
49
+ }
@@ -0,0 +1,264 @@
1
+ // ---------------------------------------------------------------------------
2
+ // @nodable/entities — TypeScript declarations
3
+ // ---------------------------------------------------------------------------
4
+
5
+ /** A function-based entity replacement value (used for numeric refs). */
6
+ export type EntityValFn = (match: string, captured: string, ...rest: unknown[]) => string;
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Encoder options
10
+ // ---------------------------------------------------------------------------
11
+
12
+ export interface EntityEncoderOptions {
13
+ /**
14
+ * Whether to encode XML unsafe characters: `&`, `<`, `>`, `"`, `'`.
15
+ * @default true
16
+ */
17
+ encodeXmlSafe?: boolean;
18
+
19
+ /**
20
+ * Whether to encode non‑ASCII characters (e.g. `é` → `&eacute;`) using the
21
+ * built‑in named entity trie.
22
+ * @default true
23
+ */
24
+ encodeAllNamed?: boolean;
25
+
26
+ /**
27
+ * Maximum number of replacements performed **cumulatively** across all
28
+ * `encode()` calls. `0` means unlimited.
29
+ *
30
+ * Use `reset()` to reset the internal counter.
31
+ * @default 0
32
+ */
33
+ maxReplacements?: number;
34
+ }
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // EntityEncoder class
38
+ // ---------------------------------------------------------------------------
39
+
40
+ /**
41
+ * High‑performance encoder that replaces characters with XML/HTML entities.
42
+ *
43
+ * - Escapes XML unsafe characters (`&`, `<`, `>`, `"`, `'`) when `encodeXmlSafe` is true.
44
+ * - Replaces non‑ASCII characters (e.g. `é`, `©`) with named entities using
45
+ * a compact trie‑based lookup when `encodeAllNamed` is true.
46
+ * - Supports a cumulative replacement limit (`maxReplacements`) that persists
47
+ * across multiple `encode()` calls until `reset()` is called.
48
+ *
49
+ * @example
50
+ * const encoder = new EntityEncoder({ encodeXmlSafe: true, encodeAllNamed: true });
51
+ * encoder.encode('<foo>'); // "&lt;foo&gt;"
52
+ * encoder.encode('© 2025'); // "&copy; 2025"
53
+ *
54
+ * // With limit
55
+ * const limited = new EntityEncoder({ maxReplacements: 2 });
56
+ * limited.encode('<>&'); // "&lt;&gt;&" (third replacement omitted)
57
+ * limited.reset(); // reset counter
58
+ */
59
+ export class EntityEncoder {
60
+ constructor(options?: EntityEncoderOptions);
61
+
62
+ /**
63
+ * Encode a string by replacing XML‑unsafe characters and (optionally)
64
+ * non‑ASCII characters with named entities.
65
+ *
66
+ * If `maxReplacements` is set and the cumulative limit has been reached,
67
+ * the input string is returned unchanged.
68
+ *
69
+ * @returns Encoded string (may be identical to input if no replacements needed
70
+ * or the limit has been exhausted).
71
+ */
72
+ encode(str: string): string;
73
+
74
+ /**
75
+ * Reset the internal replacement counter.
76
+ * Does **not** change `encodeXmlSafe`, `encodeAllNamed`, or `maxReplacements`.
77
+ */
78
+ reset(): void;
79
+ }
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // Constructor options for EntityDecoder (existing)
83
+ // ---------------------------------------------------------------------------
84
+
85
+ /**
86
+ * Controls which entity categories count toward the expansion limits.
87
+ *
88
+ * - `'external'` — only untrusted / injected entities (default)
89
+ * - `'base'` — only built‑in XML entities + user‑supplied `namedEntities`
90
+ * - `'all'` — all entities regardless of tier
91
+ * - `string[]` — explicit combination, e.g. `['external', 'base']`
92
+ */
93
+ export type ApplyLimitsTo = 'external' | 'base' | 'all' | Array<'external' | 'base'>;
94
+
95
+ export interface EntityDecoderLimitOptions {
96
+ /**
97
+ * Maximum number of entity references expanded **per document**.
98
+ * `0` means unlimited.
99
+ * @default 0
100
+ */
101
+ maxTotalExpansions?: number;
102
+
103
+ /**
104
+ * Maximum number of characters **added** by entity expansion per document.
105
+ * `0` means unlimited.
106
+ * @default 0
107
+ */
108
+ maxExpandedLength?: number;
109
+
110
+ /**
111
+ * Which entity tiers count toward the expansion limits.
112
+ *
113
+ * - `'external'` (default) – only input/runtime + persistent external entities
114
+ * - `'base'` – only built‑in XML + `namedEntities`
115
+ * - `'all'` – every entity regardless of tier
116
+ * - `string[]` – explicit combination, e.g. `['external', 'base']`
117
+ *
118
+ * @default 'external'
119
+ */
120
+ applyLimitsTo?: ApplyLimitsTo;
121
+ }
122
+
123
+ export interface EntityDecoderNCROptions {
124
+ /**
125
+ * XML version used for NCR classification.
126
+ * @default 1.0
127
+ */
128
+ xmlVersion?: 1.0 | 1.1;
129
+
130
+ /**
131
+ * Base action for all numeric references.
132
+ * @default 'allow'
133
+ */
134
+ onNCR?: 'allow' | 'leave' | 'remove' | 'throw';
135
+
136
+ /**
137
+ * Action for null NCR (U+0000).
138
+ * @default 'remove'
139
+ */
140
+ nullNCR?: 'remove' | 'throw';
141
+ }
142
+
143
+ export interface EntityDecoderOptions {
144
+ /**
145
+ * Extra named entities merged into the **base map** (trusted, counts as `'base'` tier).
146
+ * These are combined with the built‑in XML entities (`lt`, `gt`, `quot`, `apos`).
147
+ * Values containing `&` are silently skipped to prevent recursive expansion.
148
+ *
149
+ * @default null
150
+ */
151
+ namedEntities?: Record<string, string | { regex: RegExp; val: string | EntityValFn }> | null;
152
+
153
+
154
+ /**
155
+ * Hook called once on the fully decoded string (after all replacements).
156
+ *
157
+ * - Receives `(resolved, original)` and **must return a string**.
158
+ * - To reject expansion, return `original`.
159
+ * - To sanitize, return a cleaned version of `resolved`.
160
+ *
161
+ * @example
162
+ * postCheck: (resolved, original) =>
163
+ * /<[a-z]/i.test(resolved) ? original : resolved
164
+ */
165
+ postCheck?: ((resolved: string, original: string) => string) | null;
166
+
167
+ /**
168
+ * Whether numeric character references (`&#NNN;`, `&#xHH;`) are allowed.
169
+ * @default true
170
+ */
171
+ numericAllowed?: boolean;
172
+
173
+ /**
174
+ * Array of entity names or numeric references to leave unexpanded.
175
+ * @default []
176
+ */
177
+ leave?: string[];
178
+
179
+ /**
180
+ * Array of entity names or numeric references to remove.
181
+ * @default []
182
+ */
183
+ remove?: string[];
184
+
185
+ /**
186
+ * Security limits for entity expansion.
187
+ */
188
+ limit?: EntityDecoderLimitOptions;
189
+
190
+ /**
191
+ * Numeric Character Reference (NCR) policy.
192
+ */
193
+ ncr?: EntityDecoderNCROptions;
194
+ }
195
+
196
+ // ---------------------------------------------------------------------------
197
+ // EntityDecoder class (default export)
198
+ // ---------------------------------------------------------------------------
199
+
200
+ /**
201
+ * Single‑pass, zero‑regex entity decoder for XML/HTML content.
202
+ *
203
+ * ## Entity lookup priority (highest → lowest)
204
+ * 1. **input / runtime** – injected via `addInputEntities()` (DOCTYPE per document)
205
+ * 2. **persistent external** – set via `setExternalEntities()` / `addExternalEntity()`
206
+ * 3. **base map** – built‑in XML entities + user‑supplied `namedEntities`
207
+ *
208
+ * Numeric references (`&#NNN;`, `&#xHH;`) are resolved directly and count as the `'base'` tier.
209
+ *
210
+ * @example
211
+ * const decoder = new EntityDecoder({
212
+ * namedEntities: COMMON_HTML,
213
+ * maxTotalExpansions: 100
214
+ * });
215
+ * decoder.setExternalEntities({ brand: 'Acme' });
216
+ *
217
+ * decoder.addInputEntities({ version: '1.0' });
218
+ * decoder.decode('&brand; v&version; &lt;'); // 'Acme v1.0 <'
219
+ *
220
+ * decoder.reset(); // clears input entities + counters, keeps external entities
221
+ */
222
+ export default class EntityDecoder {
223
+ constructor(options?: EntityDecoderOptions);
224
+
225
+ setExternalEntities(
226
+ map: Record<string, string | { regex: RegExp; val: string | EntityValFn }>
227
+ ): void;
228
+
229
+ addExternalEntity(key: string, value: string): void;
230
+
231
+ addInputEntities(
232
+ map: Record<
233
+ string,
234
+ | string
235
+ | { regx: RegExp; val: string | EntityValFn }
236
+ | { regex: RegExp; val: string | EntityValFn }
237
+ >
238
+ ): void;
239
+
240
+ reset(): this;
241
+
242
+ decode(str: string): string;
243
+ }
244
+
245
+ // ---------------------------------------------------------------------------
246
+ // Named entity group exports (for use with `namedEntities` option)
247
+ // ---------------------------------------------------------------------------
248
+
249
+ export const COMMON_HTML: Record<string, string>;
250
+ export const ALL_ENTITIES: Record<string, string>;
251
+ export const XML: Record<string, string>;
252
+ export const BASIC_LATIN: Record<string, string>;
253
+ export const LATIN_ACCENTS: Record<string, string>;
254
+ export const LATIN_EXTENDED: Record<string, string>;
255
+ export const GREEK: Record<string, string>;
256
+ export const CYRILLIC: Record<string, string>;
257
+ export const MATH: Record<string, string>;
258
+ export const MATH_ADVANCED: Record<string, string>;
259
+ export const ARROWS: Record<string, string>;
260
+ export const SHAPES: Record<string, string>;
261
+ export const PUNCTUATION: Record<string, string>;
262
+ export const CURRENCY: Record<string, string>;
263
+ export const FRACTIONS: Record<string, string>;
264
+ export const MISC_SYMBOLS: Record<string, string>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @nodable/entities
3
+ *
4
+ * Standalone, zero-dependency XML/HTML entity replacement.
5
+ *
6
+
7
+ */
8
+
9
+ export { default as EntityDecoder } from './EntityDecoder.js';
10
+ export {
11
+ COMMON_HTML,
12
+ XML,
13
+ ALL_ENTITIES,
14
+ ARROWS,
15
+ BASIC_LATIN,
16
+ CURRENCY,
17
+ MATH,
18
+ MATH_ADVANCED,
19
+ CYRILLIC,
20
+ FRACTIONS,
21
+ GREEK,
22
+ LATIN_ACCENTS,
23
+ LATIN_EXTENDED,
24
+ MISC_SYMBOLS,
25
+ PUNCTUATION,
26
+ SHAPES,
27
+ } from './entities.js';
28
+
29
+ export { default as EntityEncoder } from './EntityEncoder.js';
@@ -0,0 +1,40 @@
1
+
2
+
3
+
4
+ **1.2.0** (2026-05-08)
5
+ - Add support for `sanitizeName` option
6
+ - Support xml-naming for validating and sanitizing tag and attribute names
7
+
8
+ **1.1.9** (2026-05-06)
9
+ - fix: format output for preserve order when indent by is set to empty string
10
+
11
+ **1.1.8** (2026-05-05)
12
+ - fix: skip text property for PI tags
13
+ - improve typings
14
+
15
+ **1.1.7** (2026--05-04)
16
+ - fix security issues when attribute value contains quotes
17
+
18
+ **1.1.6** (2026--05-04)
19
+ - fix security issues related to comment
20
+ - skip comment with null value
21
+
22
+ **1.1.5** (2026-04-17)
23
+ - fix security issues related to comment and cdata
24
+
25
+ **1.1.4** (2026-03-16)
26
+ - support maxNestedTags option
27
+
28
+ **1.1.3** (2026-03-13)
29
+ - declare Matcher & Expression as unknown so user is not forced to install path-expression-matcher
30
+
31
+ **1.1.2** (2026-03-11)
32
+ - fix typings
33
+
34
+ **1.1.1** (2026-03-11)
35
+ - upgrade path-expression-matcher to 1.1.3
36
+
37
+ **1.1.0** (2026-03-10)
38
+
39
+ - Integrate [path-expression-matcher](https://github.com/NaturalIntelligence/path-expression-matcher)
40
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Natural Intelligence
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # fast-xml-builder
2
+ Build XML from JSON
3
+
4
+
5
+ XML Builder was part of [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) for years. But considering that any bug in the parser may false-alarm users who are only using the builder, we have decided to split it into a separate package.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install fast-xml-builder
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```javascript
16
+ import XMLBuilder from 'fast-xml-builder';
17
+
18
+ const builder = new XMLBuilder();
19
+ const xml = builder.build({ name: 'value' });
20
+ ```
21
+
22
+ fast-xml-builder fully supports the response generated by fast-xml-parser. You can use options like `preserveOrder`, `ignoreAttributes`, `attributeNamePrefix`, `textNodeName`, `cdataPropName`, `commentPropName`, `format`, `indentBy`, `suppressEmptyNode`, `suppressUnpairedNode`, `stopNodes`, `oneListGroup`, `maxNestedTags`, and many more.
23
+
24
+ ## Default Options
25
+
26
+ ```js
27
+ {
28
+ attributeNamePrefix: '@_',
29
+ attributesGroupName: false,
30
+ textNodeName: '#text',
31
+ ignoreAttributes: true,
32
+ cdataPropName: false,
33
+ commentPropName: false,
34
+ format: false,
35
+ indentBy: ' ',
36
+ suppressEmptyNode: false,
37
+ suppressUnpairedNode: true,
38
+ suppressBooleanAttributes: true,
39
+ preserveOrder: false,
40
+ processEntities: true,
41
+ unpairedTags: [],
42
+ stopNodes: [],
43
+ oneListGroup: false,
44
+ maxNestedTags: 100,
45
+ jPath: true,
46
+ tagValueProcessor: (key, val) => val,
47
+ attributeValueProcessor: (attrName, val) => val,
48
+ }
49
+ ```
50
+
51
+ ## Options Reference
52
+
53
+ Check [Options reference](docs/Builder_v1.md) for more detail and examples.
54
+
55
+ - **arrayNodeName**: When building XML from an array, set `arrayNodeName` to wrap each element in a tag name.
56
+ - **attributeNamePrefix**: Prefix used to identify attribute properties in the JS object. Default: `'@_'`.
57
+ - **attributesGroupName**: Group name for attributes in the JS object. When set, all attributes are expected to be nested under this key. Not supported with `preserveOrder: true`.
58
+ - **attributeValueProcessor**: Customize how attribute values are serialized. Receives the attribute name and value.
59
+ - **cdataPropName**: Property name that identifies CDATA content. Values under this key are wrapped in `<![CDATA[...]]>`.
60
+ - **commentPropName**: Property name that identifies comment content. Values under this key are rendered as `<!-- ... -->`.
61
+ - **format**: By default, output is a single-line XML string. Set `format: true` for human-readable, indented output.
62
+ - **ignoreAttributes**: By default (`true`), attributes are skipped. Set to `false` to include them. Also supports selective ignoring via an array of strings, array of regular expressions, or a callback function.
63
+ - **indentBy**: String used for each level of indentation. Default: `' '` (two spaces). Only applies when `format: true`.
64
+ - **maxNestedTags**: Limits the maximum depth of nested tags. An error is thrown if this depth is exceeded. Default: `100`.
65
+ - **oneListGroup**: Groups all repeated child tags under a single parent tag.
66
+ - **preserveOrder**: When a JS object was produced by XMLParser with `preserveOrder: true`, pass the same option to XMLBuilder to reconstruct the original XML correctly.
67
+ - **processEntities**: When `true` (default), special characters in text and attribute values are replaced with XML entities (`&amp;`, `&lt;`, etc.). Set to `false` for a performance boost when you know your content has no entities. Note: quotes in attribute values are always escaped regardless of this setting.
68
+ - **stopNodes**: Tags listed here are treated as raw content containers — their text content is written as-is without entity encoding. Accepts an array of tag name strings or `Expression` instances from `path-expression-matcher`. The old `*.tagName` wildcard syntax is still accepted and automatically converted to the equivalent `..tagName` deep-wildcard syntax.
69
+ - **suppressBooleanAttributes**: When `true` (default), attributes with the value `true` are rendered without the value (e.g. `<tag attr>` instead of `<tag attr="true">`).
70
+ - **suppressEmptyNode**: When `true`, tags with no text value are rendered as self-closing (`<tag/>`).
71
+ - **suppressUnpairedNode**: When `true` (default), unpaired tags are rendered without a closing slash (`<br>`). When `false`, they are rendered as `<br/>`.
72
+ - **tagValueProcessor**: Customize how tag text values are serialized. Receives the tag name and value.
73
+ - **textNodeName**: Property name representing the text content of a tag in the JS object. Default: `'#text'`.
74
+ - **unpairedTags**: List of tag names that have no matching closing tag (e.g. `<br>` in HTML).
@@ -0,0 +1 @@
1
+ (()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{default:()=>w});class i{constructor(t,e={},i){this.pattern=t,this.separator=e.separator||".",this.segments=this._parse(t),this.data=i,this._hasDeepWildcard=this.segments.some(t=>"deep-wildcard"===t.type),this._hasAttributeCondition=this.segments.some(t=>void 0!==t.attrName),this._hasPositionSelector=this.segments.some(t=>void 0!==t.position)}_parse(t){const e=[];let i=0,s="";for(;i<t.length;)t[i]===this.separator?i+1<t.length&&t[i+1]===this.separator?(s.trim()&&(e.push(this._parseSegment(s.trim())),s=""),e.push({type:"deep-wildcard"}),i+=2):(s.trim()&&e.push(this._parseSegment(s.trim())),s="",i++):(s+=t[i],i++);return s.trim()&&e.push(this._parseSegment(s.trim())),e}_parseSegment(t){const e={type:"tag"};let i=null,s=t;const n=t.match(/^([^\[]+)(\[[^\]]*\])(.*)$/);if(n&&(s=n[1]+n[3],n[2])){const t=n[2].slice(1,-1);t&&(i=t)}let r,o,a=s;if(s.includes("::")){const e=s.indexOf("::");if(r=s.substring(0,e).trim(),a=s.substring(e+2).trim(),!r)throw new Error(`Invalid namespace in pattern: ${t}`)}let h=null;if(a.includes(":")){const t=a.lastIndexOf(":"),e=a.substring(0,t).trim(),i=a.substring(t+1).trim();["first","last","odd","even"].includes(i)||/^nth\(\d+\)$/.test(i)?(o=e,h=i):o=a}else o=a;if(!o)throw new Error(`Invalid segment pattern: ${t}`);if(e.tag=o,r&&(e.namespace=r),i)if(i.includes("=")){const t=i.indexOf("=");e.attrName=i.substring(0,t).trim(),e.attrValue=i.substring(t+1).trim()}else e.attrName=i.trim();if(h){const t=h.match(/^nth\((\d+)\)$/);t?(e.position="nth",e.positionValue=parseInt(t[1],10)):e.position=h}return e}get length(){return this.segments.length}hasDeepWildcard(){return this._hasDeepWildcard}hasAttributeCondition(){return this._hasAttributeCondition}hasPositionSelector(){return this._hasPositionSelector}toString(){return this.pattern}}class s{constructor(t){this._matcher=t}get separator(){return this._matcher.separator}getCurrentTag(){const t=this._matcher.path;return t.length>0?t[t.length-1].tag:void 0}getCurrentNamespace(){const t=this._matcher.path;return t.length>0?t[t.length-1].namespace:void 0}getAttrValue(t){const e=this._matcher.path;if(0!==e.length)return e[e.length-1].values?.[t]}hasAttr(t){const e=this._matcher.path;if(0===e.length)return!1;const i=e[e.length-1];return void 0!==i.values&&t in i.values}getPosition(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].position??0}getCounter(){const t=this._matcher.path;return 0===t.length?-1:t[t.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this._matcher.path.length}toString(t,e=!0){return this._matcher.toString(t,e)}toArray(){return this._matcher.path.map(t=>t.tag)}matches(t){return this._matcher.matches(t)}matchesAny(t){return t.matchesAny(this._matcher)}}class n{constructor(t={}){this.separator=t.separator||".",this.path=[],this.siblingStacks=[],this._pathStringCache=null,this._view=new s(this)}push(t,e=null,i=null){this._pathStringCache=null,this.path.length>0&&(this.path[this.path.length-1].values=void 0);const s=this.path.length;this.siblingStacks[s]||(this.siblingStacks[s]=new Map);const n=this.siblingStacks[s],r=i?`${i}:${t}`:t,o=n.get(r)||0;let a=0;for(const t of n.values())a+=t;n.set(r,o+1);const h={tag:t,position:a,counter:o};null!=i&&(h.namespace=i),null!=e&&(h.values=e),this.path.push(h)}pop(){if(0===this.path.length)return;this._pathStringCache=null;const t=this.path.pop();return this.siblingStacks.length>this.path.length+1&&(this.siblingStacks.length=this.path.length+1),t}updateCurrent(t){if(this.path.length>0){const e=this.path[this.path.length-1];null!=t&&(e.values=t)}}getCurrentTag(){return this.path.length>0?this.path[this.path.length-1].tag:void 0}getCurrentNamespace(){return this.path.length>0?this.path[this.path.length-1].namespace:void 0}getAttrValue(t){if(0!==this.path.length)return this.path[this.path.length-1].values?.[t]}hasAttr(t){if(0===this.path.length)return!1;const e=this.path[this.path.length-1];return void 0!==e.values&&t in e.values}getPosition(){return 0===this.path.length?-1:this.path[this.path.length-1].position??0}getCounter(){return 0===this.path.length?-1:this.path[this.path.length-1].counter??0}getIndex(){return this.getPosition()}getDepth(){return this.path.length}toString(t,e=!0){const i=t||this.separator;if(i===this.separator&&!0===e){if(null!==this._pathStringCache)return this._pathStringCache;const t=this.path.map(t=>t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(i);return this._pathStringCache=t,t}return this.path.map(t=>e&&t.namespace?`${t.namespace}:${t.tag}`:t.tag).join(i)}toArray(){return this.path.map(t=>t.tag)}reset(){this._pathStringCache=null,this.path=[],this.siblingStacks=[]}matches(t){const e=t.segments;return 0!==e.length&&(t.hasDeepWildcard()?this._matchWithDeepWildcard(e):this._matchSimple(e))}_matchSimple(t){if(this.path.length!==t.length)return!1;for(let e=0;e<t.length;e++)if(!this._matchSegment(t[e],this.path[e],e===this.path.length-1))return!1;return!0}_matchWithDeepWildcard(t){let e=this.path.length-1,i=t.length-1;for(;i>=0&&e>=0;){const s=t[i];if("deep-wildcard"===s.type){if(i--,i<0)return!0;const s=t[i];let n=!1;for(let t=e;t>=0;t--)if(this._matchSegment(s,this.path[t],t===this.path.length-1)){e=t-1,i--,n=!0;break}if(!n)return!1}else{if(!this._matchSegment(s,this.path[e],e===this.path.length-1))return!1;e--,i--}}return i<0}_matchSegment(t,e,i){if("*"!==t.tag&&t.tag!==e.tag)return!1;if(void 0!==t.namespace&&"*"!==t.namespace&&t.namespace!==e.namespace)return!1;if(void 0!==t.attrName){if(!i)return!1;if(!e.values||!(t.attrName in e.values))return!1;if(void 0!==t.attrValue&&String(e.values[t.attrName])!==String(t.attrValue))return!1}if(void 0!==t.position){if(!i)return!1;const s=e.counter??0;if("first"===t.position&&0!==s)return!1;if("odd"===t.position&&s%2!=1)return!1;if("even"===t.position&&s%2!=0)return!1;if("nth"===t.position&&s!==t.positionValue)return!1}return!0}matchesAny(t){return t.matchesAny(this)}snapshot(){return{path:this.path.map(t=>({...t})),siblingStacks:this.siblingStacks.map(t=>new Map(t))}}restore(t){this._pathStringCache=null,this.path=t.path.map(t=>({...t})),this.siblingStacks=t.siblingStacks.map(t=>new Map(t))}readOnly(){return this._view}}function r(t){return String(t).replace(/--/g,"- -").replace(/--/g,"- -").replace(/-$/,"- ")}function o(t){return String(t).replace(/\]\]>/g,"]]]]><![CDATA[>")}function a(t){return String(t).replace(/"/g,"&quot;").replace(/'/g,"&apos;")}const h=":A-Za-z_À-ÖØ-öø-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�",p=":A-Za-z_À-˿Ͱ-ͽͿ-҆҈-῿‌-‍⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-󯿿",u=p+"\\-\\.\\d·̀-ͯ҇‿-⁀",l=(t,e,i="")=>{const s=`[${t.replace(":","")}][${e.replace(":","")}]*`;return{name:new RegExp(`^[${t}][${e}]*$`,i),ncName:new RegExp(`^${s}$`,i),qName:new RegExp(`^${s}(?::${s})?$`,i),nmToken:new RegExp(`^[${e}]+$`,i),nmTokens:new RegExp(`^[${e}]+(?:\\s+[${e}]+)*$`,i)}},c=l(h,h+"\\-\\.\\d·̀-ͯ‿-⁀"),g=l(p,u,"u"),d=(t,{xmlVersion:e="1.0"}={})=>((t="1.0")=>"1.1"===t?g:c)(e).qName.test(t);function f(t,e,i,s,n){return i.sanitizeName?d(t,{xmlVersion:n})?t:i.sanitizeName(t,{isAttribute:e,matcher:s.readOnly()}):t}function m(t,e){let s="";e.format&&(s="\n");const r=[];if(e.stopNodes&&Array.isArray(e.stopNodes))for(let t=0;t<e.stopNodes.length;t++){const s=e.stopNodes[t];"string"==typeof s?r.push(new i(s)):s instanceof i&&r.push(s)}const o=function(t,e){if(!Array.isArray(t)||0===t.length)return"1.0";const i=t[0];if("?xml"===A(i)){const t=i[":@"];if(t){const i=e.attributeNamePrefix+"version";if(t[i])return t[i]}}return"1.0"}(t,e);return N(t,e,s,new n,r,o)}function N(t,e,i,s,n,a){let h="",p=!1;if(e.maxNestedTags&&s.getDepth()>e.maxNestedTags)throw new Error("Maximum nested tags exceeded");if(!Array.isArray(t)){if(null!=t){let i=t.toString();return i=S(i,e),i}return""}for(let u=0;u<t.length;u++){const l=t[u],c=A(l);if(void 0===c)continue;const g=c===e.textNodeName||c===e.cdataPropName||c===e.commentPropName||"?"===c[0]?c:f(c,!1,e,s,a),d=b(l[":@"],e);s.push(g,d);const m=P(s,n);if(g===e.textNodeName){let t=l[c];m||(t=e.tagValueProcessor(g,t),t=S(t,e)),p&&(h+=i),h+=t,p=!1,s.pop();continue}if(g===e.cdataPropName){p&&(h+=i),h+=`<![CDATA[${o(l[c][0][e.textNodeName])}]]>`,p=!1,s.pop();continue}if(g===e.commentPropName){h+=i+`\x3c!--${r(l[c][0][e.textNodeName])}--\x3e`,p=!0,s.pop();continue}if("?"===g[0]){h+=("?xml"===g?"":i)+`<${g}${$(l[":@"],e,m,s,a)}?>`,p=!0,s.pop();continue}let y=i;""!==y&&(y+=e.indentBy);const v=i+`<${g}${$(l[":@"],e,m,s,a)}`;let w;w=m?x(l[c],e):N(l[c],e,y,s,n,a),-1!==e.unpairedTags.indexOf(g)?e.suppressUnpairedNode?h+=v+">":h+=v+"/>":w&&0!==w.length||!e.suppressEmptyNode?w&&w.endsWith(">")?h+=v+`>${w}${i}</${g}>`:(h+=v+">",w&&""!==i&&(w.includes("/>")||w.includes("</"))?h+=i+e.indentBy+w+i:h+=w,h+=`</${g}>`):h+=v+"/>",p=!0,s.pop()}return h}function b(t,e){if(!t||e.ignoreAttributes)return null;const i={};let s=!1;for(let n in t)Object.prototype.hasOwnProperty.call(t,n)&&(i[n.startsWith(e.attributeNamePrefix)?n.substr(e.attributeNamePrefix.length):n]=a(t[n]),s=!0);return s?i:null}function x(t,e){if(!Array.isArray(t))return null!=t?t.toString():"";let i="";for(let s=0;s<t.length;s++){const n=t[s],r=A(n);if(r===e.textNodeName)i+=n[r];else if(r===e.cdataPropName)i+=n[r][0][e.textNodeName];else if(r===e.commentPropName)i+=n[r][0][e.textNodeName];else{if(r&&"?"===r[0])continue;if(r){const t=y(n[":@"],e),s=x(n[r],e);s&&0!==s.length?i+=`<${r}${t}>${s}</${r}>`:i+=`<${r}${t}/>`}}}return i}function y(t,e){let i="";if(t&&!e.ignoreAttributes)for(let s in t){if(!Object.prototype.hasOwnProperty.call(t,s))continue;let n=t[s];!0===n&&e.suppressBooleanAttributes?i+=` ${s.substr(e.attributeNamePrefix.length)}`:i+=` ${s.substr(e.attributeNamePrefix.length)}="${a(n)}"`}return i}function A(t){const e=Object.keys(t);for(let i=0;i<e.length;i++){const s=e[i];if(Object.prototype.hasOwnProperty.call(t,s)&&":@"!==s)return s}}function $(t,e,i,s,n){let r="";if(t&&!e.ignoreAttributes)for(let o in t){if(!Object.prototype.hasOwnProperty.call(t,o))continue;const h=o.substr(e.attributeNamePrefix.length),p=i?h:f(h,!0,e,s,n);let u;i?u=t[o]:(u=e.attributeValueProcessor(o,t[o]),u=S(u,e)),!0===u&&e.suppressBooleanAttributes?r+=` ${p}`:r+=` ${p}="${a(u)}"`}return r}function P(t,e){if(!e||0===e.length)return!1;for(let i=0;i<e.length;i++)if(t.matches(e[i]))return!0;return!1}function S(t,e){if(t&&t.length>0&&e.processEntities)for(let i=0;i<e.entities.length;i++){const s=e.entities[i];t=t.replace(s.regex,s.val)}return t}const v={attributeNamePrefix:"@_",attributesGroupName:!1,textNodeName:"#text",ignoreAttributes:!0,cdataPropName:!1,format:!1,indentBy:" ",suppressEmptyNode:!1,suppressUnpairedNode:!0,suppressBooleanAttributes:!0,tagValueProcessor:function(t,e){return e},attributeValueProcessor:function(t,e){return e},preserveOrder:!1,commentPropName:!1,unpairedTags:[],entities:[{regex:new RegExp("&","g"),val:"&amp;"},{regex:new RegExp(">","g"),val:"&gt;"},{regex:new RegExp("<","g"),val:"&lt;"},{regex:new RegExp("'","g"),val:"&apos;"},{regex:new RegExp('"',"g"),val:"&quot;"}],processEntities:!0,stopNodes:[],oneListGroup:!1,maxNestedTags:100,jPath:!0,sanitizeName:!1};function w(t){if(this.options=Object.assign({},v,t),this.options.stopNodes&&Array.isArray(this.options.stopNodes)&&(this.options.stopNodes=this.options.stopNodes.map(t=>"string"==typeof t&&t.startsWith("*.")?".."+t.substring(2):t)),this.stopNodeExpressions=[],this.options.stopNodes&&Array.isArray(this.options.stopNodes))for(let t=0;t<this.options.stopNodes.length;t++){const e=this.options.stopNodes[t];"string"==typeof e?this.stopNodeExpressions.push(new i(e)):e instanceof i&&this.stopNodeExpressions.push(e)}var e;!0===this.options.ignoreAttributes||this.options.attributesGroupName?this.isAttribute=function(){return!1}:(this.ignoreAttributesFn="function"==typeof(e=this.options.ignoreAttributes)?e:Array.isArray(e)?t=>{for(const i of e){if("string"==typeof i&&t===i)return!0;if(i instanceof RegExp&&i.test(t))return!0}}:()=>!1,this.attrPrefixLen=this.options.attributeNamePrefix.length,this.isAttribute=C),this.processTextOrObjNode=O,this.options.format?(this.indentate=_,this.tagEndChar=">\n",this.newLine="\n"):(this.indentate=function(){return""},this.tagEndChar=">",this.newLine="")}function E(t,e,i,s,n){return i.sanitizeName?d(t,{xmlVersion:n})?t:i.sanitizeName(t,{isAttribute:e,matcher:s.readOnly()}):t}function O(t,e,i,s,n){const r=this.extractAttributes(t);if(s.push(e,r),this.checkStopNode(s)){const n=this.buildRawContent(t),r=this.buildAttributesForStopNode(t);return s.pop(),this.buildObjectNode(n,e,r,i)}const o=this.j2x(t,i+1,s,n);return s.pop(),"?"===e[0]?this.buildTextValNode("",e,o.attrStr,i,s):void 0!==t[this.options.textNodeName]&&1===Object.keys(t).length?this.buildTextValNode(t[this.options.textNodeName],e,o.attrStr,i,s):this.buildObjectNode(o.val,e,o.attrStr,i)}function _(t){return this.options.indentBy.repeat(t)}function C(t){return!(!t.startsWith(this.options.attributeNamePrefix)||t===this.options.textNodeName)&&t.substr(this.attrPrefixLen)}w.prototype.build=function(t){if(this.options.preserveOrder)return m(t,this.options);{Array.isArray(t)&&this.options.arrayNodeName&&this.options.arrayNodeName.length>1&&(t={[this.options.arrayNodeName]:t});const e=new n,i=function(t,e){const i=t["?xml"];if(i&&"object"==typeof i){if(e.attributesGroupName&&i[e.attributesGroupName]){const t=i[e.attributesGroupName][e.attributeNamePrefix+"version"];if(t)return t}const t=i[e.attributeNamePrefix+"version"];if(t)return t}return"1.0"}(t,this.options);return this.j2x(t,0,e,i).val}},w.prototype.j2x=function(t,e,i,s){let n="",r="";if(this.options.maxNestedTags&&i.getDepth()>=this.options.maxNestedTags)throw new Error("Maximum nested tags exceeded");const o=this.options.jPath?i.toString():i,a=this.checkStopNode(i);for(let h in t){if(!Object.prototype.hasOwnProperty.call(t,h))continue;const p=h===this.options.textNodeName||h===this.options.cdataPropName||h===this.options.commentPropName||this.options.attributesGroupName&&h===this.options.attributesGroupName||this.isAttribute(h)||"?"===h[0]?h:E(h,!1,this.options,i,s);if(void 0===t[h])this.isAttribute(h)&&(r+="");else if(null===t[h])this.isAttribute(h)||p===this.options.cdataPropName||p===this.options.commentPropName?r+="":"?"===p[0]?r+=this.indentate(e)+"<"+p+"?"+this.tagEndChar:r+=this.indentate(e)+"<"+p+"/"+this.tagEndChar;else if(t[h]instanceof Date)r+=this.buildTextValNode(t[h],p,"",e,i);else if("object"!=typeof t[h]){const u=this.isAttribute(h);if(u&&!this.ignoreAttributesFn(u,o)){const e=E(u,!0,this.options,i,s);n+=this.buildAttrPairStr(e,""+t[h],a)}else if(!u)if(h===this.options.textNodeName){let e=this.options.tagValueProcessor(h,""+t[h]);r+=this.replaceEntitiesValue(e)}else{i.push(p);const s=this.checkStopNode(i);if(i.pop(),s){const i=""+t[h];r+=""===i?this.indentate(e)+"<"+p+this.closeTag(p)+this.tagEndChar:this.indentate(e)+"<"+p+">"+i+"</"+p+this.tagEndChar}else r+=this.buildTextValNode(t[h],p,"",e,i)}}else if(Array.isArray(t[h])){const n=t[h].length;let o="",a="";for(let u=0;u<n;u++){const n=t[h][u];if(void 0===n);else if(null===n)"?"===p[0]?r+=this.indentate(e)+"<"+p+"?"+this.tagEndChar:r+=this.indentate(e)+"<"+p+"/"+this.tagEndChar;else if("object"==typeof n)if(this.options.oneListGroup){i.push(p);const t=this.j2x(n,e+1,i,s);i.pop(),o+=t.val,this.options.attributesGroupName&&n.hasOwnProperty(this.options.attributesGroupName)&&(a+=t.attrStr)}else o+=this.processTextOrObjNode(n,p,e,i,s);else if(this.options.oneListGroup){let t=this.options.tagValueProcessor(p,n);t=this.replaceEntitiesValue(t),o+=t}else{i.push(p);const t=this.checkStopNode(i);if(i.pop(),t){const t=""+n;o+=""===t?this.indentate(e)+"<"+p+this.closeTag(p)+this.tagEndChar:this.indentate(e)+"<"+p+">"+t+"</"+p+this.tagEndChar}else o+=this.buildTextValNode(n,p,"",e,i)}}this.options.oneListGroup&&(o=this.buildObjectNode(o,p,a,e)),r+=o}else if(this.options.attributesGroupName&&h===this.options.attributesGroupName){const e=Object.keys(t[h]),r=e.length;for(let o=0;o<r;o++){const r=E(e[o],!0,this.options,i,s);n+=this.buildAttrPairStr(r,""+t[h][e[o]],a)}}else r+=this.processTextOrObjNode(t[h],p,e,i,s)}return{attrStr:n,val:r}},w.prototype.buildAttrPairStr=function(t,e,i){return i||(e=this.options.attributeValueProcessor(t,""+e),e=this.replaceEntitiesValue(e)),this.options.suppressBooleanAttributes&&"true"===e?" "+t:" "+t+'="'+a(e)+'"'},w.prototype.extractAttributes=function(t){if(!t||"object"!=typeof t)return null;const e={};let i=!1;if(this.options.attributesGroupName&&t[this.options.attributesGroupName]){const s=t[this.options.attributesGroupName];for(let t in s)Object.prototype.hasOwnProperty.call(s,t)&&(e[t.startsWith(this.options.attributeNamePrefix)?t.substring(this.options.attributeNamePrefix.length):t]=a(s[t]),i=!0)}else for(let s in t){if(!Object.prototype.hasOwnProperty.call(t,s))continue;const n=this.isAttribute(s);n&&(e[n]=a(t[s]),i=!0)}return i?e:null},w.prototype.buildRawContent=function(t){if("string"==typeof t)return t;if("object"!=typeof t||null===t)return String(t);if(void 0!==t[this.options.textNodeName])return t[this.options.textNodeName];let e="";for(let i in t){if(!Object.prototype.hasOwnProperty.call(t,i))continue;if(this.isAttribute(i))continue;if(this.options.attributesGroupName&&i===this.options.attributesGroupName)continue;const s=t[i];if(i===this.options.textNodeName)e+=s;else if(Array.isArray(s)){for(let t of s)if("string"==typeof t||"number"==typeof t)e+=`<${i}>${t}</${i}>`;else if("object"==typeof t&&null!==t){const s=this.buildRawContent(t),n=this.buildAttributesForStopNode(t);e+=""===s?`<${i}${n}/>`:`<${i}${n}>${s}</${i}>`}}else if("object"==typeof s&&null!==s){const t=this.buildRawContent(s),n=this.buildAttributesForStopNode(s);e+=""===t?`<${i}${n}/>`:`<${i}${n}>${t}</${i}>`}else e+=`<${i}>${s}</${i}>`}return e},w.prototype.buildAttributesForStopNode=function(t){if(!t||"object"!=typeof t)return"";let e="";if(this.options.attributesGroupName&&t[this.options.attributesGroupName]){const i=t[this.options.attributesGroupName];for(let t in i){if(!Object.prototype.hasOwnProperty.call(i,t))continue;const s=t.startsWith(this.options.attributeNamePrefix)?t.substring(this.options.attributeNamePrefix.length):t,n=i[t];!0===n&&this.options.suppressBooleanAttributes?e+=" "+s:e+=" "+s+'="'+n+'"'}}else for(let i in t){if(!Object.prototype.hasOwnProperty.call(t,i))continue;const s=this.isAttribute(i);if(s){const n=t[i];!0===n&&this.options.suppressBooleanAttributes?e+=" "+s:e+=" "+s+'="'+n+'"'}}return e},w.prototype.buildObjectNode=function(t,e,i,s){if(""===t)return"?"===e[0]?this.indentate(s)+"<"+e+i+"?"+this.tagEndChar:this.indentate(s)+"<"+e+i+this.closeTag(e)+this.tagEndChar;if("?"===e[0])return this.indentate(s)+"<"+e+i+"?"+this.tagEndChar;{let n="</"+e+this.tagEndChar,r="";return"?"===e[0]&&(r="?",n=""),!i&&""!==i||-1!==t.indexOf("<")?!1!==this.options.commentPropName&&e===this.options.commentPropName&&0===r.length?this.indentate(s)+`\x3c!--${t}--\x3e`+this.newLine:this.indentate(s)+"<"+e+i+r+this.tagEndChar+t+this.indentate(s)+n:this.indentate(s)+"<"+e+i+r+">"+t+n}},w.prototype.closeTag=function(t){let e="";return-1!==this.options.unpairedTags.indexOf(t)?this.options.suppressUnpairedNode||(e="/"):e=this.options.suppressEmptyNode?"/":`></${t}`,e},w.prototype.checkStopNode=function(t){if(!this.stopNodeExpressions||0===this.stopNodeExpressions.length)return!1;for(let e=0;e<this.stopNodeExpressions.length;e++)if(t.matches(this.stopNodeExpressions[e]))return!0;return!1},w.prototype.buildTextValNode=function(t,e,i,s,n){if(!1!==this.options.cdataPropName&&e===this.options.cdataPropName){const e=o(t);return this.indentate(s)+`<![CDATA[${e}]]>`+this.newLine}if(!1!==this.options.commentPropName&&e===this.options.commentPropName){const e=r(t);return this.indentate(s)+`\x3c!--${e}--\x3e`+this.newLine}if("?"===e[0])return this.indentate(s)+"<"+e+i+"?"+this.tagEndChar;{let n=this.options.tagValueProcessor(e,t);return n=this.replaceEntitiesValue(n),""===n?this.indentate(s)+"<"+e+i+this.closeTag(e)+this.tagEndChar:this.indentate(s)+"<"+e+i+">"+n+"</"+e+this.tagEndChar}},w.prototype.replaceEntitiesValue=function(t){if(t&&t.length>0&&this.options.processEntities)for(let e=0;e<this.options.entities.length;e++){const i=this.options.entities[e];t=t.replace(i.regex,i.val)}return t},module.exports=e})();