@ai-sdk-tool/rxml 0.1.0 → 0.1.2-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
  var RXMLParseError = class extends Error {
3
3
  constructor(message, cause, line, column) {
4
4
  super(message);
5
+ this.name = "RXMLParseError";
5
6
  this.cause = cause;
6
7
  this.line = line;
7
8
  this.column = column;
8
- this.name = "RXMLParseError";
9
9
  }
10
10
  };
11
11
  var RXMLDuplicateStringTagError = class extends Error {
@@ -17,384 +17,25 @@ var RXMLDuplicateStringTagError = class extends Error {
17
17
  var RXMLCoercionError = class extends Error {
18
18
  constructor(message, cause) {
19
19
  super(message);
20
- this.cause = cause;
21
20
  this.name = "RXMLCoercionError";
21
+ this.cause = cause;
22
22
  }
23
23
  };
24
24
  var RXMLStringifyError = class extends Error {
25
25
  constructor(message, cause) {
26
26
  super(message);
27
- this.cause = cause;
28
27
  this.name = "RXMLStringifyError";
28
+ this.cause = cause;
29
29
  }
30
30
  };
31
31
  var RXMLStreamError = class extends Error {
32
32
  constructor(message, cause) {
33
33
  super(message);
34
- this.cause = cause;
35
34
  this.name = "RXMLStreamError";
35
+ this.cause = cause;
36
36
  }
37
37
  };
38
38
 
39
- // src/schema/base-coercion.ts
40
- function unwrapJsonSchema(schema) {
41
- if (!schema || typeof schema !== "object") return schema;
42
- const s = schema;
43
- if (s.jsonSchema && typeof s.jsonSchema === "object") {
44
- return unwrapJsonSchema(s.jsonSchema);
45
- }
46
- return schema;
47
- }
48
- function getSchemaType(schema) {
49
- const unwrapped = unwrapJsonSchema(schema);
50
- if (!unwrapped || typeof unwrapped !== "object") return void 0;
51
- const t = unwrapped.type;
52
- if (typeof t === "string") return t;
53
- if (Array.isArray(t)) {
54
- const preferred = [
55
- "object",
56
- "array",
57
- "boolean",
58
- "number",
59
- "integer",
60
- "string"
61
- ];
62
- for (const p of preferred) if (t.includes(p)) return p;
63
- }
64
- const s = unwrapped;
65
- if (s && typeof s === "object" && (s.properties || s.additionalProperties)) {
66
- return "object";
67
- }
68
- if (s && typeof s === "object" && (s.items || s.prefixItems)) {
69
- return "array";
70
- }
71
- return void 0;
72
- }
73
- function coerceBySchema(value, schema) {
74
- const unwrapped = unwrapJsonSchema(schema);
75
- if (!unwrapped || typeof unwrapped !== "object") {
76
- if (typeof value === "string") {
77
- const s = value.trim();
78
- const lower = s.toLowerCase();
79
- if (lower === "true") return true;
80
- if (lower === "false") return false;
81
- if (/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(s)) {
82
- const num = Number(s);
83
- if (Number.isFinite(num)) return num;
84
- }
85
- if (s.startsWith("{") && s.endsWith("}") || s.startsWith("[") && s.endsWith("]")) {
86
- try {
87
- const parsed = JSON.parse(s);
88
- return coerceBySchema(parsed, void 0);
89
- } catch (e) {
90
- }
91
- }
92
- }
93
- return value;
94
- }
95
- const schemaType = getSchemaType(unwrapped);
96
- if (typeof value === "string") {
97
- const s = value.trim();
98
- if (schemaType === "object") {
99
- try {
100
- let normalized = s.replace(/'/g, '"');
101
- normalized = normalized.replace(/^\{\s*\}$/s, "{}");
102
- const obj = JSON.parse(normalized);
103
- if (obj && typeof obj === "object" && !Array.isArray(obj)) {
104
- const props = unwrapped.properties;
105
- const out = {};
106
- for (const [k, v] of Object.entries(obj)) {
107
- const propSchema = props ? props[k] : void 0;
108
- out[k] = typeof propSchema === "boolean" ? v : coerceBySchema(v, propSchema);
109
- }
110
- return out;
111
- }
112
- } catch (e) {
113
- }
114
- }
115
- if (schemaType === "array") {
116
- try {
117
- const normalized = s.replace(/'/g, '"');
118
- const arr = JSON.parse(normalized);
119
- if (Array.isArray(arr)) {
120
- const u = unwrapped;
121
- const prefixItems = Array.isArray(
122
- u.prefixItems
123
- ) ? u.prefixItems : void 0;
124
- const itemsSchema = u.items;
125
- if (prefixItems && arr.length === prefixItems.length) {
126
- return arr.map((v, i) => coerceBySchema(v, prefixItems[i]));
127
- }
128
- return arr.map((v) => coerceBySchema(v, itemsSchema));
129
- }
130
- } catch (e) {
131
- const csv = s.includes("\n") ? s.split(/\n+/) : s.split(/,\s*/);
132
- const trimmed = csv.map((x) => x.trim()).filter((x) => x.length > 0);
133
- const u = unwrapped;
134
- const prefixItems = Array.isArray(
135
- u.prefixItems
136
- ) ? u.prefixItems : void 0;
137
- const itemsSchema = u.items;
138
- if (prefixItems && trimmed.length === prefixItems.length) {
139
- return trimmed.map((x, i) => coerceBySchema(x, prefixItems[i]));
140
- }
141
- return trimmed.map((x) => coerceBySchema(x, itemsSchema));
142
- }
143
- }
144
- }
145
- if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
146
- const out = {};
147
- const props = unwrapped.properties;
148
- for (const [k, v] of Object.entries(value)) {
149
- const propSchema = props ? props[k] : void 0;
150
- out[k] = typeof propSchema === "boolean" ? v : coerceBySchema(v, propSchema);
151
- }
152
- return out;
153
- }
154
- if (schemaType === "array") {
155
- const u = unwrapped;
156
- const itemsSchema = u.items;
157
- const prefixItems = Array.isArray(
158
- u.prefixItems
159
- ) ? u.prefixItems : void 0;
160
- if (Array.isArray(value)) {
161
- if (prefixItems && value.length === prefixItems.length) {
162
- return value.map((v, i) => coerceBySchema(v, prefixItems[i]));
163
- }
164
- return value.map((v) => coerceBySchema(v, itemsSchema));
165
- }
166
- if (value && typeof value === "object") {
167
- const maybe = value;
168
- if (Object.prototype.hasOwnProperty.call(maybe, "item")) {
169
- const items = maybe.item;
170
- const arr = Array.isArray(items) ? items : [items];
171
- if (prefixItems && arr.length === prefixItems.length) {
172
- return arr.map((v, i) => coerceBySchema(v, prefixItems[i]));
173
- }
174
- return arr.map((v) => coerceBySchema(v, itemsSchema));
175
- }
176
- const keys = Object.keys(maybe);
177
- if (keys.length === 1) {
178
- const singleKey = keys[0];
179
- const singleValue = maybe[singleKey];
180
- if (Array.isArray(singleValue)) {
181
- const coercedArray = singleValue.map(
182
- (v) => coerceBySchema(v, itemsSchema)
183
- );
184
- return coercedArray;
185
- }
186
- }
187
- if (keys.length > 0 && keys.every((k) => /^\d+$/.test(k))) {
188
- const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
189
- if (prefixItems && arr.length === prefixItems.length) {
190
- return arr.map((v, i) => coerceBySchema(v, prefixItems[i]));
191
- }
192
- return arr.map((v) => coerceBySchema(v, itemsSchema));
193
- }
194
- }
195
- if (value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
196
- if (prefixItems && prefixItems.length > 0) {
197
- return [coerceBySchema(value, prefixItems[0])];
198
- }
199
- return [coerceBySchema(value, itemsSchema)];
200
- }
201
- }
202
- if (typeof value === "string") {
203
- const s = value.trim();
204
- if (schemaType === "boolean") {
205
- const lower = s.toLowerCase();
206
- if (lower === "true") return true;
207
- if (lower === "false") return false;
208
- }
209
- if (schemaType === "number" || schemaType === "integer") {
210
- if (/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(s)) {
211
- const num = Number(s);
212
- if (Number.isFinite(num)) return num;
213
- }
214
- }
215
- }
216
- return value;
217
- }
218
-
219
- // src/schema/coercion.ts
220
- function getPropertySchema(toolSchema, key) {
221
- const unwrapped = unwrapJsonSchema(toolSchema);
222
- if (!unwrapped || typeof unwrapped !== "object") return void 0;
223
- const u = unwrapped;
224
- const props = u.properties;
225
- if (props && Object.prototype.hasOwnProperty.call(props, key)) {
226
- return props[key];
227
- }
228
- return void 0;
229
- }
230
- function domToObject(nodes, schema, textNodeName = "#text") {
231
- const result = {};
232
- for (const node of nodes) {
233
- if (typeof node === "string") {
234
- continue;
235
- }
236
- const { tagName, children, attributes } = node;
237
- let value;
238
- if (children.length === 0) {
239
- value = "";
240
- } else if (children.length === 1 && typeof children[0] === "string") {
241
- value = children[0];
242
- } else {
243
- value = processComplexContent(
244
- children,
245
- getPropertySchema(schema, tagName),
246
- textNodeName
247
- );
248
- }
249
- if (Object.keys(attributes).length > 0) {
250
- if (typeof value === "string") {
251
- const result2 = { [textNodeName]: value };
252
- for (const [attrName, attrValue] of Object.entries(attributes)) {
253
- result2[`@_${attrName}`] = attrValue;
254
- }
255
- value = result2;
256
- } else if (value && typeof value === "object" && !Array.isArray(value)) {
257
- for (const [attrName, attrValue] of Object.entries(attributes)) {
258
- value[`@_${attrName}`] = attrValue;
259
- }
260
- }
261
- }
262
- if (result[tagName]) {
263
- if (!Array.isArray(result[tagName])) {
264
- result[tagName] = [result[tagName]];
265
- }
266
- result[tagName].push(value);
267
- } else {
268
- result[tagName] = value;
269
- }
270
- }
271
- return result;
272
- }
273
- function processComplexContent(children, schema, textNodeName) {
274
- const textContent = [];
275
- const elements = {};
276
- for (const child of children) {
277
- if (typeof child === "string") {
278
- textContent.push(child);
279
- } else {
280
- let childValue;
281
- if (child.children.length === 0) {
282
- childValue = "";
283
- } else if (child.children.length === 1 && typeof child.children[0] === "string") {
284
- childValue = child.children[0];
285
- } else {
286
- childValue = processComplexContent(
287
- child.children,
288
- getPropertySchema(schema, child.tagName),
289
- textNodeName
290
- );
291
- }
292
- if (Object.keys(child.attributes).length > 0) {
293
- if (typeof childValue === "string") {
294
- const result = {
295
- [textNodeName]: childValue
296
- };
297
- for (const [attrName, attrValue] of Object.entries(
298
- child.attributes
299
- )) {
300
- result[`@_${attrName}`] = attrValue;
301
- }
302
- childValue = result;
303
- } else if (childValue && typeof childValue === "object" && !Array.isArray(childValue)) {
304
- for (const [attrName, attrValue] of Object.entries(
305
- child.attributes
306
- )) {
307
- childValue[`@_${attrName}`] = attrValue;
308
- }
309
- }
310
- }
311
- if (elements[child.tagName]) {
312
- if (!Array.isArray(elements[child.tagName])) {
313
- elements[child.tagName] = [elements[child.tagName]];
314
- }
315
- elements[child.tagName].push(childValue);
316
- } else {
317
- elements[child.tagName] = childValue;
318
- }
319
- }
320
- }
321
- if (textContent.length > 0 && Object.keys(elements).length > 0) {
322
- return {
323
- [textNodeName]: textContent.join("").trim(),
324
- ...elements
325
- };
326
- }
327
- if (textContent.length > 0 && Object.keys(elements).length === 0) {
328
- return textContent.join("").trim();
329
- }
330
- if (Object.keys(elements).length > 0) {
331
- return elements;
332
- }
333
- return "";
334
- }
335
- function coerceDomBySchema(domObject, schema) {
336
- try {
337
- return coerceBySchema(domObject, schema);
338
- } catch (error) {
339
- throw new RXMLCoercionError("Failed to coerce DOM object by schema", error);
340
- }
341
- }
342
- function getStringTypedProperties(schema) {
343
- const set = /* @__PURE__ */ new Set();
344
- const unwrapped = unwrapJsonSchema(schema);
345
- if (unwrapped && typeof unwrapped === "object") {
346
- const u = unwrapped;
347
- const props = u.properties;
348
- if (props && typeof props === "object") {
349
- for (const key of Object.keys(props)) {
350
- const propSchema = props[key];
351
- const propType = getSchemaType(propSchema);
352
- if (propType === "string") {
353
- set.add(key);
354
- }
355
- }
356
- }
357
- }
358
- return set;
359
- }
360
- function processArrayContent(value, schema, textNodeName) {
361
- if (!Array.isArray(value)) return value;
362
- const schemaType = getSchemaType(schema);
363
- if (schemaType === "string") {
364
- return value.map((item) => {
365
- if (typeof item === "string") return item.trim();
366
- if (item && typeof item === "object" && textNodeName in item) {
367
- const textVal = item[textNodeName];
368
- return typeof textVal === "string" ? textVal.trim() : String(textVal);
369
- }
370
- return String(item);
371
- });
372
- }
373
- return value.map((item) => {
374
- if (typeof item === "string") return item.trim();
375
- if (item && typeof item === "object" && textNodeName in item) {
376
- const textVal = item[textNodeName];
377
- return typeof textVal === "string" ? textVal.trim() : textVal;
378
- }
379
- return item;
380
- });
381
- }
382
- function processIndexedTuple(obj, textNodeName) {
383
- const keys = Object.keys(obj);
384
- const indices = keys.map((k) => parseInt(k, 10)).sort((a, b) => a - b);
385
- const isValidTuple = indices[0] === 0 && indices.every((val, idx) => val === idx);
386
- if (!isValidTuple) return [obj];
387
- const sortedKeys = keys.sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
388
- return sortedKeys.map((key) => {
389
- const item = obj[key];
390
- if (item && typeof item === "object" && textNodeName in item) {
391
- const textVal = item[textNodeName];
392
- return typeof textVal === "string" ? textVal.trim() : textVal;
393
- }
394
- return typeof item === "string" ? item.trim() : item;
395
- });
396
- }
397
-
398
39
  // src/core/types.ts
399
40
  var CharCodes = {
400
41
  OPEN_BRACKET: "<".charCodeAt(0),
@@ -431,32 +72,37 @@ var DEFAULT_NO_CHILD_NODES = [
431
72
  var NAME_SPACER = "\r\n >/= ";
432
73
 
433
74
  // src/utils/helpers.ts
75
+ var NAME_START_CHAR_REGEX = /[A-Za-z_:]/;
76
+ var NAME_CHAR_REGEX = /[A-Za-z0-9_.:-]/;
434
77
  function isNameStartChar(ch) {
435
- return /[A-Za-z_:]/.test(ch);
78
+ return NAME_START_CHAR_REGEX.test(ch);
436
79
  }
437
80
  function isNameChar(ch) {
438
- return /[A-Za-z0-9_.:-]/.test(ch);
81
+ return NAME_CHAR_REGEX.test(ch);
439
82
  }
440
83
  function skipQuoted(s, i) {
441
84
  const quote = s[i];
442
- i++;
443
- while (i < s.length) {
444
- const ch = s[i];
85
+ let pos = i + 1;
86
+ while (pos < s.length) {
87
+ const ch = s[pos];
445
88
  if (ch === "\\") {
446
- i += 2;
89
+ pos += 2;
447
90
  continue;
448
91
  }
449
- if (ch === quote) return i + 1;
450
- i++;
92
+ if (ch === quote) {
93
+ return pos + 1;
94
+ }
95
+ pos += 1;
451
96
  }
452
- return i;
97
+ return pos;
453
98
  }
454
99
  function parseName(s, pos) {
455
100
  const start = pos;
456
- while (NAME_SPACER.indexOf(s[pos]) === -1 && s[pos]) {
457
- pos++;
101
+ let currentPos = pos;
102
+ while (NAME_SPACER.indexOf(s[currentPos]) === -1 && s[currentPos]) {
103
+ currentPos += 1;
458
104
  }
459
- return { name: s.slice(start, pos), newPos: pos };
105
+ return { name: s.slice(start, currentPos), newPos: currentPos };
460
106
  }
461
107
  function parseString(s, pos) {
462
108
  const startChar = s[pos];
@@ -474,12 +120,12 @@ function parseString(s, pos) {
474
120
  function getLineColumn(s, pos) {
475
121
  let line = 1;
476
122
  let column = 1;
477
- for (let i = 0; i < pos && i < s.length; i++) {
123
+ for (let i = 0; i < pos && i < s.length; i += 1) {
478
124
  if (s[i] === "\n") {
479
- line++;
125
+ line += 1;
480
126
  column = 1;
481
127
  } else {
482
- column++;
128
+ column += 1;
483
129
  }
484
130
  }
485
131
  return { line, column };
@@ -499,383 +145,1361 @@ function escapeXmlMinimalAttr(value, wrapper = '"') {
499
145
  }
500
146
  return escaped;
501
147
  }
148
+ function unescapeXml(text) {
149
+ return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, "&");
150
+ }
502
151
 
503
- // src/schema/extraction.ts
504
- function extractRawInner(xmlContent, tagName) {
505
- const len = xmlContent.length;
506
- const target = tagName;
507
- let bestStart = -1;
508
- let bestEnd = -1;
509
- let bestDepth = Number.POSITIVE_INFINITY;
510
- let i = 0;
511
- let depth = 0;
512
- while (i < len) {
513
- const lt = xmlContent.indexOf("<", i);
514
- if (lt === -1) return void 0;
515
- i = lt + 1;
516
- if (i >= len) return void 0;
517
- const ch = xmlContent[i];
518
- if (ch === "!") {
519
- if (xmlContent.startsWith("!--", i + 1)) {
520
- const close = xmlContent.indexOf("-->", i + 4);
521
- i = close === -1 ? len : close + 3;
522
- continue;
523
- }
524
- if (xmlContent.startsWith("![CDATA[", i + 1)) {
525
- const close = xmlContent.indexOf("]]>", i + 9);
526
- i = close === -1 ? len : close + 3;
527
- continue;
528
- }
529
- const gt = xmlContent.indexOf(">", i + 1);
530
- i = gt === -1 ? len : gt + 1;
531
- continue;
532
- } else if (ch === "?") {
533
- const close = xmlContent.indexOf("?>", i + 1);
534
- i = close === -1 ? len : close + 2;
535
- continue;
536
- } else if (ch === "/") {
537
- const gt = xmlContent.indexOf(">", i + 1);
538
- i = gt === -1 ? len : gt + 1;
539
- depth = Math.max(0, depth - 1);
540
- continue;
541
- } else {
542
- let j = i;
543
- if (j < len && isNameStartChar(xmlContent[j])) {
544
- j++;
545
- while (j < len && isNameChar(xmlContent[j])) j++;
546
- }
547
- const name = xmlContent.slice(i, j);
548
- let k = j;
549
- let isSelfClosing = false;
550
- while (k < len) {
551
- const c = xmlContent[k];
552
- if (c === '"' || c === "'") {
553
- k = skipQuoted(xmlContent, k);
554
- continue;
555
- }
556
- if (c === ">") break;
557
- if (c === "/" && xmlContent[k + 1] === ">") {
558
- isSelfClosing = true;
559
- k++;
560
- break;
561
- }
562
- k++;
563
- }
564
- const tagEnd = k;
565
- if (name === target) {
566
- const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
567
- if (isSelfClosing) {
568
- if (depth < bestDepth) {
569
- bestStart = contentStart;
570
- bestEnd = contentStart;
571
- bestDepth = depth;
572
- }
573
- } else {
574
- let pos = contentStart;
575
- let sameDepth = 1;
576
- while (pos < len) {
577
- const nextLt = xmlContent.indexOf("<", pos);
578
- if (nextLt === -1) break;
579
- const nx = nextLt + 1;
580
- if (nx >= len) break;
581
- const h = xmlContent[nx];
582
- if (h === "!") {
583
- if (xmlContent.startsWith("!--", nx + 1)) {
584
- const close = xmlContent.indexOf("-->", nx + 4);
585
- pos = close === -1 ? len : close + 3;
586
- continue;
587
- }
588
- if (xmlContent.startsWith("![CDATA[", nx + 1)) {
589
- const close = xmlContent.indexOf("]]>", nx + 9);
590
- pos = close === -1 ? len : close + 3;
591
- continue;
592
- }
593
- const gt2 = xmlContent.indexOf(">", nx + 1);
594
- pos = gt2 === -1 ? len : gt2 + 1;
595
- continue;
596
- } else if (h === "?") {
597
- const close = xmlContent.indexOf("?>", nx + 1);
598
- pos = close === -1 ? len : close + 2;
599
- continue;
600
- } else if (h === "/") {
601
- let t = nx + 1;
602
- if (t < len && isNameStartChar(xmlContent[t])) {
603
- t++;
604
- while (t < len && isNameChar(xmlContent[t])) t++;
605
- }
606
- const endName = xmlContent.slice(nx + 1, t);
607
- const gt2 = xmlContent.indexOf(">", t);
608
- if (endName === target) {
609
- sameDepth--;
610
- if (sameDepth === 0) {
611
- if (depth < bestDepth) {
612
- bestStart = contentStart;
613
- bestEnd = nextLt;
614
- bestDepth = depth;
615
- }
616
- break;
617
- }
618
- }
619
- pos = gt2 === -1 ? len : gt2 + 1;
620
- continue;
621
- } else {
622
- let t = nx;
623
- if (t < len && isNameStartChar(xmlContent[t])) {
624
- t++;
625
- while (t < len && isNameChar(xmlContent[t])) t++;
626
- }
627
- let u = t;
628
- let isSelfClosingNested = false;
629
- while (u < len) {
630
- const cu = xmlContent[u];
631
- if (cu === '"' || cu === "'") {
632
- u = skipQuoted(xmlContent, u);
633
- continue;
634
- }
635
- if (cu === ">") break;
636
- if (cu === "/" && xmlContent[u + 1] === ">") {
637
- isSelfClosingNested = true;
638
- u++;
639
- break;
640
- }
641
- u++;
642
- }
643
- const startName = xmlContent.slice(nx, t);
644
- if (startName === target && !isSelfClosingNested) {
645
- sameDepth++;
646
- }
647
- pos = xmlContent[u] === ">" ? u + 1 : u + 1;
648
- continue;
649
- }
650
- }
651
- }
652
- }
653
- i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
654
- depth += isSelfClosing ? 0 : 1;
655
- continue;
152
+ // src/builders/stringify.ts
153
+ function stringify(rootTag, obj, options = {}) {
154
+ var _a, _b, _c, _d;
155
+ try {
156
+ const format = (_a = options.format) != null ? _a : true;
157
+ const minimalEscaping = (_b = options.minimalEscaping) != null ? _b : false;
158
+ const suppressEmptyNode = (_c = options.suppressEmptyNode) != null ? _c : false;
159
+ const strictBooleanAttributes = (_d = options.strictBooleanAttributes) != null ? _d : false;
160
+ let result = "";
161
+ if (format) {
162
+ result += '<?xml version="1.0" encoding="UTF-8"?>\n';
163
+ }
164
+ result += stringifyValue(rootTag, obj, {
165
+ depth: 0,
166
+ format,
167
+ suppressEmptyNode,
168
+ minimalEscaping,
169
+ strictBooleanAttributes
170
+ });
171
+ return result;
172
+ } catch (error) {
173
+ throw new RXMLStringifyError("Failed to stringify XML", error);
174
+ }
175
+ }
176
+ function escapeContent(content, minimalEscaping) {
177
+ return minimalEscaping ? escapeXmlMinimalText(content) : escapeXml(content);
178
+ }
179
+ function createSelfClosingTag(tagName, indent, newline) {
180
+ return `${indent}<${tagName}/>${newline}`;
181
+ }
182
+ function createTextElement(tagName, content, indent, newline) {
183
+ return `${indent}<${tagName}>${content}</${tagName}>${newline}`;
184
+ }
185
+ function isPrimitive(value) {
186
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
187
+ }
188
+ function stringifyPrimitive(tagName, value, context, format) {
189
+ const { minimalEscaping, suppressEmptyNode } = context;
190
+ const content = escapeContent(String(value), minimalEscaping);
191
+ if (content === "" && suppressEmptyNode) {
192
+ return "";
193
+ }
194
+ return createTextElement(tagName, content, format.indent, format.newline);
195
+ }
196
+ function stringifyArray(tagName, value, context) {
197
+ let result = "";
198
+ for (const item of value) {
199
+ result += stringifyValue(tagName, item, context);
200
+ }
201
+ return result;
202
+ }
203
+ function stringifyValue(tagName, value, context) {
204
+ const { format, suppressEmptyNode, minimalEscaping } = context;
205
+ const indent = format ? " ".repeat(context.depth) : "";
206
+ const newline = format ? "\n" : "";
207
+ if (value === null || value === void 0) {
208
+ if (suppressEmptyNode) {
209
+ return "";
210
+ }
211
+ return createSelfClosingTag(tagName, indent, newline);
212
+ }
213
+ if (isPrimitive(value)) {
214
+ return stringifyPrimitive(tagName, value, context, { indent, newline });
215
+ }
216
+ if (Array.isArray(value)) {
217
+ return stringifyArray(tagName, value, context);
218
+ }
219
+ if (typeof value === "object") {
220
+ return stringifyObject(tagName, value, context);
221
+ }
222
+ const content = escapeContent(String(value), minimalEscaping);
223
+ if (content === "" && suppressEmptyNode) {
224
+ return "";
225
+ }
226
+ return createTextElement(tagName, content, indent, newline);
227
+ }
228
+ function extractObjectParts(obj) {
229
+ const attributes = {};
230
+ const elements = {};
231
+ let textContent;
232
+ for (const [key, value] of Object.entries(obj)) {
233
+ if (key.startsWith("@")) {
234
+ attributes[key.substring(1)] = value;
235
+ } else if (key === "#text" || key === "_text") {
236
+ textContent = String(value);
237
+ } else if (key === "_attributes") {
238
+ if (typeof value === "object" && value !== null) {
239
+ Object.assign(attributes, value);
240
+ }
241
+ } else {
242
+ elements[key] = value;
243
+ }
244
+ }
245
+ return { attributes, elements, textContent };
246
+ }
247
+ function formatAttribute(attrName, attrValue, minimalEscaping, strictBooleanAttributes) {
248
+ if (attrValue === null) {
249
+ return strictBooleanAttributes ? ` ${attrName}="${attrName}"` : ` ${attrName}`;
250
+ }
251
+ const valueStr = String(attrValue);
252
+ if (valueStr.indexOf('"') === -1) {
253
+ const escaped2 = minimalEscaping ? escapeXmlMinimalAttr(valueStr, '"') : escapeXml(valueStr);
254
+ return ` ${attrName}="${escaped2}"`;
255
+ }
256
+ const escaped = minimalEscaping ? escapeXmlMinimalAttr(valueStr, "'") : escapeXml(valueStr);
257
+ return ` ${attrName}='${escaped}'`;
258
+ }
259
+ function buildOpeningTag(tagName, attributes, context) {
260
+ let openTag = `<${tagName}`;
261
+ const { minimalEscaping, strictBooleanAttributes } = context;
262
+ for (const [attrName, attrValue] of Object.entries(attributes)) {
263
+ openTag += formatAttribute(
264
+ attrName,
265
+ attrValue,
266
+ minimalEscaping,
267
+ strictBooleanAttributes
268
+ );
269
+ }
270
+ return openTag;
271
+ }
272
+ function stringifyTextOnlyContent(options) {
273
+ const { tagName, textContent, openTag, format, minimalEscaping } = options;
274
+ const content = escapeContent(textContent, minimalEscaping);
275
+ return `${format.indent}${openTag}${content}</${tagName}>${format.newline}`;
276
+ }
277
+ function stringifyComplexContent(tagName, parts, context, options) {
278
+ const { format, minimalEscaping, depth } = context;
279
+ const { textContent, elements } = parts;
280
+ const hasElements = Object.keys(elements).length > 0;
281
+ let result = `${options.indent}${options.openTag}`;
282
+ if (textContent) {
283
+ const content = escapeContent(textContent, minimalEscaping);
284
+ result += format ? `${options.newline}${options.childIndent}${content}` : content;
285
+ }
286
+ if (hasElements) {
287
+ if (format) {
288
+ result += options.newline;
289
+ }
290
+ for (const [elementName, elementValue] of Object.entries(elements)) {
291
+ result += stringifyValue(elementName, elementValue, {
292
+ ...context,
293
+ depth: depth + 1
294
+ });
295
+ }
296
+ if (format) {
297
+ result += options.indent;
298
+ }
299
+ }
300
+ result += `</${tagName}>${options.newline}`;
301
+ return result;
302
+ }
303
+ function stringifyObject(tagName, obj, context) {
304
+ const { depth, format, suppressEmptyNode } = context;
305
+ const indent = format ? " ".repeat(depth) : "";
306
+ const newline = format ? "\n" : "";
307
+ const childIndent = format ? " ".repeat(depth + 1) : "";
308
+ const parts = extractObjectParts(obj);
309
+ const openTag = buildOpeningTag(tagName, parts.attributes, context);
310
+ const hasElements = Object.keys(parts.elements).length > 0;
311
+ const hasTextContent = parts.textContent !== void 0 && parts.textContent !== "";
312
+ if (!(hasElements || hasTextContent)) {
313
+ if (suppressEmptyNode) {
314
+ return "";
315
+ }
316
+ return `${indent}${openTag}/>${newline}`;
317
+ }
318
+ const fullOpenTag = `${openTag}>`;
319
+ if (!hasElements && hasTextContent && parts.textContent) {
320
+ return stringifyTextOnlyContent({
321
+ tagName,
322
+ textContent: parts.textContent,
323
+ openTag: fullOpenTag,
324
+ format: { indent, newline },
325
+ minimalEscaping: context.minimalEscaping
326
+ });
327
+ }
328
+ return stringifyComplexContent(tagName, parts, context, {
329
+ indent,
330
+ newline,
331
+ childIndent,
332
+ openTag: fullOpenTag
333
+ });
334
+ }
335
+ function stringifyNodes(nodes, format = true, options = {}) {
336
+ let result = "";
337
+ for (const node of nodes) {
338
+ if (typeof node === "string") {
339
+ result += node;
340
+ } else {
341
+ result += stringifyNode(node, 0, format, options);
342
+ }
343
+ }
344
+ return result;
345
+ }
346
+ function formatNodeAttribute(attrName, attrValue, minimalEscaping, strictBooleanAttributes) {
347
+ if (attrValue === null) {
348
+ if (strictBooleanAttributes) {
349
+ return ` ${attrName}="${attrName}"`;
350
+ }
351
+ return ` ${attrName}`;
352
+ }
353
+ if (attrValue.indexOf('"') === -1) {
354
+ const escaped2 = minimalEscaping ? escapeXmlMinimalAttr(attrValue, '"') : escapeXml(attrValue);
355
+ return ` ${attrName}="${escaped2}"`;
356
+ }
357
+ const escaped = minimalEscaping ? escapeXmlMinimalAttr(attrValue, "'") : escapeXml(attrValue);
358
+ return ` ${attrName}='${escaped}'`;
359
+ }
360
+ function buildNodeOpeningTag(node, opts) {
361
+ let result = `${opts.indent}<${node.tagName}`;
362
+ for (const [attrName, attrValue] of Object.entries(node.attributes)) {
363
+ result += formatNodeAttribute(
364
+ attrName,
365
+ attrValue,
366
+ opts.minimalEscaping,
367
+ opts.strictBooleanAttributes
368
+ );
369
+ }
370
+ return result;
371
+ }
372
+ function stringifyNodeChildren(options) {
373
+ const {
374
+ children,
375
+ depth,
376
+ format,
377
+ stringifyOptions,
378
+ minimalEscaping,
379
+ newline
380
+ } = options;
381
+ let content = "";
382
+ let hasElementChildren = false;
383
+ for (const child of children) {
384
+ if (typeof child === "string") {
385
+ content += minimalEscaping ? escapeXmlMinimalText(child) : escapeXml(child);
386
+ } else {
387
+ if (!hasElementChildren && format) {
388
+ content += newline;
389
+ hasElementChildren = true;
390
+ }
391
+ content += stringifyNode(child, depth + 1, format, stringifyOptions);
392
+ }
393
+ }
394
+ return { content, hasElementChildren };
395
+ }
396
+ function stringifyNode(node, depth = 0, format = true, options = {}) {
397
+ var _a, _b;
398
+ const indent = format ? " ".repeat(depth) : "";
399
+ const newline = format ? "\n" : "";
400
+ const minimalEscaping = (_a = options.minimalEscaping) != null ? _a : false;
401
+ const strictBooleanAttributes = (_b = options.strictBooleanAttributes) != null ? _b : false;
402
+ const opts = {
403
+ minimalEscaping,
404
+ strictBooleanAttributes,
405
+ indent,
406
+ newline
407
+ };
408
+ let result = buildNodeOpeningTag(node, opts);
409
+ if (node.tagName[0] === "?") {
410
+ return `${result}?>${newline}`;
411
+ }
412
+ if (node.children.length === 0) {
413
+ return `${result}/>${newline}`;
414
+ }
415
+ result += ">";
416
+ const { content, hasElementChildren } = stringifyNodeChildren({
417
+ children: node.children,
418
+ depth,
419
+ format,
420
+ stringifyOptions: options,
421
+ minimalEscaping,
422
+ newline
423
+ });
424
+ result += content;
425
+ if (hasElementChildren && format) {
426
+ result += indent;
427
+ }
428
+ result += `</${node.tagName}>`;
429
+ if (format) {
430
+ result += newline;
431
+ }
432
+ return result;
433
+ }
434
+ function toContentString(nodes) {
435
+ let result = "";
436
+ for (const node of nodes) {
437
+ if (typeof node === "string") {
438
+ result += ` ${node}`;
439
+ } else {
440
+ result += ` ${toContentString(node.children)}`;
441
+ }
442
+ result = result.trim();
443
+ }
444
+ return result;
445
+ }
446
+
447
+ // src/schema/base-coercion.ts
448
+ var NUMERIC_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
449
+ var EMPTY_OBJECT_REGEX = /^\{\s*\}$/s;
450
+ var NEWLINE_SPLIT_REGEX = /\n+/;
451
+ var COMMA_SPLIT_REGEX = /,\s*/;
452
+ var DIGIT_KEY_REGEX = /^\d+$/;
453
+ function unwrapJsonSchema(schema) {
454
+ if (!schema || typeof schema !== "object") {
455
+ return schema;
456
+ }
457
+ const s = schema;
458
+ if (s.jsonSchema && typeof s.jsonSchema === "object") {
459
+ return unwrapJsonSchema(s.jsonSchema);
460
+ }
461
+ return schema;
462
+ }
463
+ function getSchemaType(schema) {
464
+ const unwrapped = unwrapJsonSchema(schema);
465
+ if (!unwrapped || typeof unwrapped !== "object") {
466
+ return;
467
+ }
468
+ const t = unwrapped.type;
469
+ if (typeof t === "string") {
470
+ return t;
471
+ }
472
+ if (Array.isArray(t)) {
473
+ const preferred = [
474
+ "object",
475
+ "array",
476
+ "boolean",
477
+ "number",
478
+ "integer",
479
+ "string"
480
+ ];
481
+ for (const p of preferred) {
482
+ if (t.includes(p)) {
483
+ return p;
484
+ }
485
+ }
486
+ }
487
+ const s = unwrapped;
488
+ if (s && typeof s === "object" && (s.properties || s.additionalProperties)) {
489
+ return "object";
490
+ }
491
+ if (s && typeof s === "object" && (s.items || s.prefixItems)) {
492
+ return "array";
493
+ }
494
+ return;
495
+ }
496
+ function coerceStringWithoutSchema(value) {
497
+ const s = value.trim();
498
+ const lower = s.toLowerCase();
499
+ if (lower === "true") {
500
+ return true;
501
+ }
502
+ if (lower === "false") {
503
+ return false;
504
+ }
505
+ if (NUMERIC_REGEX.test(s)) {
506
+ const num = Number(s);
507
+ if (Number.isFinite(num)) {
508
+ return num;
509
+ }
510
+ }
511
+ if (s.startsWith("{") && s.endsWith("}") || s.startsWith("[") && s.endsWith("]")) {
512
+ try {
513
+ const parsed = JSON.parse(s);
514
+ return coerceBySchema(parsed, void 0);
515
+ } catch (e) {
516
+ }
517
+ }
518
+ return value;
519
+ }
520
+ function coerceStringToObject(s, unwrapped) {
521
+ try {
522
+ let normalized = s.replace(/'/g, '"');
523
+ normalized = normalized.replace(EMPTY_OBJECT_REGEX, "{}");
524
+ const obj = JSON.parse(normalized);
525
+ if (obj && typeof obj === "object" && !Array.isArray(obj)) {
526
+ const props = unwrapped.properties;
527
+ const out = {};
528
+ for (const [k, v] of Object.entries(obj)) {
529
+ const propSchema = props ? props[k] : void 0;
530
+ out[k] = typeof propSchema === "boolean" ? v : coerceBySchema(v, propSchema);
531
+ }
532
+ return out;
533
+ }
534
+ } catch (e) {
535
+ }
536
+ return null;
537
+ }
538
+ function coerceStringToArray(s, unwrapped) {
539
+ const prefixItems = Array.isArray(unwrapped.prefixItems) ? unwrapped.prefixItems : void 0;
540
+ const itemsSchema = unwrapped.items;
541
+ try {
542
+ const normalized = s.replace(/'/g, '"');
543
+ const arr = JSON.parse(normalized);
544
+ if (Array.isArray(arr)) {
545
+ if (prefixItems && arr.length === prefixItems.length) {
546
+ return arr.map((v, i) => coerceBySchema(v, prefixItems[i]));
547
+ }
548
+ return arr.map((v) => coerceBySchema(v, itemsSchema));
549
+ }
550
+ } catch (e) {
551
+ const csv = s.includes("\n") ? s.split(NEWLINE_SPLIT_REGEX) : s.split(COMMA_SPLIT_REGEX);
552
+ const trimmed = csv.map((x) => x.trim()).filter((x) => x.length > 0);
553
+ if (prefixItems && trimmed.length === prefixItems.length) {
554
+ return trimmed.map((x, i) => coerceBySchema(x, prefixItems[i]));
555
+ }
556
+ return trimmed.map((x) => coerceBySchema(x, itemsSchema));
557
+ }
558
+ return null;
559
+ }
560
+ function coerceObjectToObject(value, unwrapped) {
561
+ const out = {};
562
+ const props = unwrapped.properties;
563
+ for (const [k, v] of Object.entries(value)) {
564
+ const propSchema = props ? props[k] : void 0;
565
+ out[k] = typeof propSchema === "boolean" ? v : coerceBySchema(v, propSchema);
566
+ }
567
+ return out;
568
+ }
569
+ function coerceArrayToArray(value, prefixItems, itemsSchema) {
570
+ if (prefixItems && value.length === prefixItems.length) {
571
+ return value.map((v, i) => coerceBySchema(v, prefixItems[i]));
572
+ }
573
+ return value.map((v) => coerceBySchema(v, itemsSchema));
574
+ }
575
+ function coerceObjectToArray(maybe, prefixItems, itemsSchema) {
576
+ if (Object.hasOwn(maybe, "item")) {
577
+ const items = maybe.item;
578
+ const arr = Array.isArray(items) ? items : [items];
579
+ return coerceArrayToArray(arr, prefixItems, itemsSchema);
580
+ }
581
+ const keys = Object.keys(maybe);
582
+ if (keys.length === 1) {
583
+ const singleValue = maybe[keys[0]];
584
+ if (Array.isArray(singleValue)) {
585
+ return singleValue.map((v) => coerceBySchema(v, itemsSchema));
586
+ }
587
+ }
588
+ if (keys.length > 0 && keys.every((k) => DIGIT_KEY_REGEX.test(k))) {
589
+ const arr = keys.sort((a, b) => Number(a) - Number(b)).map((k) => maybe[k]);
590
+ return coerceArrayToArray(arr, prefixItems, itemsSchema);
591
+ }
592
+ return null;
593
+ }
594
+ function coercePrimitiveToArray(value, prefixItems, itemsSchema) {
595
+ if (prefixItems && prefixItems.length > 0) {
596
+ return [coerceBySchema(value, prefixItems[0])];
597
+ }
598
+ return [coerceBySchema(value, itemsSchema)];
599
+ }
600
+ function coerceStringToPrimitive(s, schemaType) {
601
+ if (schemaType === "boolean") {
602
+ const lower = s.toLowerCase();
603
+ if (lower === "true") {
604
+ return true;
605
+ }
606
+ if (lower === "false") {
607
+ return false;
608
+ }
609
+ }
610
+ if ((schemaType === "number" || schemaType === "integer") && NUMERIC_REGEX.test(s)) {
611
+ const num = Number(s);
612
+ if (Number.isFinite(num)) {
613
+ return num;
614
+ }
615
+ }
616
+ return null;
617
+ }
618
+ function coerceStringValue(value, schemaType, u) {
619
+ const s = value.trim();
620
+ if (schemaType === "object") {
621
+ const result = coerceStringToObject(s, u);
622
+ if (result !== null) {
623
+ return result;
624
+ }
625
+ }
626
+ if (schemaType === "array") {
627
+ const result = coerceStringToArray(s, u);
628
+ if (result !== null) {
629
+ return result;
630
+ }
631
+ }
632
+ const primitiveResult = coerceStringToPrimitive(s, schemaType);
633
+ if (primitiveResult !== null) {
634
+ return primitiveResult;
635
+ }
636
+ return value;
637
+ }
638
+ function coerceArrayValue(value, prefixItems, itemsSchema) {
639
+ if (Array.isArray(value)) {
640
+ return coerceArrayToArray(value, prefixItems, itemsSchema);
641
+ }
642
+ if (value && typeof value === "object") {
643
+ const result = coerceObjectToArray(
644
+ value,
645
+ prefixItems,
646
+ itemsSchema
647
+ );
648
+ if (result !== null) {
649
+ return result;
650
+ }
651
+ }
652
+ if (value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
653
+ return coercePrimitiveToArray(value, prefixItems, itemsSchema);
654
+ }
655
+ return value;
656
+ }
657
+ function coerceBySchema(value, schema) {
658
+ const unwrapped = unwrapJsonSchema(schema);
659
+ if (!unwrapped || typeof unwrapped !== "object") {
660
+ if (typeof value === "string") {
661
+ return coerceStringWithoutSchema(value);
662
+ }
663
+ return value;
664
+ }
665
+ const schemaType = getSchemaType(unwrapped);
666
+ const u = unwrapped;
667
+ if (typeof value === "string") {
668
+ return coerceStringValue(value, schemaType, u);
669
+ }
670
+ if (schemaType === "object" && value && typeof value === "object" && !Array.isArray(value)) {
671
+ return coerceObjectToObject(value, u);
672
+ }
673
+ if (schemaType === "array") {
674
+ const prefixItems = Array.isArray(u.prefixItems) ? u.prefixItems : void 0;
675
+ const itemsSchema = u.items;
676
+ return coerceArrayValue(value, prefixItems, itemsSchema);
677
+ }
678
+ return value;
679
+ }
680
+
681
+ // src/schema/coercion.ts
682
+ function getPropertySchema(toolSchema, key) {
683
+ const unwrapped = unwrapJsonSchema(toolSchema);
684
+ if (!unwrapped || typeof unwrapped !== "object") {
685
+ return;
686
+ }
687
+ const u = unwrapped;
688
+ const props = u.properties;
689
+ if (props && Object.hasOwn(props, key)) {
690
+ return props[key];
691
+ }
692
+ return;
693
+ }
694
+ function getNodeValue(children, schema, tagName, textNodeName) {
695
+ if (children.length === 0) {
696
+ return "";
697
+ }
698
+ if (children.length === 1 && typeof children[0] === "string") {
699
+ return children[0];
700
+ }
701
+ return processComplexContent(
702
+ children,
703
+ getPropertySchema(schema, tagName),
704
+ textNodeName
705
+ );
706
+ }
707
+ function addAttributesToValue(value, attributes, textNodeName) {
708
+ if (Object.keys(attributes).length === 0) {
709
+ return value;
710
+ }
711
+ if (typeof value === "string") {
712
+ const valueResult = { [textNodeName]: value };
713
+ for (const [attrName, attrValue] of Object.entries(attributes)) {
714
+ valueResult[`@_${attrName}`] = attrValue;
715
+ }
716
+ return valueResult;
717
+ }
718
+ if (value && typeof value === "object" && !Array.isArray(value)) {
719
+ for (const [attrName, attrValue] of Object.entries(attributes)) {
720
+ value[`@_${attrName}`] = attrValue;
721
+ }
722
+ }
723
+ return value;
724
+ }
725
+ function addToResult(result, tagName, value) {
726
+ if (result[tagName]) {
727
+ if (!Array.isArray(result[tagName])) {
728
+ result[tagName] = [result[tagName]];
729
+ }
730
+ result[tagName].push(value);
731
+ } else {
732
+ result[tagName] = value;
733
+ }
734
+ }
735
+ function domToObject(nodes, schema, textNodeName = "#text") {
736
+ const result = {};
737
+ for (const node of nodes) {
738
+ if (typeof node === "string") {
739
+ continue;
740
+ }
741
+ const { tagName, children, attributes } = node;
742
+ let value = getNodeValue(children, schema, tagName, textNodeName);
743
+ value = addAttributesToValue(value, attributes, textNodeName);
744
+ addToResult(result, tagName, value);
745
+ }
746
+ return result;
747
+ }
748
+ function processChildElement(child, schema, textNodeName) {
749
+ let childValue;
750
+ if (child.children.length === 0) {
751
+ childValue = "";
752
+ } else if (child.children.length === 1 && typeof child.children[0] === "string") {
753
+ childValue = child.children[0];
754
+ } else {
755
+ childValue = processComplexContent(
756
+ child.children,
757
+ getPropertySchema(schema, child.tagName),
758
+ textNodeName
759
+ );
760
+ }
761
+ return addAttributesToValue(childValue, child.attributes, textNodeName);
762
+ }
763
+ function combineContent(textContent, elements, textNodeName) {
764
+ const hasText = textContent.length > 0;
765
+ const hasElements = Object.keys(elements).length > 0;
766
+ if (hasText && hasElements) {
767
+ return {
768
+ [textNodeName]: textContent.join("").trim(),
769
+ ...elements
770
+ };
771
+ }
772
+ if (hasText) {
773
+ return textContent.join("").trim();
774
+ }
775
+ if (hasElements) {
776
+ return elements;
777
+ }
778
+ return "";
779
+ }
780
+ function processComplexContent(children, schema, textNodeName) {
781
+ const textContent = [];
782
+ const elements = {};
783
+ for (const child of children) {
784
+ if (typeof child === "string") {
785
+ textContent.push(child);
786
+ } else {
787
+ const childValue = processChildElement(child, schema, textNodeName);
788
+ addToResult(elements, child.tagName, childValue);
789
+ }
790
+ }
791
+ return combineContent(textContent, elements, textNodeName);
792
+ }
793
+ function coerceDomBySchema(domObject, schema) {
794
+ try {
795
+ return coerceBySchema(domObject, schema);
796
+ } catch (error) {
797
+ throw new RXMLCoercionError("Failed to coerce DOM object by schema", error);
798
+ }
799
+ }
800
+ function visitObjectProperties(props, collected, visit) {
801
+ for (const [key, propSchema] of Object.entries(props)) {
802
+ const t = getSchemaType(propSchema);
803
+ if (t === "string") {
804
+ collected.add(key);
805
+ } else if (t === "object" || t === "array") {
806
+ visit(propSchema);
807
+ }
808
+ }
809
+ }
810
+ function visitArrayItems(u, visit) {
811
+ const items = u.items;
812
+ if (items) {
813
+ visit(items);
814
+ }
815
+ const prefix = u.prefixItems;
816
+ if (Array.isArray(prefix)) {
817
+ for (const item of prefix) {
818
+ visit(item);
819
+ }
820
+ }
821
+ }
822
+ function getStringTypedProperties(schema) {
823
+ const collected = /* @__PURE__ */ new Set();
824
+ const visit = (s) => {
825
+ const unwrapped = unwrapJsonSchema(s);
826
+ if (!unwrapped || typeof unwrapped !== "object") {
827
+ return;
828
+ }
829
+ const u = unwrapped;
830
+ const type = getSchemaType(unwrapped);
831
+ if (type === "object") {
832
+ const props = u.properties;
833
+ if (props && typeof props === "object") {
834
+ visitObjectProperties(props, collected, visit);
835
+ }
836
+ } else if (type === "array") {
837
+ visitArrayItems(u, visit);
838
+ }
839
+ };
840
+ visit(schema);
841
+ return collected;
842
+ }
843
+ function processArrayContent(value, schema, textNodeName) {
844
+ if (!Array.isArray(value)) {
845
+ return value;
846
+ }
847
+ const schemaType = getSchemaType(schema);
848
+ if (schemaType === "string") {
849
+ return value.map((item) => {
850
+ if (typeof item === "string") {
851
+ return item.trim();
852
+ }
853
+ if (item && typeof item === "object" && textNodeName in item) {
854
+ const textVal = item[textNodeName];
855
+ return typeof textVal === "string" ? textVal.trim() : String(textVal);
856
+ }
857
+ return String(item);
858
+ });
859
+ }
860
+ return value.map((item) => {
861
+ if (typeof item === "string") {
862
+ return item.trim();
863
+ }
864
+ if (item && typeof item === "object" && textNodeName in item) {
865
+ const textVal = item[textNodeName];
866
+ return typeof textVal === "string" ? textVal.trim() : textVal;
867
+ }
868
+ return item;
869
+ });
870
+ }
871
+ function processIndexedTuple(obj, textNodeName) {
872
+ const keys = Object.keys(obj);
873
+ const indices = keys.map((k) => Number.parseInt(k, 10)).sort((a, b) => a - b);
874
+ const isValidTuple = indices[0] === 0 && indices.every((val, idx) => val === idx);
875
+ if (!isValidTuple) {
876
+ return [obj];
877
+ }
878
+ const sortedKeys = keys.sort(
879
+ (a, b) => Number.parseInt(a, 10) - Number.parseInt(b, 10)
880
+ );
881
+ return sortedKeys.map((key) => {
882
+ const item = obj[key];
883
+ if (item && typeof item === "object" && textNodeName in item) {
884
+ const textVal = item[textNodeName];
885
+ return typeof textVal === "string" ? textVal.trim() : textVal;
886
+ }
887
+ return typeof item === "string" ? item.trim() : item;
888
+ });
889
+ }
890
+
891
+ // src/schema/extraction.ts
892
+ function skipDoctype(xmlContent, i, len) {
893
+ const gt = xmlContent.indexOf(">", i + 1);
894
+ return gt === -1 ? len : gt + 1;
895
+ }
896
+ function skipComment(xmlContent, i, len) {
897
+ const close = xmlContent.indexOf("-->", i + 4);
898
+ return close === -1 ? len : close + 3;
899
+ }
900
+ function skipCdata(xmlContent, i, len) {
901
+ const close = xmlContent.indexOf("]]>", i + 9);
902
+ return close === -1 ? len : close + 3;
903
+ }
904
+ function skipProcessingInstruction(xmlContent, i, len) {
905
+ const close = xmlContent.indexOf("?>", i + 1);
906
+ return close === -1 ? len : close + 2;
907
+ }
908
+ function skipSpecialConstruct(xmlContent, i, len) {
909
+ const ch = xmlContent[i];
910
+ if (ch === "!") {
911
+ if (xmlContent.startsWith("!DOCTYPE", i + 1)) {
912
+ return skipDoctype(xmlContent, i, len);
913
+ }
914
+ if (xmlContent.startsWith("!--", i + 1)) {
915
+ return skipComment(xmlContent, i, len);
916
+ }
917
+ if (xmlContent.startsWith("![CDATA[", i + 1)) {
918
+ return skipCdata(xmlContent, i, len);
919
+ }
920
+ const gt = xmlContent.indexOf(">", i + 1);
921
+ return gt === -1 ? len : gt + 1;
922
+ }
923
+ if (ch === "?") {
924
+ return skipProcessingInstruction(xmlContent, i, len);
925
+ }
926
+ return -1;
927
+ }
928
+ function parseTagName(xmlContent, i, len) {
929
+ let j = i;
930
+ if (j < len && isNameStartChar(xmlContent[j])) {
931
+ j += 1;
932
+ while (j < len && isNameChar(xmlContent[j])) {
933
+ j += 1;
934
+ }
935
+ }
936
+ return { name: xmlContent.slice(i, j), pos: j };
937
+ }
938
+ function skipToTagEnd(xmlContent, start, len) {
939
+ let k = start;
940
+ let isSelfClosing = false;
941
+ while (k < len) {
942
+ const c = xmlContent[k];
943
+ if (c === '"' || c === "'") {
944
+ k = skipQuoted(xmlContent, k);
945
+ continue;
946
+ }
947
+ if (c === ">") {
948
+ break;
949
+ }
950
+ if (c === "/" && xmlContent[k + 1] === ">") {
951
+ isSelfClosing = true;
952
+ k += 1;
953
+ break;
954
+ }
955
+ k += 1;
956
+ }
957
+ return { pos: k, isSelfClosing };
958
+ }
959
+ function processClosingTagMatch(options) {
960
+ const { xmlContent, nx, len, tagName, depth, nextLt } = options;
961
+ const tagInfo = parseTagName(xmlContent, nx + 1, len);
962
+ const gt = xmlContent.indexOf(">", tagInfo.pos);
963
+ if (tagInfo.name === tagName) {
964
+ const newDepth = depth - 1;
965
+ if (newDepth === 0) {
966
+ return { newPos: nextLt, newDepth, found: true };
967
+ }
968
+ return { newPos: gt === -1 ? len : gt + 1, newDepth, found: false };
969
+ }
970
+ return { newPos: gt === -1 ? len : gt + 1, newDepth: depth, found: false };
971
+ }
972
+ function processOpeningTagMatch(options) {
973
+ const { xmlContent, nx, len, tagName, depth } = options;
974
+ const tagInfo = parseTagName(xmlContent, nx, len);
975
+ const tagEndInfo = skipToTagEnd(xmlContent, tagInfo.pos, len);
976
+ const newDepth = tagInfo.name === tagName && !tagEndInfo.isSelfClosing ? depth + 1 : depth;
977
+ const newPos = xmlContent[tagEndInfo.pos] === ">" ? tagEndInfo.pos + 1 : tagEndInfo.pos + 1;
978
+ return { newPos, newDepth };
979
+ }
980
+ function findMatchingCloseTag(xmlContent, startPos, tagName, len) {
981
+ let pos = startPos;
982
+ let depth = 1;
983
+ while (pos < len) {
984
+ const nextLt = xmlContent.indexOf("<", pos);
985
+ if (nextLt === -1 || nextLt + 1 >= len) {
986
+ break;
987
+ }
988
+ const nx = nextLt + 1;
989
+ const h = xmlContent[nx];
990
+ const specialPos = skipSpecialConstruct(xmlContent, nx, len);
991
+ if (specialPos !== -1) {
992
+ pos = specialPos;
993
+ continue;
994
+ }
995
+ if (h === "/") {
996
+ const result = processClosingTagMatch({
997
+ xmlContent,
998
+ nx,
999
+ len,
1000
+ tagName,
1001
+ depth,
1002
+ nextLt
1003
+ });
1004
+ if (result.found) {
1005
+ return result.newPos;
1006
+ }
1007
+ pos = result.newPos;
1008
+ depth = result.newDepth;
1009
+ } else {
1010
+ const result = processOpeningTagMatch({
1011
+ xmlContent,
1012
+ nx,
1013
+ len,
1014
+ tagName,
1015
+ depth
1016
+ });
1017
+ pos = result.newPos;
1018
+ depth = result.newDepth;
1019
+ }
1020
+ }
1021
+ return -1;
1022
+ }
1023
+ function updateBestMatch(depth, bestDepth, contentStart, contentEnd) {
1024
+ if (depth < bestDepth) {
1025
+ return { start: contentStart, end: contentEnd, depth };
1026
+ }
1027
+ return null;
1028
+ }
1029
+ function processTargetTag(options) {
1030
+ const { xmlContent, tagEnd, isSelfClosing, target, len, depth, bestDepth } = options;
1031
+ const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1032
+ if (isSelfClosing) {
1033
+ return updateBestMatch(depth, bestDepth, contentStart, contentStart);
1034
+ }
1035
+ const closePos = findMatchingCloseTag(xmlContent, contentStart, target, len);
1036
+ if (closePos !== -1) {
1037
+ return updateBestMatch(depth, bestDepth, contentStart, closePos);
1038
+ }
1039
+ return null;
1040
+ }
1041
+ function handleClosingTagInExtract(xmlContent, i, len, depth) {
1042
+ const gt = xmlContent.indexOf(">", i + 1);
1043
+ return {
1044
+ newPos: gt === -1 ? len : gt + 1,
1045
+ newDepth: Math.max(0, depth - 1)
1046
+ };
1047
+ }
1048
+ function processOpeningTagInExtract(options) {
1049
+ const { xmlContent, i, len, target, depth, bestDepth } = options;
1050
+ const tagInfo = parseTagName(xmlContent, i, len);
1051
+ const tagEndInfo = skipToTagEnd(xmlContent, tagInfo.pos, len);
1052
+ const tagEnd = tagEndInfo.pos;
1053
+ const isSelfClosing = tagEndInfo.isSelfClosing;
1054
+ let bestMatch = null;
1055
+ if (tagInfo.name === target) {
1056
+ bestMatch = processTargetTag({
1057
+ xmlContent,
1058
+ tagEnd,
1059
+ isSelfClosing,
1060
+ target,
1061
+ len,
1062
+ depth,
1063
+ bestDepth
1064
+ });
1065
+ }
1066
+ return {
1067
+ newPos: xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1,
1068
+ newDepth: depth + (isSelfClosing ? 0 : 1),
1069
+ bestMatch
1070
+ };
1071
+ }
1072
+ function extractRawInner(xmlContent, tagName) {
1073
+ const len = xmlContent.length;
1074
+ const target = tagName;
1075
+ let bestStart = -1;
1076
+ let bestEnd = -1;
1077
+ let bestDepth = Number.POSITIVE_INFINITY;
1078
+ let i = 0;
1079
+ let depth = 0;
1080
+ while (i < len) {
1081
+ const lt = xmlContent.indexOf("<", i);
1082
+ if (lt === -1 || lt + 1 >= len) {
1083
+ return;
1084
+ }
1085
+ i = lt + 1;
1086
+ const ch = xmlContent[i];
1087
+ const specialPos = skipSpecialConstruct(xmlContent, i, len);
1088
+ if (specialPos !== -1) {
1089
+ i = specialPos;
1090
+ continue;
1091
+ }
1092
+ if (ch === "/") {
1093
+ const result2 = handleClosingTagInExtract(xmlContent, i, len, depth);
1094
+ i = result2.newPos;
1095
+ depth = result2.newDepth;
1096
+ continue;
1097
+ }
1098
+ const result = processOpeningTagInExtract({
1099
+ xmlContent,
1100
+ i,
1101
+ len,
1102
+ target,
1103
+ depth,
1104
+ bestDepth
1105
+ });
1106
+ if (result.bestMatch) {
1107
+ bestStart = result.bestMatch.start;
1108
+ bestEnd = result.bestMatch.end;
1109
+ bestDepth = result.bestMatch.depth;
1110
+ }
1111
+ i = result.newPos;
1112
+ depth = result.newDepth;
1113
+ }
1114
+ if (bestStart !== -1) {
1115
+ return xmlContent.slice(bestStart, bestEnd);
1116
+ }
1117
+ return;
1118
+ }
1119
+ function processOpeningTag(options) {
1120
+ const { xmlContent, tagEnd, isSelfClosing, target, len, ranges } = options;
1121
+ const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1122
+ if (isSelfClosing) {
1123
+ ranges.push({ start: contentStart, end: contentStart });
1124
+ return contentStart;
1125
+ }
1126
+ const closePos = findMatchingCloseTag(xmlContent, contentStart, target, len);
1127
+ if (closePos !== -1) {
1128
+ ranges.push({ start: contentStart, end: closePos });
1129
+ const gt = xmlContent.indexOf(">", closePos);
1130
+ return gt === -1 ? len : gt + 1;
1131
+ }
1132
+ return -1;
1133
+ }
1134
+ function handleClosingTagInFindAll(xmlContent, i, len) {
1135
+ const gt = xmlContent.indexOf(">", i + 1);
1136
+ return gt === -1 ? len : gt + 1;
1137
+ }
1138
+ function findAllInnerRanges(xmlContent, tagName) {
1139
+ const len = xmlContent.length;
1140
+ const target = tagName;
1141
+ const ranges = [];
1142
+ let i = 0;
1143
+ while (i < len) {
1144
+ const lt = xmlContent.indexOf("<", i);
1145
+ if (lt === -1 || lt + 1 >= len) {
1146
+ break;
1147
+ }
1148
+ i = lt + 1;
1149
+ const ch = xmlContent[i];
1150
+ const specialPos = skipSpecialConstruct(xmlContent, i, len);
1151
+ if (specialPos !== -1) {
1152
+ i = specialPos;
1153
+ continue;
1154
+ }
1155
+ if (ch === "/") {
1156
+ i = handleClosingTagInFindAll(xmlContent, i, len);
1157
+ continue;
1158
+ }
1159
+ const tagInfo = parseTagName(xmlContent, i, len);
1160
+ const tagEndInfo = skipToTagEnd(xmlContent, tagInfo.pos, len);
1161
+ const tagEnd = tagEndInfo.pos;
1162
+ const isSelfClosing = tagEndInfo.isSelfClosing;
1163
+ if (tagInfo.name !== target) {
1164
+ i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1165
+ continue;
1166
+ }
1167
+ const nextPos = processOpeningTag({
1168
+ xmlContent,
1169
+ tagEnd,
1170
+ isSelfClosing,
1171
+ target,
1172
+ len,
1173
+ ranges
1174
+ });
1175
+ if (nextPos === -1) {
1176
+ break;
1177
+ }
1178
+ i = nextPos;
1179
+ }
1180
+ return ranges;
1181
+ }
1182
+ function findTopLevelTargetRange(options) {
1183
+ const { xmlContent, tagEnd, isSelfClosing, target, len } = options;
1184
+ const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1185
+ if (isSelfClosing) {
1186
+ return { start: contentStart, end: contentStart };
1187
+ }
1188
+ const closePos = findMatchingCloseTag(xmlContent, contentStart, target, len);
1189
+ if (closePos !== -1) {
1190
+ return { start: contentStart, end: closePos };
1191
+ }
1192
+ return;
1193
+ }
1194
+ function handleClosingTagInFindFirst(xmlContent, i, len, depth) {
1195
+ const gt = xmlContent.indexOf(">", i + 1);
1196
+ return {
1197
+ newPos: gt === -1 ? len : gt + 1,
1198
+ newDepth: Math.max(0, depth - 1)
1199
+ };
1200
+ }
1201
+ function findFirstTopLevelRange(xmlContent, tagName) {
1202
+ const len = xmlContent.length;
1203
+ const target = tagName;
1204
+ let i = 0;
1205
+ let depth = 0;
1206
+ while (i < len) {
1207
+ const lt = xmlContent.indexOf("<", i);
1208
+ if (lt === -1 || lt + 1 >= len) {
1209
+ return;
1210
+ }
1211
+ i = lt + 1;
1212
+ const ch = xmlContent[i];
1213
+ const specialPos = skipSpecialConstruct(xmlContent, i, len);
1214
+ if (specialPos !== -1) {
1215
+ i = specialPos;
1216
+ continue;
1217
+ }
1218
+ if (ch === "/") {
1219
+ const result = handleClosingTagInFindFirst(xmlContent, i, len, depth);
1220
+ i = result.newPos;
1221
+ depth = result.newDepth;
1222
+ continue;
1223
+ }
1224
+ const tagInfo = parseTagName(xmlContent, i, len);
1225
+ const tagEndInfo = skipToTagEnd(xmlContent, tagInfo.pos, len);
1226
+ const tagEnd = tagEndInfo.pos;
1227
+ const isSelfClosing = tagEndInfo.isSelfClosing;
1228
+ if (depth === 0 && tagInfo.name === target) {
1229
+ return findTopLevelTargetRange({
1230
+ xmlContent,
1231
+ tagEnd,
1232
+ isSelfClosing,
1233
+ target,
1234
+ len
1235
+ });
1236
+ }
1237
+ i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
1238
+ depth += isSelfClosing ? 0 : 1;
1239
+ }
1240
+ return;
1241
+ }
1242
+ function isPositionExcluded(pos, excludeRanges) {
1243
+ if (!excludeRanges || excludeRanges.length === 0) {
1244
+ return false;
1245
+ }
1246
+ for (const r of excludeRanges) {
1247
+ if (pos >= r.start && pos < r.end) {
1248
+ return true;
1249
+ }
1250
+ }
1251
+ return false;
1252
+ }
1253
+ function skipCommentInCounting(xmlContent, i, len) {
1254
+ const close = xmlContent.indexOf("-->", i + 4);
1255
+ return close === -1 ? len : close + 3;
1256
+ }
1257
+ function skipCdataInCounting(xmlContent, i, len) {
1258
+ const close = xmlContent.indexOf("]]>", i + 9);
1259
+ return close === -1 ? len : close + 3;
1260
+ }
1261
+ function skipSpecialInCounting(xmlContent, ch, i, len) {
1262
+ if (ch === "!") {
1263
+ if (xmlContent.startsWith("!--", i + 1)) {
1264
+ return skipCommentInCounting(xmlContent, i, len);
1265
+ }
1266
+ if (xmlContent.startsWith("![CDATA[", i + 1)) {
1267
+ return skipCdataInCounting(xmlContent, i, len);
1268
+ }
1269
+ const gt = xmlContent.indexOf(">", i + 1);
1270
+ return gt === -1 ? len : gt + 1;
1271
+ }
1272
+ if (ch === "?") {
1273
+ const close = xmlContent.indexOf("?>", i + 1);
1274
+ return close === -1 ? len : close + 2;
1275
+ }
1276
+ if (ch === "/") {
1277
+ const gt = xmlContent.indexOf(">", i + 1);
1278
+ return gt === -1 ? len : gt + 1;
1279
+ }
1280
+ return -1;
1281
+ }
1282
+ function parseAndCountTag(options) {
1283
+ const { xmlContent, i, len, target, lt, excludeRanges } = options;
1284
+ let j = i;
1285
+ if (j < len && isNameStartChar(xmlContent[j])) {
1286
+ j += 1;
1287
+ while (j < len && isNameChar(xmlContent[j])) {
1288
+ j += 1;
1289
+ }
1290
+ }
1291
+ const name = xmlContent.slice(i, j);
1292
+ let k = j;
1293
+ while (k < len) {
1294
+ const c = xmlContent[k];
1295
+ if (c === '"' || c === "'") {
1296
+ k = skipQuoted(xmlContent, k);
1297
+ continue;
1298
+ }
1299
+ if (c === ">") {
1300
+ break;
656
1301
  }
1302
+ if (c === "/" && xmlContent[k + 1] === ">") {
1303
+ k += 1;
1304
+ break;
1305
+ }
1306
+ k += 1;
657
1307
  }
658
- if (bestStart !== -1) {
659
- return xmlContent.slice(bestStart, bestEnd);
660
- }
661
- return void 0;
1308
+ const shouldCount = name === target && !isPositionExcluded(lt, excludeRanges);
1309
+ return { nextPos: k + 1, shouldCount };
662
1310
  }
663
- function findFirstTopLevelRange(xmlContent, tagName) {
1311
+ function countTagOccurrences(xmlContent, tagName, excludeRanges, shouldSkipFirst = true) {
664
1312
  const len = xmlContent.length;
665
1313
  const target = tagName;
666
1314
  let i = 0;
667
- let depth = 0;
1315
+ let count = 0;
1316
+ let skipFirstLocal = shouldSkipFirst;
668
1317
  while (i < len) {
669
1318
  const lt = xmlContent.indexOf("<", i);
670
- if (lt === -1) return void 0;
1319
+ if (lt === -1) {
1320
+ break;
1321
+ }
671
1322
  i = lt + 1;
672
- if (i >= len) return void 0;
1323
+ if (i >= len) {
1324
+ break;
1325
+ }
673
1326
  const ch = xmlContent[i];
674
- if (ch === "!") {
675
- if (xmlContent.startsWith("!--", i + 1)) {
676
- const close = xmlContent.indexOf("-->", i + 4);
677
- i = close === -1 ? len : close + 3;
678
- continue;
679
- }
680
- if (xmlContent.startsWith("![CDATA[", i + 1)) {
681
- const close = xmlContent.indexOf("]]>", i + 9);
682
- i = close === -1 ? len : close + 3;
683
- continue;
684
- }
685
- const gt = xmlContent.indexOf(">", i + 1);
686
- i = gt === -1 ? len : gt + 1;
687
- continue;
688
- } else if (ch === "?") {
689
- const close = xmlContent.indexOf("?>", i + 1);
690
- i = close === -1 ? len : close + 2;
691
- continue;
692
- } else if (ch === "/") {
693
- const gt = xmlContent.indexOf(">", i + 1);
694
- i = gt === -1 ? len : gt + 1;
695
- depth = Math.max(0, depth - 1);
1327
+ const skipPos = skipSpecialInCounting(xmlContent, ch, i, len);
1328
+ if (skipPos !== -1) {
1329
+ i = skipPos;
696
1330
  continue;
697
- } else {
698
- let j = i;
699
- if (j < len && isNameStartChar(xmlContent[j])) {
700
- j++;
701
- while (j < len && isNameChar(xmlContent[j])) j++;
702
- }
703
- const name = xmlContent.slice(i, j);
704
- let k = j;
705
- let isSelfClosing = false;
706
- while (k < len) {
707
- const c = xmlContent[k];
708
- if (c === '"' || c === "'") {
709
- k = skipQuoted(xmlContent, k);
710
- continue;
711
- }
712
- if (c === ">") break;
713
- if (c === "/" && xmlContent[k + 1] === ">") {
714
- isSelfClosing = true;
715
- k++;
716
- break;
717
- }
718
- k++;
719
- }
720
- const tagEnd = k;
721
- if (depth === 0 && name === target) {
722
- const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
723
- if (isSelfClosing) return { start: contentStart, end: contentStart };
724
- let pos = contentStart;
725
- let sameDepth = 1;
726
- while (pos < len) {
727
- const nextLt = xmlContent.indexOf("<", pos);
728
- if (nextLt === -1) break;
729
- const nx = nextLt + 1;
730
- if (nx >= len) break;
731
- const h = xmlContent[nx];
732
- if (h === "!") {
733
- if (xmlContent.startsWith("!--", nx + 1)) {
734
- const close = xmlContent.indexOf("-->", nx + 4);
735
- pos = close === -1 ? len : close + 3;
736
- continue;
737
- }
738
- if (xmlContent.startsWith("![CDATA[", nx + 1)) {
739
- const close = xmlContent.indexOf("]]>", nx + 9);
740
- pos = close === -1 ? len : close + 3;
741
- continue;
742
- }
743
- const gt2 = xmlContent.indexOf(">", nx + 1);
744
- pos = gt2 === -1 ? len : gt2 + 1;
745
- continue;
746
- } else if (h === "?") {
747
- const close = xmlContent.indexOf("?>", nx + 1);
748
- pos = close === -1 ? len : close + 2;
749
- continue;
750
- } else if (h === "/") {
751
- let t = nx + 1;
752
- if (t < len && isNameStartChar(xmlContent[t])) {
753
- t++;
754
- while (t < len && isNameChar(xmlContent[t])) t++;
755
- }
756
- const endName = xmlContent.slice(nx + 1, t);
757
- const gt2 = xmlContent.indexOf(">", t);
758
- if (endName === target) {
759
- sameDepth--;
760
- if (sameDepth === 0) {
761
- return { start: contentStart, end: nextLt };
762
- }
763
- }
764
- pos = gt2 === -1 ? len : gt2 + 1;
765
- continue;
766
- } else {
767
- let t = nx;
768
- if (t < len && isNameStartChar(xmlContent[t])) {
769
- t++;
770
- while (t < len && isNameChar(xmlContent[t])) t++;
771
- }
772
- const startName = xmlContent.slice(nx, t);
773
- let u = t;
774
- let isSelfClosingNested = false;
775
- while (u < len) {
776
- const cu = xmlContent[u];
777
- if (cu === '"' || cu === "'") {
778
- u = skipQuoted(xmlContent, u);
779
- continue;
780
- }
781
- if (cu === ">") break;
782
- if (cu === "/" && xmlContent[u + 1] === ">") {
783
- isSelfClosingNested = true;
784
- u++;
785
- break;
786
- }
787
- u++;
788
- }
789
- if (startName === target && !isSelfClosingNested) {
790
- sameDepth++;
791
- }
792
- pos = xmlContent[u] === ">" ? u + 1 : u + 1;
793
- continue;
794
- }
795
- }
796
- return void 0;
1331
+ }
1332
+ const result = parseAndCountTag({
1333
+ xmlContent,
1334
+ i,
1335
+ len,
1336
+ target,
1337
+ lt,
1338
+ excludeRanges
1339
+ });
1340
+ if (result.shouldCount) {
1341
+ if (skipFirstLocal) {
1342
+ skipFirstLocal = false;
1343
+ } else {
1344
+ count += 1;
797
1345
  }
798
- i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
799
- depth += isSelfClosing ? 0 : 1;
1346
+ }
1347
+ i = result.nextPos;
1348
+ }
1349
+ return count;
1350
+ }
1351
+ function skipAttributes(xmlContent, i, len) {
1352
+ let k = i;
1353
+ while (k < len && xmlContent[k] !== ">") {
1354
+ const c = xmlContent[k];
1355
+ if (c === '"' || c === "'") {
1356
+ k = skipQuoted(xmlContent, k);
800
1357
  continue;
801
1358
  }
1359
+ if (c === "/" && xmlContent[k + 1] === ">") {
1360
+ k += 1;
1361
+ break;
1362
+ }
1363
+ k += 1;
802
1364
  }
803
- return void 0;
1365
+ return k;
804
1366
  }
805
- function countTagOccurrences(xmlContent, tagName, excludeRanges, shouldSkipFirst = true) {
1367
+ function updateDepthForClosingTag(xmlContent, nextLt, target, closeDepth) {
1368
+ const { name: closeName } = parseName(xmlContent, nextLt + 2);
1369
+ return closeName === target ? closeDepth - 1 : closeDepth;
1370
+ }
1371
+ function updateDepthForOpeningTag(xmlContent, nextLt, target, closeDepth) {
1372
+ const { name: openName } = parseName(xmlContent, nextLt + 1);
1373
+ return openName === target ? closeDepth + 1 : closeDepth;
1374
+ }
1375
+ function findClosingTagForRange(xmlContent, k, len, target) {
1376
+ let closeDepth = 1;
1377
+ let j = k + 1;
1378
+ while (j < len && closeDepth > 0) {
1379
+ const nextLt = xmlContent.indexOf("<", j);
1380
+ if (nextLt === -1) {
1381
+ break;
1382
+ }
1383
+ if (xmlContent[nextLt + 1] === "/") {
1384
+ closeDepth = updateDepthForClosingTag(
1385
+ xmlContent,
1386
+ nextLt,
1387
+ target,
1388
+ closeDepth
1389
+ );
1390
+ } else if (xmlContent[nextLt + 1] !== "!" && xmlContent[nextLt + 1] !== "?") {
1391
+ closeDepth = updateDepthForOpeningTag(
1392
+ xmlContent,
1393
+ nextLt,
1394
+ target,
1395
+ closeDepth
1396
+ );
1397
+ }
1398
+ j = xmlContent.indexOf(">", nextLt + 1);
1399
+ if (j === -1) {
1400
+ break;
1401
+ }
1402
+ j += 1;
1403
+ }
1404
+ return closeDepth === 0 ? j : -1;
1405
+ }
1406
+ function processTopLevelTarget(options) {
1407
+ const { xmlContent, tagStart, k, len, target, ranges } = options;
1408
+ const isSelfClosing = xmlContent[k] === "/" || xmlContent.startsWith("/>", k);
1409
+ if (isSelfClosing) {
1410
+ ranges.push({
1411
+ start: tagStart,
1412
+ end: k + (xmlContent[k] === "/" ? 2 : 1)
1413
+ });
1414
+ return { newDepth: 0 };
1415
+ }
1416
+ const endPos = findClosingTagForRange(xmlContent, k, len, target);
1417
+ if (endPos !== -1) {
1418
+ ranges.push({ start: tagStart, end: endPos });
1419
+ }
1420
+ return { newDepth: 0 };
1421
+ }
1422
+ function skipDoctypeInSpecial(xmlContent, i, len) {
1423
+ const gt = xmlContent.indexOf(">", i + 1);
1424
+ return gt === -1 ? len : gt + 1;
1425
+ }
1426
+ function handleSpecialConstructs(xmlContent, ch, i, len) {
1427
+ if (ch === "!") {
1428
+ if (xmlContent.startsWith("!DOCTYPE", i + 1)) {
1429
+ return skipDoctypeInSpecial(xmlContent, i, len);
1430
+ }
1431
+ if (xmlContent.startsWith("!--", i + 1)) {
1432
+ return skipCommentInCounting(xmlContent, i, len);
1433
+ }
1434
+ if (xmlContent.startsWith("![CDATA[", i + 1)) {
1435
+ return skipCdataInCounting(xmlContent, i, len);
1436
+ }
1437
+ const gt = xmlContent.indexOf(">", i + 1);
1438
+ return gt === -1 ? len : gt + 1;
1439
+ }
1440
+ if (ch === "?") {
1441
+ const close = xmlContent.indexOf("?>", i + 1);
1442
+ return close === -1 ? len : close + 2;
1443
+ }
1444
+ return -1;
1445
+ }
1446
+ function handleClosingTagInFindAllTop(xmlContent, i, target, depth) {
1447
+ const { name: closingName, newPos: closingPos } = parseName(
1448
+ xmlContent,
1449
+ i + 1
1450
+ );
1451
+ const newDepth = closingName === target ? depth - 1 : depth;
1452
+ const gt = xmlContent.indexOf(">", closingPos);
1453
+ return {
1454
+ newPos: gt === -1 ? -1 : gt + 1,
1455
+ newDepth
1456
+ };
1457
+ }
1458
+ function findAllTopLevelRanges(xmlContent, tagName) {
1459
+ const ranges = [];
806
1460
  const len = xmlContent.length;
807
1461
  const target = tagName;
808
1462
  let i = 0;
809
- let count = 0;
810
- let skipFirstLocal = shouldSkipFirst;
811
- const isExcluded = (pos) => {
812
- if (!excludeRanges || excludeRanges.length === 0) return false;
813
- for (const r of excludeRanges) {
814
- if (pos >= r.start && pos < r.end) return true;
815
- }
816
- return false;
817
- };
1463
+ let depth = 0;
818
1464
  while (i < len) {
819
1465
  const lt = xmlContent.indexOf("<", i);
820
- if (lt === -1) break;
1466
+ if (lt === -1 || lt + 1 >= len) {
1467
+ break;
1468
+ }
821
1469
  i = lt + 1;
822
- if (i >= len) break;
823
1470
  const ch = xmlContent[i];
824
- if (ch === "!") {
825
- if (xmlContent.startsWith("!--", i + 1)) {
826
- const close = xmlContent.indexOf("-->", i + 4);
827
- i = close === -1 ? len : close + 3;
828
- continue;
829
- }
830
- if (xmlContent.startsWith("![CDATA[", i + 1)) {
831
- const close = xmlContent.indexOf("]]>", i + 9);
832
- i = close === -1 ? len : close + 3;
833
- continue;
834
- }
835
- const gt = xmlContent.indexOf(">", i + 1);
836
- i = gt === -1 ? len : gt + 1;
837
- continue;
838
- } else if (ch === "?") {
839
- const close = xmlContent.indexOf("?>", i + 1);
840
- i = close === -1 ? len : close + 2;
1471
+ const specialPos = handleSpecialConstructs(xmlContent, ch, i, len);
1472
+ if (specialPos !== -1) {
1473
+ i = specialPos;
841
1474
  continue;
842
- } else if (ch === "/") {
843
- const gt = xmlContent.indexOf(">", i + 1);
844
- i = gt === -1 ? len : gt + 1;
845
- continue;
846
- } else {
847
- let j = i;
848
- if (j < len && isNameStartChar(xmlContent[j])) {
849
- j++;
850
- while (j < len && isNameChar(xmlContent[j])) j++;
851
- }
852
- const name = xmlContent.slice(i, j);
853
- let k = j;
854
- while (k < len) {
855
- const c = xmlContent[k];
856
- if (c === '"' || c === "'") {
857
- k = skipQuoted(xmlContent, k);
858
- continue;
859
- }
860
- if (c === ">") break;
861
- if (c === "/" && xmlContent[k + 1] === ">") {
862
- k++;
863
- break;
864
- }
865
- k++;
866
- }
867
- if (name === target && !isExcluded(lt)) {
868
- if (skipFirstLocal) {
869
- skipFirstLocal = false;
870
- } else {
871
- count++;
872
- }
1475
+ }
1476
+ if (ch === "/") {
1477
+ const result = handleClosingTagInFindAllTop(xmlContent, i, target, depth);
1478
+ if (result.newPos === -1) {
1479
+ break;
873
1480
  }
874
- i = k + 1;
1481
+ i = result.newPos;
1482
+ depth = result.newDepth;
875
1483
  continue;
876
1484
  }
877
- }
878
- return count;
1485
+ const { name, newPos } = parseName(xmlContent, i);
1486
+ i = newPos;
1487
+ const k = skipAttributes(xmlContent, i, len);
1488
+ if (name === target && depth === 0) {
1489
+ depth += 1;
1490
+ const result = processTopLevelTarget({
1491
+ xmlContent,
1492
+ tagStart: lt,
1493
+ k,
1494
+ len,
1495
+ target,
1496
+ ranges
1497
+ });
1498
+ depth += result.newDepth;
1499
+ }
1500
+ i = k + 1;
1501
+ }
1502
+ return ranges;
879
1503
  }
880
1504
 
881
1505
  // src/core/tokenizer.ts
@@ -894,57 +1518,30 @@ var XMLTokenizer = class {
894
1518
  this.pos = options.pos || 0;
895
1519
  }
896
1520
  /**
897
- * Parse XML children recursively
1521
+ * Handle closing tag parsing
898
1522
  */
899
- parseChildren(tagName) {
900
- const children = [];
901
- let consumedToEnd = false;
902
- while (this.xmlString[this.pos]) {
903
- if (this.xmlString.charCodeAt(this.pos) === CharCodes.OPEN_BRACKET) {
904
- if (this.xmlString.charCodeAt(this.pos + 1) === CharCodes.SLASH) {
905
- const closeStart = this.pos + 2;
906
- this.pos = this.xmlString.indexOf(">", this.pos);
907
- const closeTag = this.xmlString.substring(closeStart, this.pos);
908
- if (tagName && closeTag.trim() !== tagName) {
909
- const { line, column } = getLineColumn(this.xmlString, this.pos);
910
- throw new RXMLParseError(
911
- `Unexpected close tag at line ${line}, column ${column}. Expected </${tagName}>, found </${closeTag}>`,
912
- void 0,
913
- line,
914
- column
915
- );
916
- }
917
- if (this.pos !== -1) this.pos += 1;
918
- return children;
919
- } else if (this.xmlString.charCodeAt(this.pos + 1) === CharCodes.EXCLAMATION) {
920
- const prevPos = this.pos;
921
- this.handleSpecialContent(children);
922
- if (this.pos >= this.xmlString.length && prevPos < this.xmlString.length) {
923
- consumedToEnd = true;
924
- }
925
- } else {
926
- const node = this.parseNode();
927
- children.push(node);
928
- if (node.tagName[0] === "?") {
929
- children.push(...node.children);
930
- node.children = [];
931
- }
932
- }
933
- } else {
934
- const text = this.parseText();
935
- if (this.options.keepWhitespace) {
936
- if (text.length > 0) {
937
- children.push(text);
938
- }
939
- } else {
940
- const trimmed = text.trim();
941
- if (trimmed.length > 0) {
942
- children.push(trimmed);
943
- }
944
- }
945
- this.pos++;
946
- }
1523
+ handleClosingTag(tagName, children) {
1524
+ const closeStart = this.pos + 2;
1525
+ this.pos = this.xmlString.indexOf(">", this.pos);
1526
+ const closeTag = this.xmlString.substring(closeStart, this.pos);
1527
+ if (tagName && closeTag.trim() !== tagName) {
1528
+ const { line, column } = getLineColumn(this.xmlString, this.pos);
1529
+ throw new RXMLParseError(
1530
+ `Unexpected close tag at line ${line}, column ${column}. Expected </${tagName}>, found </${closeTag}>`,
1531
+ void 0,
1532
+ line,
1533
+ column
1534
+ );
947
1535
  }
1536
+ if (this.pos !== -1) {
1537
+ this.pos += 1;
1538
+ }
1539
+ return children;
1540
+ }
1541
+ /**
1542
+ * Check if we're at end of string and should throw unclosed tag error
1543
+ */
1544
+ checkUnclosedTag(tagName, consumedToEnd) {
948
1545
  if (tagName && this.pos >= this.xmlString.length && !consumedToEnd) {
949
1546
  const { line, column } = getLineColumn(this.xmlString, this.pos - 1);
950
1547
  throw new RXMLParseError(
@@ -954,93 +1551,205 @@ var XMLTokenizer = class {
954
1551
  column
955
1552
  );
956
1553
  }
1554
+ }
1555
+ /**
1556
+ * Process special content (comments, CDATA, DOCTYPE) and track if we consumed to end
1557
+ */
1558
+ processSpecialContent(children) {
1559
+ const prevPos = this.pos;
1560
+ this.handleSpecialContent(children);
1561
+ return this.pos >= this.xmlString.length && prevPos < this.xmlString.length;
1562
+ }
1563
+ /**
1564
+ * Handle text content parsing
1565
+ */
1566
+ handleTextContent(children) {
1567
+ const text = this.parseText();
1568
+ if (this.options.keepWhitespace) {
1569
+ if (text.length > 0) {
1570
+ children.push(text);
1571
+ }
1572
+ } else {
1573
+ const trimmed = text.trim();
1574
+ if (trimmed.length > 0) {
1575
+ children.push(trimmed);
1576
+ }
1577
+ }
1578
+ this.pos += 1;
1579
+ }
1580
+ /**
1581
+ * Handle regular element parsing
1582
+ */
1583
+ handleRegularElement(children) {
1584
+ const node = this.parseNode();
1585
+ children.push(node);
1586
+ if (node.tagName[0] === "?") {
1587
+ children.push(...node.children);
1588
+ node.children = [];
1589
+ }
1590
+ }
1591
+ /**
1592
+ * Process a single child element based on the current character
1593
+ */
1594
+ processSingleChild(children, tagName) {
1595
+ if (this.xmlString.charCodeAt(this.pos) !== CharCodes.OPEN_BRACKET) {
1596
+ this.handleTextContent(children);
1597
+ return { shouldReturn: false, consumedToEnd: false };
1598
+ }
1599
+ const nextChar = this.xmlString.charCodeAt(this.pos + 1);
1600
+ if (nextChar === CharCodes.SLASH) {
1601
+ const result = this.handleClosingTag(tagName, children);
1602
+ if (result !== null) {
1603
+ return { shouldReturn: true, consumedToEnd: false };
1604
+ }
1605
+ return { shouldReturn: false, consumedToEnd: false };
1606
+ }
1607
+ if (nextChar === CharCodes.EXCLAMATION) {
1608
+ const wasConsumedToEnd = this.processSpecialContent(children);
1609
+ return { shouldReturn: false, consumedToEnd: wasConsumedToEnd };
1610
+ }
1611
+ this.handleRegularElement(children);
1612
+ return { shouldReturn: false, consumedToEnd: false };
1613
+ }
1614
+ /**
1615
+ * Parse XML children recursively
1616
+ */
1617
+ parseChildren(tagName) {
1618
+ const children = [];
1619
+ let consumedToEnd = false;
1620
+ while (this.xmlString[this.pos]) {
1621
+ const result = this.processSingleChild(children, tagName);
1622
+ if (result.shouldReturn) {
1623
+ return children;
1624
+ }
1625
+ if (result.consumedToEnd) {
1626
+ consumedToEnd = true;
1627
+ }
1628
+ }
1629
+ this.checkUnclosedTag(tagName, consumedToEnd);
957
1630
  return children;
958
1631
  }
959
1632
  /**
960
- * Parse a single XML node
1633
+ * Check if character is whitespace
961
1634
  */
962
- parseNode() {
963
- var _a;
964
- this.pos++;
965
- const { name: tagName, newPos } = parseName(this.xmlString, this.pos);
966
- this.pos = newPos;
1635
+ isWhitespace(code) {
1636
+ return code === CharCodes.SPACE || code === CharCodes.TAB || code === CharCodes.NEWLINE || code === CharCodes.CARRIAGE_RETURN;
1637
+ }
1638
+ /**
1639
+ * Skip whitespace characters
1640
+ */
1641
+ skipWhitespace() {
1642
+ while (this.pos < this.xmlString.length && this.isWhitespace(this.xmlString.charCodeAt(this.pos))) {
1643
+ this.pos += 1;
1644
+ }
1645
+ }
1646
+ /**
1647
+ * Parse attribute value
1648
+ */
1649
+ parseAttributeValue() {
1650
+ if (this.pos >= this.xmlString.length || this.xmlString[this.pos] !== "=") {
1651
+ return null;
1652
+ }
1653
+ this.pos += 1;
1654
+ this.skipWhitespace();
1655
+ const code = this.xmlString.charCodeAt(this.pos);
1656
+ if (code === CharCodes.SINGLE_QUOTE || code === CharCodes.DOUBLE_QUOTE) {
1657
+ const { value: parsedValue, newPos: valueEnd } = parseString(
1658
+ this.xmlString,
1659
+ this.pos
1660
+ );
1661
+ this.pos = valueEnd;
1662
+ return parsedValue;
1663
+ }
1664
+ return null;
1665
+ }
1666
+ /**
1667
+ * Parse single attribute
1668
+ */
1669
+ parseAttribute(attributes) {
1670
+ const { name: attrName, newPos: nameEnd } = parseName(
1671
+ this.xmlString,
1672
+ this.pos
1673
+ );
1674
+ this.pos = nameEnd;
1675
+ this.skipWhitespace();
1676
+ const value = this.parseAttributeValue();
1677
+ attributes[attrName] = value;
1678
+ }
1679
+ /**
1680
+ * Parse all attributes
1681
+ */
1682
+ parseAttributes() {
967
1683
  const attributes = {};
968
- let children = [];
969
1684
  while (this.xmlString.charCodeAt(this.pos) !== CharCodes.CLOSE_BRACKET && this.xmlString[this.pos]) {
970
1685
  const c = this.xmlString.charCodeAt(this.pos);
971
- if (c === CharCodes.SPACE || c === CharCodes.TAB || c === CharCodes.NEWLINE || c === CharCodes.CARRIAGE_RETURN) {
972
- this.pos++;
1686
+ if (this.isWhitespace(c)) {
1687
+ this.pos += 1;
973
1688
  continue;
974
1689
  }
975
1690
  if (c > 64 && c < 91 || c > 96 && c < 123) {
976
- const { name: attrName, newPos: nameEnd } = parseName(
977
- this.xmlString,
978
- this.pos
979
- );
980
- this.pos = nameEnd;
981
- while (this.pos < this.xmlString.length && (this.xmlString.charCodeAt(this.pos) === CharCodes.SPACE || this.xmlString.charCodeAt(this.pos) === CharCodes.TAB || this.xmlString.charCodeAt(this.pos) === CharCodes.NEWLINE || this.xmlString.charCodeAt(this.pos) === CharCodes.CARRIAGE_RETURN)) {
982
- this.pos++;
983
- }
984
- let value = null;
985
- if (this.pos < this.xmlString.length && this.xmlString[this.pos] === "=") {
986
- this.pos++;
987
- while (this.pos < this.xmlString.length && (this.xmlString.charCodeAt(this.pos) === CharCodes.SPACE || this.xmlString.charCodeAt(this.pos) === CharCodes.TAB || this.xmlString.charCodeAt(this.pos) === CharCodes.NEWLINE || this.xmlString.charCodeAt(this.pos) === CharCodes.CARRIAGE_RETURN)) {
988
- this.pos++;
989
- }
990
- const code = this.xmlString.charCodeAt(this.pos);
991
- if (code === CharCodes.SINGLE_QUOTE || code === CharCodes.DOUBLE_QUOTE) {
992
- const { value: parsedValue, newPos: valueEnd } = parseString(
993
- this.xmlString,
994
- this.pos
995
- );
996
- value = parsedValue;
997
- this.pos = valueEnd;
998
- }
999
- }
1000
- attributes[attrName] = value;
1691
+ this.parseAttribute(attributes);
1001
1692
  } else {
1002
- this.pos++;
1693
+ this.pos += 1;
1003
1694
  }
1004
1695
  }
1005
- const isSelfClosing = this.xmlString.charCodeAt(this.pos - 1) === CharCodes.SLASH || tagName[0] === "?" && this.xmlString.charCodeAt(this.pos - 1) === CharCodes.QUESTION;
1006
- if (!isSelfClosing) {
1007
- if (tagName === "script") {
1008
- const start = this.pos + 1;
1009
- this.pos = this.xmlString.indexOf("</script>", this.pos);
1010
- if (this.pos === -1) {
1011
- children = [this.xmlString.slice(start)];
1012
- this.pos = this.xmlString.length;
1013
- } else {
1014
- children = [this.xmlString.slice(start, this.pos)];
1015
- this.pos += 9;
1016
- }
1017
- } else if (tagName === "style") {
1018
- const start = this.pos + 1;
1019
- this.pos = this.xmlString.indexOf("</style>", this.pos);
1020
- if (this.pos === -1) {
1021
- children = [this.xmlString.slice(start)];
1022
- this.pos = this.xmlString.length;
1023
- } else {
1024
- children = [this.xmlString.slice(start, this.pos)];
1025
- this.pos += 8;
1026
- }
1027
- } else if (((_a = this.options.noChildNodes) == null ? void 0 : _a.indexOf(tagName)) === -1) {
1028
- this.pos++;
1029
- children = this.parseChildren(tagName);
1030
- } else {
1031
- this.pos++;
1032
- if (DEFAULT_NO_CHILD_NODES.includes(tagName)) {
1033
- } else {
1034
- const closingTag = `</${tagName}>`;
1035
- const closingPos = this.xmlString.indexOf(closingTag, this.pos);
1036
- if (closingPos !== -1) {
1037
- this.pos = closingPos + closingTag.length;
1038
- }
1039
- }
1040
- }
1041
- } else {
1042
- this.pos++;
1696
+ return attributes;
1697
+ }
1698
+ /**
1699
+ * Parse special tag content (script, style)
1700
+ */
1701
+ parseSpecialTagContent(_tagName, closingTag) {
1702
+ const start = this.pos + 1;
1703
+ this.pos = this.xmlString.indexOf(closingTag, this.pos);
1704
+ if (this.pos === -1) {
1705
+ const children2 = [this.xmlString.slice(start)];
1706
+ this.pos = this.xmlString.length;
1707
+ return children2;
1708
+ }
1709
+ const children = [this.xmlString.slice(start, this.pos)];
1710
+ this.pos += closingTag.length;
1711
+ return children;
1712
+ }
1713
+ /**
1714
+ * Parse node children based on tag type
1715
+ */
1716
+ parseNodeChildren(tagName, isSelfClosing) {
1717
+ var _a;
1718
+ if (isSelfClosing) {
1719
+ this.pos += 1;
1720
+ return [];
1721
+ }
1722
+ if (tagName === "script") {
1723
+ return this.parseSpecialTagContent(tagName, "</script>");
1724
+ }
1725
+ if (tagName === "style") {
1726
+ return this.parseSpecialTagContent(tagName, "</style>");
1727
+ }
1728
+ if (((_a = this.options.noChildNodes) == null ? void 0 : _a.indexOf(tagName)) === -1) {
1729
+ this.pos += 1;
1730
+ return this.parseChildren(tagName);
1731
+ }
1732
+ this.pos += 1;
1733
+ if (DEFAULT_NO_CHILD_NODES.includes(tagName)) {
1734
+ return [];
1043
1735
  }
1736
+ const closingTag = `</${tagName}>`;
1737
+ const closingPos = this.xmlString.indexOf(closingTag, this.pos);
1738
+ if (closingPos !== -1) {
1739
+ this.pos = closingPos + closingTag.length;
1740
+ }
1741
+ return [];
1742
+ }
1743
+ /**
1744
+ * Parse a single XML node
1745
+ */
1746
+ parseNode() {
1747
+ this.pos += 1;
1748
+ const { name: tagName, newPos } = parseName(this.xmlString, this.pos);
1749
+ this.pos = newPos;
1750
+ const attributes = this.parseAttributes();
1751
+ const isSelfClosing = this.xmlString.charCodeAt(this.pos - 1) === CharCodes.SLASH || tagName[0] === "?" && this.xmlString.charCodeAt(this.pos - 1) === CharCodes.QUESTION;
1752
+ const children = this.parseNodeChildren(tagName, isSelfClosing);
1044
1753
  return { tagName, attributes, children };
1045
1754
  }
1046
1755
  /**
@@ -1080,7 +1789,7 @@ var XMLTokenizer = class {
1080
1789
  if (this.options.keepComments) {
1081
1790
  children.push(this.xmlString.substring(startCommentPos, this.pos + 1));
1082
1791
  }
1083
- this.pos++;
1792
+ this.pos += 1;
1084
1793
  }
1085
1794
  /**
1086
1795
  * Handle CDATA sections
@@ -1108,10 +1817,10 @@ var XMLTokenizer = class {
1108
1817
  } else if (encapsulated && this.xmlString.charCodeAt(this.pos) === CharCodes.CLOSE_CORNER_BRACKET) {
1109
1818
  encapsulated = false;
1110
1819
  }
1111
- this.pos++;
1820
+ this.pos += 1;
1112
1821
  }
1113
1822
  children.push(this.xmlString.substring(startDoctype, this.pos));
1114
- this.pos++;
1823
+ this.pos += 1;
1115
1824
  }
1116
1825
  /**
1117
1826
  * Get current position
@@ -1128,6 +1837,146 @@ var XMLTokenizer = class {
1128
1837
  };
1129
1838
 
1130
1839
  // src/core/parser.ts
1840
+ var WHITESPACE_REGEX = /\s/;
1841
+ var NUMERIC_STRING_REGEX = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
1842
+ var DIGIT_KEY_REGEX2 = /^\d+$/;
1843
+ function getTopLevelStringProps(s) {
1844
+ const set = /* @__PURE__ */ new Set();
1845
+ const unwrapped = unwrapJsonSchema(s);
1846
+ if (unwrapped && typeof unwrapped === "object") {
1847
+ const props = unwrapped.properties;
1848
+ if (props && typeof props === "object") {
1849
+ for (const [k, v] of Object.entries(props)) {
1850
+ if (getSchemaType(v) === "string") {
1851
+ set.add(k);
1852
+ }
1853
+ }
1854
+ }
1855
+ }
1856
+ return set;
1857
+ }
1858
+ function restorePlaceholderString(val, placeholderMap) {
1859
+ if (val.startsWith("__RXML_PLACEHOLDER_")) {
1860
+ const orig = placeholderMap.get(val);
1861
+ return orig !== void 0 ? orig : val;
1862
+ }
1863
+ return val;
1864
+ }
1865
+ function restorePlaceholdersInObject(obj, _placeholderMap, textNodeName, restorer) {
1866
+ const out = {};
1867
+ for (const [k, v] of Object.entries(obj)) {
1868
+ const restored = restorer(v);
1869
+ if (k === textNodeName && typeof restored === "string") {
1870
+ out[k] = restored.trim();
1871
+ } else {
1872
+ out[k] = restored;
1873
+ }
1874
+ }
1875
+ return out;
1876
+ }
1877
+ function createPlaceholderRestorer(placeholderMap, textNodeName) {
1878
+ const restorer = (val) => {
1879
+ if (val == null) {
1880
+ return val;
1881
+ }
1882
+ if (typeof val === "string") {
1883
+ return restorePlaceholderString(val, placeholderMap);
1884
+ }
1885
+ if (Array.isArray(val)) {
1886
+ return val.map(restorer);
1887
+ }
1888
+ if (typeof val === "object") {
1889
+ return restorePlaceholdersInObject(
1890
+ val,
1891
+ placeholderMap,
1892
+ textNodeName,
1893
+ restorer
1894
+ );
1895
+ }
1896
+ return val;
1897
+ };
1898
+ return restorer;
1899
+ }
1900
+ function tryConvertToNumber(val) {
1901
+ if (typeof val !== "string") {
1902
+ return val;
1903
+ }
1904
+ const trimmed = val.trim();
1905
+ if (NUMERIC_STRING_REGEX.test(trimmed)) {
1906
+ const num = Number(trimmed);
1907
+ if (Number.isFinite(num)) {
1908
+ return num;
1909
+ }
1910
+ }
1911
+ return trimmed;
1912
+ }
1913
+ function processItemValue(item, textNodeName) {
1914
+ let currentVal = item;
1915
+ if (item && typeof item === "object" && Object.hasOwn(item, textNodeName)) {
1916
+ currentVal = item[textNodeName];
1917
+ }
1918
+ const trimmed = typeof currentVal === "string" ? currentVal.trim() : currentVal;
1919
+ return tryConvertToNumber(trimmed);
1920
+ }
1921
+ function processItemWrapper(itemValue, textNodeName) {
1922
+ if (Array.isArray(itemValue)) {
1923
+ return itemValue.map((item) => processItemValue(item, textNodeName));
1924
+ }
1925
+ const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1926
+ return tryConvertToNumber(trimmed);
1927
+ }
1928
+ function shouldRethrowParseError(error, xmlString) {
1929
+ if (!(error instanceof RXMLParseError)) {
1930
+ return false;
1931
+ }
1932
+ const isSimple = xmlString.split("<").length < 6;
1933
+ return error.message.includes("Unexpected close tag") && isSimple || error.message.includes("Unclosed tag") && isSimple;
1934
+ }
1935
+ function extractPartialXmlResults(xmlString, options) {
1936
+ const partialResults = [];
1937
+ const xmlPattern = /<([a-zA-Z_][\w.-]*)[^>]*>.*?<\/\1>/gs;
1938
+ let match = null;
1939
+ match = xmlPattern.exec(xmlString);
1940
+ while (match !== null) {
1941
+ try {
1942
+ const elementXml = match[0];
1943
+ const tokenizer = new XMLTokenizer(elementXml, options);
1944
+ const parsed = tokenizer.parseChildren();
1945
+ partialResults.push(...parsed);
1946
+ } catch (e) {
1947
+ }
1948
+ match = xmlPattern.exec(xmlString);
1949
+ }
1950
+ return partialResults;
1951
+ }
1952
+ function deepDecodeStringsBySchema(input, schema) {
1953
+ var _a;
1954
+ if (input == null || schema == null) {
1955
+ return input;
1956
+ }
1957
+ const type = getSchemaType(schema);
1958
+ if (type === "string" && typeof input === "string") {
1959
+ return unescapeXml(input);
1960
+ }
1961
+ if (type === "array" && Array.isArray(input)) {
1962
+ const unwrapped = unwrapJsonSchema(schema);
1963
+ const itemSchema = (_a = unwrapped == null ? void 0 : unwrapped.items) != null ? _a : {};
1964
+ return input.map((item) => deepDecodeStringsBySchema(item, itemSchema));
1965
+ }
1966
+ if (type === "object" && input && typeof input === "object") {
1967
+ const obj = input;
1968
+ const out = {};
1969
+ for (const key of Object.keys(obj)) {
1970
+ const childSchema = getPropertySchema(schema, key);
1971
+ out[key] = deepDecodeStringsBySchema(obj[key], childSchema);
1972
+ }
1973
+ return out;
1974
+ }
1975
+ if (typeof input === "string") {
1976
+ return unescapeXml(input);
1977
+ }
1978
+ return input;
1979
+ }
1131
1980
  function parse(xmlInner, schema, options = {}) {
1132
1981
  var _a, _b, _c;
1133
1982
  const textNodeName = (_a = options.textNodeName) != null ? _a : "#text";
@@ -1140,7 +1989,9 @@ function parse(xmlInner, schema, options = {}) {
1140
1989
  let rootName = "";
1141
1990
  while (i < s.length) {
1142
1991
  const lt = s.indexOf("<", i);
1143
- if (lt === -1) break;
1992
+ if (lt === -1) {
1993
+ break;
1994
+ }
1144
1995
  const next = s[lt + 1];
1145
1996
  if (next === "?") {
1146
1997
  const end = s.indexOf("?>", lt + 2);
@@ -1167,7 +2018,7 @@ function parse(xmlInner, schema, options = {}) {
1167
2018
  }
1168
2019
  let j = lt + 1;
1169
2020
  while (j < s.length && s[j] !== " " && s[j] !== "\n" && s[j] !== "\r" && s[j] !== " " && s[j] !== "/" && s[j] !== ">") {
1170
- j++;
2021
+ j += 1;
1171
2022
  }
1172
2023
  rootStart = lt;
1173
2024
  rootName = s.slice(lt + 1, j);
@@ -1180,27 +2031,36 @@ function parse(xmlInner, schema, options = {}) {
1180
2031
  const closeHead = s.indexOf(`</${rootName}`, range.end);
1181
2032
  if (closeHead === range.end) {
1182
2033
  let p = closeHead + 2 + rootName.length;
1183
- while (p < s.length && /\s/.test(s[p])) p++;
1184
- if (s[p] === ">") fullEnd = p + 1;
2034
+ while (p < s.length && WHITESPACE_REGEX.test(s[p])) {
2035
+ p += 1;
2036
+ }
2037
+ if (s[p] === ">") {
2038
+ fullEnd = p + 1;
2039
+ }
1185
2040
  }
1186
2041
  if (fullEnd === s.length) {
1187
2042
  const unwrapped = unwrapJsonSchema(schema);
1188
2043
  const schemaProps = unwrapped && typeof unwrapped === "object" ? unwrapped.properties : void 0;
1189
- if (schemaProps && !Object.prototype.hasOwnProperty.call(schemaProps, rootName)) {
2044
+ if (schemaProps && !Object.hasOwn(schemaProps, rootName)) {
1190
2045
  actualXmlInner = s.slice(range.start, range.end);
1191
2046
  }
1192
2047
  }
1193
2048
  }
1194
2049
  }
1195
2050
  }
1196
- const stringTypedProps = getStringTypedProperties(schema);
2051
+ const topLevelStringProps = getTopLevelStringProps(schema);
2052
+ const deepStringTypedProps = getStringTypedProperties(schema);
1197
2053
  const duplicateKeys = /* @__PURE__ */ new Set();
1198
- for (const key of stringTypedProps) {
2054
+ for (const key of topLevelStringProps) {
1199
2055
  const excludeRanges = [];
1200
- for (const other of stringTypedProps) {
1201
- if (other === key) continue;
2056
+ for (const other of topLevelStringProps) {
2057
+ if (other === key) {
2058
+ continue;
2059
+ }
1202
2060
  const range = findFirstTopLevelRange(actualXmlInner, other);
1203
- if (range) excludeRanges.push(range);
2061
+ if (range) {
2062
+ excludeRanges.push(range);
2063
+ }
1204
2064
  }
1205
2065
  const occurrences = countTagOccurrences(
1206
2066
  actualXmlInner,
@@ -1227,37 +2087,35 @@ function parse(xmlInner, schema, options = {}) {
1227
2087
  const originalContentMap = /* @__PURE__ */ new Map();
1228
2088
  try {
1229
2089
  const ranges = [];
1230
- for (const key of stringTypedProps) {
1231
- const r = findFirstTopLevelRange(actualXmlInner, key);
1232
- if (r && r.end > r.start) ranges.push({ ...r, key });
2090
+ for (const key of deepStringTypedProps) {
2091
+ const innerRanges = findAllInnerRanges(actualXmlInner, key);
2092
+ for (const r of innerRanges) {
2093
+ if (r.end > r.start) {
2094
+ ranges.push({ ...r, key });
2095
+ }
2096
+ }
1233
2097
  }
1234
2098
  if (ranges.length > 0) {
1235
2099
  const sorted = [...ranges].sort((a, b) => a.start - b.start);
1236
- const filtered = [];
2100
+ let rebuilt = "";
2101
+ let cursor = 0;
1237
2102
  for (const r of sorted) {
1238
- const last = filtered[filtered.length - 1];
1239
- if (last && r.start >= last.start && r.end <= last.end) {
2103
+ if (r.start < cursor) {
1240
2104
  continue;
1241
2105
  }
1242
- filtered.push(r);
1243
- }
1244
- if (filtered.length > 0) {
1245
- filtered.sort((a, b) => a.start - b.start);
1246
- let rebuilt = "";
1247
- let cursor = 0;
1248
- for (const r of filtered) {
1249
- if (cursor < r.start)
1250
- rebuilt += actualXmlInner.slice(cursor, r.start);
1251
- const placeholder = `__RXML_PLACEHOLDER_${r.key}__`;
1252
- const originalContent = actualXmlInner.slice(r.start, r.end);
1253
- originalContentMap.set(placeholder, originalContent);
1254
- rebuilt += placeholder;
1255
- cursor = r.end;
2106
+ if (cursor < r.start) {
2107
+ rebuilt += actualXmlInner.slice(cursor, r.start);
1256
2108
  }
1257
- if (cursor < actualXmlInner.length)
1258
- rebuilt += actualXmlInner.slice(cursor);
1259
- xmlInnerForParsing = rebuilt;
2109
+ const placeholder = `__RXML_PLACEHOLDER_${r.key}_${r.start}_${r.end}__`;
2110
+ const originalContent = actualXmlInner.slice(r.start, r.end);
2111
+ originalContentMap.set(placeholder, originalContent);
2112
+ rebuilt += placeholder;
2113
+ cursor = r.end;
1260
2114
  }
2115
+ if (cursor < actualXmlInner.length) {
2116
+ rebuilt += actualXmlInner.slice(cursor);
2117
+ }
2118
+ xmlInnerForParsing = rebuilt;
1261
2119
  }
1262
2120
  } catch (error) {
1263
2121
  if (options.onError) {
@@ -1281,9 +2139,14 @@ function parse(xmlInner, schema, options = {}) {
1281
2139
  throw new RXMLParseError("Failed to parse XML", cause);
1282
2140
  }
1283
2141
  const parsedArgs = domToObject(parsedNodes, schema, textNodeName);
2142
+ const restorePlaceholdersDeep = createPlaceholderRestorer(
2143
+ originalContentMap,
2144
+ textNodeName
2145
+ );
2146
+ const parsedArgsRestored = restorePlaceholdersDeep(parsedArgs);
1284
2147
  const args = {};
1285
- for (const k of Object.keys(parsedArgs || {})) {
1286
- const v = parsedArgs[k];
2148
+ for (const k of Object.keys(parsedArgsRestored || {})) {
2149
+ const v = parsedArgsRestored[k];
1287
2150
  let val = v;
1288
2151
  const propSchema = getPropertySchema(schema, k);
1289
2152
  const propType = getSchemaType(propSchema);
@@ -1301,7 +2164,7 @@ function parse(xmlInner, schema, options = {}) {
1301
2164
  }
1302
2165
  }
1303
2166
  if (propType === "string" && !Array.isArray(v)) {
1304
- const placeholderUsed = typeof v === "string" && v.startsWith("__RXML_PLACEHOLDER_") || v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, textNodeName) && typeof v[textNodeName] === "string" && v[textNodeName].startsWith(
2167
+ const placeholderUsed = typeof v === "string" && v.startsWith("__RXML_PLACEHOLDER_") || v && typeof v === "object" && Object.hasOwn(v, textNodeName) && typeof v[textNodeName] === "string" && v[textNodeName].startsWith(
1305
2168
  "__RXML_PLACEHOLDER_"
1306
2169
  );
1307
2170
  if (placeholderUsed) {
@@ -1323,13 +2186,13 @@ function parse(xmlInner, schema, options = {}) {
1323
2186
  continue;
1324
2187
  }
1325
2188
  }
1326
- if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, textNodeName)) {
2189
+ if (v && typeof v === "object" && Object.hasOwn(v, textNodeName)) {
1327
2190
  val = v[textNodeName];
1328
2191
  }
1329
2192
  if (Array.isArray(v)) {
1330
2193
  if (propType === "string") {
1331
2194
  const mapped = v.map((item) => {
1332
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, textNodeName)) {
2195
+ if (item && typeof item === "object" && Object.hasOwn(item, textNodeName)) {
1333
2196
  const textVal = item[textNodeName];
1334
2197
  return typeof textVal === "string" ? textVal : String(textVal);
1335
2198
  }
@@ -1348,41 +2211,18 @@ function parse(xmlInner, schema, options = {}) {
1348
2211
  }
1349
2212
  args[k] = (_c = mapped[0]) != null ? _c : "";
1350
2213
  continue;
1351
- } else {
1352
- val = processArrayContent(v, propSchema, textNodeName);
1353
2214
  }
1354
- } else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, textNodeName)) {
2215
+ val = processArrayContent(v, propSchema, textNodeName);
2216
+ } else if (v && typeof v === "object" && !Object.hasOwn(v, textNodeName)) {
1355
2217
  const obj = v;
1356
2218
  const keys2 = Object.keys(obj);
1357
2219
  if (keys2.length === 1 && keys2[0] === "item") {
1358
- const itemValue = obj.item;
1359
- if (Array.isArray(itemValue)) {
1360
- val = itemValue.map((item) => {
1361
- let currentVal = item;
1362
- if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, textNodeName)) {
1363
- currentVal = item[textNodeName];
1364
- }
1365
- const trimmed = typeof currentVal === "string" ? currentVal.trim() : currentVal;
1366
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1367
- const num = Number(trimmed);
1368
- if (Number.isFinite(num)) return num;
1369
- }
1370
- return trimmed;
1371
- });
1372
- } else {
1373
- const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
1374
- if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
1375
- const num = Number(trimmed);
1376
- val = Number.isFinite(num) ? num : trimmed;
1377
- } else {
1378
- val = trimmed;
1379
- }
1380
- }
2220
+ val = processItemWrapper(obj.item, textNodeName);
1381
2221
  } else {
1382
2222
  let isIndexedTuple = false;
1383
- if (keys2.length > 0 && keys2.every((key) => /^\d+$/.test(key))) {
1384
- const indices = keys2.map((k2) => parseInt(k2, 10)).sort((a, b) => a - b);
1385
- isIndexedTuple = indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
2223
+ if (keys2.length > 0 && keys2.every((key) => DIGIT_KEY_REGEX2.test(key))) {
2224
+ const indices = keys2.map((keyStr) => Number.parseInt(keyStr, 10)).sort((a, b) => a - b);
2225
+ isIndexedTuple = indices[0] === 0 && indices.every((indexVal, idx) => indexVal === idx);
1386
2226
  }
1387
2227
  if (isIndexedTuple) {
1388
2228
  val = processIndexedTuple(obj, textNodeName);
@@ -1393,8 +2233,8 @@ function parse(xmlInner, schema, options = {}) {
1393
2233
  }
1394
2234
  args[k] = typeof val === "string" ? val.trim() : val;
1395
2235
  }
1396
- for (const key of stringTypedProps) {
1397
- if (!Object.prototype.hasOwnProperty.call(args, key)) {
2236
+ for (const key of topLevelStringProps) {
2237
+ if (!Object.hasOwn(args, key)) {
1398
2238
  const raw = extractRawInner(actualXmlInner, key);
1399
2239
  if (typeof raw === "string") {
1400
2240
  args[key] = raw;
@@ -1409,14 +2249,15 @@ function parse(xmlInner, schema, options = {}) {
1409
2249
  const unwrapped = unwrapJsonSchema(schema);
1410
2250
  if (unwrapped && typeof unwrapped === "object") {
1411
2251
  const schemaProps = unwrapped.properties;
1412
- if (schemaProps && !Object.prototype.hasOwnProperty.call(schemaProps, rootKey)) {
2252
+ if (schemaProps && !Object.hasOwn(schemaProps, rootKey)) {
1413
2253
  dataToCoerce = rootValue;
1414
2254
  }
1415
2255
  }
1416
2256
  }
1417
2257
  try {
1418
2258
  const coerced = coerceDomBySchema(dataToCoerce, schema);
1419
- return coerced;
2259
+ const decoded = deepDecodeStringsBySchema(coerced, schema);
2260
+ return decoded;
1420
2261
  } catch (error) {
1421
2262
  throw new RXMLCoercionError("Failed to coerce by schema", error);
1422
2263
  }
@@ -1426,34 +2267,19 @@ function parseWithoutSchema(xmlString, options = {}) {
1426
2267
  const tokenizer = new XMLTokenizer(xmlString, options);
1427
2268
  return tokenizer.parseChildren();
1428
2269
  } catch (error) {
1429
- if (error instanceof RXMLParseError) {
1430
- const isSimple = xmlString.split("<").length < 6;
1431
- if (error.message.includes("Unexpected close tag") && isSimple || error.message.includes("Unclosed tag") && isSimple) {
1432
- throw new RXMLParseError(
1433
- error.message,
1434
- error.cause,
1435
- error.line,
1436
- error.column
1437
- );
1438
- }
2270
+ if (shouldRethrowParseError(error, xmlString)) {
2271
+ throw new RXMLParseError(
2272
+ error.message,
2273
+ error.cause,
2274
+ error.line,
2275
+ error.column
2276
+ );
1439
2277
  }
1440
2278
  if (options.onError) {
1441
2279
  options.onError("Failed to parse XML without schema", { error });
1442
2280
  }
1443
2281
  try {
1444
- const partialResults = [];
1445
- const xmlPattern = /<([a-zA-Z_][\w.-]*)[^>]*>.*?<\/\1>/gs;
1446
- let match;
1447
- while ((match = xmlPattern.exec(xmlString)) !== null) {
1448
- try {
1449
- const elementXml = match[0];
1450
- const tokenizer = new XMLTokenizer(elementXml, options);
1451
- const parsed = tokenizer.parseChildren();
1452
- partialResults.push(...parsed);
1453
- } catch (e) {
1454
- continue;
1455
- }
1456
- }
2282
+ const partialResults = extractPartialXmlResults(xmlString, options);
1457
2283
  if (partialResults.length > 0) {
1458
2284
  return partialResults;
1459
2285
  }
@@ -1470,6 +2296,26 @@ function parseNode(xmlString, options = {}) {
1470
2296
  throw new RXMLParseError("Failed to parse XML node", error);
1471
2297
  }
1472
2298
  }
2299
+ function buildNodeValue(child) {
2300
+ const kids = simplify(child.children);
2301
+ let nodeValue = kids;
2302
+ if (Object.keys(child.attributes).length) {
2303
+ if (typeof kids === "string") {
2304
+ nodeValue = kids;
2305
+ if (kids !== "") {
2306
+ nodeValue = { _attributes: child.attributes, value: kids };
2307
+ } else {
2308
+ nodeValue = { _attributes: child.attributes };
2309
+ }
2310
+ } else if (typeof kids === "object" && kids !== null) {
2311
+ kids._attributes = child.attributes;
2312
+ nodeValue = kids;
2313
+ } else {
2314
+ nodeValue = { _attributes: child.attributes };
2315
+ }
2316
+ }
2317
+ return nodeValue;
2318
+ }
1473
2319
  function simplify(children) {
1474
2320
  if (!children.length) {
1475
2321
  return "";
@@ -1478,33 +2324,20 @@ function simplify(children) {
1478
2324
  return children[0];
1479
2325
  }
1480
2326
  const out = {};
1481
- children.forEach((child) => {
2327
+ for (const child of children) {
1482
2328
  if (typeof child !== "object") {
1483
- return;
2329
+ continue;
1484
2330
  }
1485
2331
  if (!out[child.tagName]) {
1486
2332
  out[child.tagName] = [];
1487
2333
  }
1488
- const kids = simplify(child.children);
1489
- let nodeValue = kids;
1490
- if (Object.keys(child.attributes).length) {
1491
- if (typeof kids === "string") {
1492
- nodeValue = kids;
1493
- if (kids !== "") {
1494
- nodeValue = { _attributes: child.attributes, value: kids };
1495
- } else {
1496
- nodeValue = { _attributes: child.attributes };
1497
- }
1498
- } else if (typeof kids === "object" && kids !== null) {
1499
- kids._attributes = child.attributes;
1500
- nodeValue = kids;
1501
- } else {
1502
- nodeValue = { _attributes: child.attributes };
1503
- }
1504
- }
2334
+ const nodeValue = buildNodeValue(child);
1505
2335
  out[child.tagName].push(nodeValue);
1506
- });
2336
+ }
1507
2337
  for (const key in out) {
2338
+ if (!Object.hasOwn(out, key)) {
2339
+ continue;
2340
+ }
1508
2341
  const value = out[key];
1509
2342
  if (Array.isArray(value) && value.length === 1) {
1510
2343
  out[key] = value[0];
@@ -1514,46 +2347,42 @@ function simplify(children) {
1514
2347
  }
1515
2348
  function filter(children, filterFn, depth = 0, path = "") {
1516
2349
  const out = [];
1517
- children.forEach((child, i) => {
2350
+ for (let i = 0; i < children.length; i += 1) {
2351
+ const child = children[i];
1518
2352
  if (typeof child === "object" && filterFn(child, i, depth, path)) {
1519
2353
  out.push(child);
1520
2354
  }
1521
2355
  if (typeof child === "object" && child.children) {
1522
- const kids = filter(
1523
- child.children,
1524
- filterFn,
1525
- depth + 1,
1526
- (path ? path + "." : "") + i + "." + child.tagName
1527
- );
2356
+ const childPath = `${path ? `${path}.` : ""}${i}.${child.tagName}`;
2357
+ const kids = filter(child.children, filterFn, depth + 1, childPath);
1528
2358
  out.push(...kids);
1529
2359
  }
1530
- });
2360
+ }
1531
2361
  return out;
1532
2362
  }
1533
2363
 
1534
2364
  // src/core/stream.ts
1535
2365
  import { Transform } from "stream";
2366
+ var TAG_NAME_REGEX = /^([a-zA-Z_][\w.-]*)/;
2367
+ var WHITESPACE_REGEX2 = /\s/;
1536
2368
  var XMLTransformStream = class extends Transform {
1537
- constructor(offset, parseOptions = {}) {
2369
+ constructor(_offset, parseOptions = {}) {
1538
2370
  super({ readableObjectMode: true });
1539
2371
  this.buffer = "";
1540
2372
  this.emittedCount = 0;
1541
2373
  this.sawTagChar = false;
1542
- if (typeof offset === "string") {
1543
- this.position = offset.length;
1544
- } else {
1545
- this.position = offset || 0;
1546
- }
1547
2374
  this.parseOptions = {
1548
2375
  keepComments: false,
1549
2376
  keepWhitespace: false,
1550
2377
  ...parseOptions
1551
2378
  };
1552
2379
  }
1553
- _transform(chunk, encoding, callback) {
2380
+ _transform(chunk, _encoding, callback) {
1554
2381
  try {
1555
2382
  const incoming = chunk.toString();
1556
- if (incoming.includes("<")) this.sawTagChar = true;
2383
+ if (incoming.includes("<")) {
2384
+ this.sawTagChar = true;
2385
+ }
1557
2386
  this.buffer += incoming;
1558
2387
  this.processBuffer();
1559
2388
  callback();
@@ -1579,122 +2408,190 @@ var XMLTransformStream = class extends Transform {
1579
2408
  }
1580
2409
  processBuffer(isFlush = false) {
1581
2410
  while (this.buffer.length > 0) {
1582
- const openBracket = this.buffer.indexOf("<");
1583
- if (openBracket === -1) {
1584
- if (isFlush) this.buffer = "";
2411
+ if (!this.trimToNextTag(isFlush)) {
1585
2412
  break;
1586
2413
  }
1587
- if (openBracket > 0) {
1588
- this.buffer = this.buffer.slice(openBracket);
2414
+ if (this.tryProcessSpecialNode(isFlush)) {
2415
+ continue;
1589
2416
  }
1590
- if (this.buffer.startsWith("<?") || this.buffer.startsWith("<!--") || this.buffer.startsWith("<![CDATA[")) {
1591
- const endMarkers = {
1592
- "<?": "?>",
1593
- "<!--": "-->",
1594
- "<![CDATA[": "]]>"
1595
- };
1596
- let endMarker = "";
1597
- for (const [start, end] of Object.entries(endMarkers)) {
1598
- if (this.buffer.startsWith(start)) {
1599
- endMarker = end;
1600
- break;
1601
- }
1602
- }
1603
- const endPos = endMarker ? this.buffer.indexOf(endMarker) : -1;
1604
- if (endPos === -1) {
1605
- if (!isFlush) break;
1606
- this.buffer = "";
1607
- break;
1608
- }
1609
- if (this.parseOptions.keepComments && this.buffer.startsWith("<!--")) {
1610
- this.push(this.buffer.slice(0, endPos + endMarker.length));
1611
- }
1612
- this.buffer = this.buffer.slice(endPos + endMarker.length);
2417
+ if (this.trySkipStrayClosingTag(isFlush)) {
1613
2418
  continue;
1614
2419
  }
1615
- if (this.buffer.startsWith("</")) {
1616
- const closeEnd = this.buffer.indexOf(">");
1617
- if (closeEnd === -1) {
1618
- if (!isFlush) break;
1619
- this.buffer = "";
1620
- break;
1621
- }
1622
- this.buffer = this.buffer.slice(closeEnd + 1);
2420
+ const tagInfo = this.extractTagInfo(isFlush);
2421
+ if (!tagInfo) {
2422
+ break;
2423
+ }
2424
+ if (this.tryProcessSelfClosingTag(tagInfo)) {
1623
2425
  continue;
1624
2426
  }
1625
- const openTagEnd = this.buffer.indexOf(">");
1626
- if (openTagEnd === -1) {
1627
- if (!isFlush) break;
2427
+ if (!this.tryProcessRegularElement(tagInfo, isFlush)) {
2428
+ break;
2429
+ }
2430
+ }
2431
+ }
2432
+ trimToNextTag(isFlush) {
2433
+ const openBracket = this.buffer.indexOf("<");
2434
+ if (openBracket === -1) {
2435
+ if (isFlush) {
1628
2436
  this.buffer = "";
2437
+ }
2438
+ return false;
2439
+ }
2440
+ if (openBracket > 0) {
2441
+ this.buffer = this.buffer.slice(openBracket);
2442
+ }
2443
+ return true;
2444
+ }
2445
+ tryProcessSpecialNode(isFlush) {
2446
+ if (!(this.buffer.startsWith("<?") || this.buffer.startsWith("<!--") || this.buffer.startsWith("<![CDATA["))) {
2447
+ return false;
2448
+ }
2449
+ const endMarkers = {
2450
+ "<?": "?>",
2451
+ "<!--": "-->",
2452
+ "<![CDATA[": "]]>"
2453
+ };
2454
+ let endMarker = "";
2455
+ for (const [start, end] of Object.entries(endMarkers)) {
2456
+ if (this.buffer.startsWith(start)) {
2457
+ endMarker = end;
1629
2458
  break;
1630
2459
  }
1631
- const openTagContent = this.buffer.slice(1, openTagEnd);
1632
- const nameMatch = openTagContent.match(/^([a-zA-Z_][\w.-]*)/);
1633
- if (!nameMatch) {
1634
- this.buffer = this.buffer.slice(1);
1635
- continue;
2460
+ }
2461
+ const endPos = endMarker ? this.buffer.indexOf(endMarker) : -1;
2462
+ if (endPos === -1) {
2463
+ if (isFlush) {
2464
+ this.buffer = "";
1636
2465
  }
1637
- const tagName = nameMatch[1];
1638
- const isSelfClosing = this.buffer[openTagEnd - 1] === "/";
1639
- if (isSelfClosing) {
1640
- const elementEnd2 = openTagEnd + 1;
1641
- const elementXml2 = this.buffer.slice(0, elementEnd2);
1642
- try {
1643
- const tokenizer = new XMLTokenizer(elementXml2, this.parseOptions);
1644
- const node = tokenizer.parseNode();
1645
- this.emitElementAndChildren(node);
1646
- this.buffer = this.buffer.slice(elementEnd2);
1647
- continue;
1648
- } catch (e) {
1649
- this.buffer = this.buffer.slice(1);
1650
- continue;
1651
- }
2466
+ return false;
2467
+ }
2468
+ if (this.parseOptions.keepComments && this.buffer.startsWith("<!--")) {
2469
+ this.push(this.buffer.slice(0, endPos + endMarker.length));
2470
+ }
2471
+ this.buffer = this.buffer.slice(endPos + endMarker.length);
2472
+ return true;
2473
+ }
2474
+ trySkipStrayClosingTag(isFlush) {
2475
+ if (!this.buffer.startsWith("</")) {
2476
+ return false;
2477
+ }
2478
+ const closeEnd = this.buffer.indexOf(">");
2479
+ if (closeEnd === -1) {
2480
+ if (isFlush) {
2481
+ this.buffer = "";
1652
2482
  }
1653
- const closingTag = `</${tagName}>`;
1654
- let depth = 1;
1655
- let searchStart = openTagEnd + 1;
1656
- let elementEnd = -1;
1657
- while (searchStart < this.buffer.length) {
1658
- let nextOpen = this.buffer.indexOf(`<${tagName}`, searchStart);
1659
- while (nextOpen !== -1) {
1660
- const after = this.buffer[nextOpen + tagName.length + 1];
1661
- if (after === void 0 || after === ">" || /\s/.test(after)) break;
1662
- nextOpen = this.buffer.indexOf(`<${tagName}`, nextOpen + 1);
1663
- }
1664
- const nextCloseStart = this.buffer.indexOf(`</${tagName}`, searchStart);
1665
- if (nextCloseStart === -1) break;
1666
- if (nextOpen !== -1 && nextOpen < nextCloseStart) {
1667
- depth++;
1668
- searchStart = nextOpen + 1;
1669
- } else {
1670
- depth--;
1671
- let p = nextCloseStart + 2 + tagName.length;
1672
- while (p < this.buffer.length && /\s/.test(this.buffer[p])) p++;
1673
- if (this.buffer[p] !== ">") break;
1674
- const closeAdvance = p + 1;
1675
- searchStart = closeAdvance;
1676
- if (depth === 0) {
1677
- elementEnd = searchStart;
1678
- break;
1679
- }
1680
- }
2483
+ return true;
2484
+ }
2485
+ this.buffer = this.buffer.slice(closeEnd + 1);
2486
+ return true;
2487
+ }
2488
+ extractTagInfo(isFlush) {
2489
+ const openTagEnd = this.buffer.indexOf(">");
2490
+ if (openTagEnd === -1) {
2491
+ if (isFlush) {
2492
+ this.buffer = "";
1681
2493
  }
1682
- if (elementEnd === -1) {
1683
- if (!isFlush) break;
2494
+ return null;
2495
+ }
2496
+ const openTagContent = this.buffer.slice(1, openTagEnd);
2497
+ const nameMatch = openTagContent.match(TAG_NAME_REGEX);
2498
+ if (!nameMatch) {
2499
+ this.buffer = this.buffer.slice(1);
2500
+ return null;
2501
+ }
2502
+ return { openTagEnd, tagName: nameMatch[1] };
2503
+ }
2504
+ tryProcessSelfClosingTag(tagInfo) {
2505
+ const isSelfClosing = this.buffer[tagInfo.openTagEnd - 1] === "/";
2506
+ if (!isSelfClosing) {
2507
+ return false;
2508
+ }
2509
+ const elementEnd = tagInfo.openTagEnd + 1;
2510
+ const elementXml = this.buffer.slice(0, elementEnd);
2511
+ try {
2512
+ const tokenizer = new XMLTokenizer(elementXml, this.parseOptions);
2513
+ const node = tokenizer.parseNode();
2514
+ this.emitElementAndChildren(node);
2515
+ this.buffer = this.buffer.slice(elementEnd);
2516
+ return true;
2517
+ } catch (e) {
2518
+ this.buffer = this.buffer.slice(1);
2519
+ return true;
2520
+ }
2521
+ }
2522
+ tryProcessRegularElement(tagInfo, isFlush) {
2523
+ const elementEnd = this.findMatchingClosingTag(
2524
+ tagInfo.tagName,
2525
+ tagInfo.openTagEnd
2526
+ );
2527
+ if (elementEnd === -1) {
2528
+ if (isFlush) {
1684
2529
  this.buffer = this.buffer.slice(1);
1685
- continue;
2530
+ return true;
2531
+ }
2532
+ return false;
2533
+ }
2534
+ const elementXml = this.buffer.slice(0, elementEnd);
2535
+ try {
2536
+ const tokenizer = new XMLTokenizer(elementXml, this.parseOptions);
2537
+ const node = tokenizer.parseNode();
2538
+ this.emitElementAndChildren(node);
2539
+ this.buffer = this.buffer.slice(elementEnd);
2540
+ return true;
2541
+ } catch (e) {
2542
+ this.emit("error", new RXMLStreamError("Parse error", e));
2543
+ return false;
2544
+ }
2545
+ }
2546
+ findMatchingClosingTag(tagName, openTagEnd) {
2547
+ let depth = 1;
2548
+ let searchStart = openTagEnd + 1;
2549
+ while (searchStart < this.buffer.length) {
2550
+ const nextOpen = this.findNextOpeningTag(tagName, searchStart);
2551
+ const nextCloseStart = this.buffer.indexOf(`</${tagName}`, searchStart);
2552
+ if (nextCloseStart === -1) {
2553
+ return -1;
2554
+ }
2555
+ if (nextOpen !== -1 && nextOpen < nextCloseStart) {
2556
+ depth += 1;
2557
+ searchStart = nextOpen + 1;
2558
+ } else {
2559
+ depth -= 1;
2560
+ const closeAdvance = this.advancePastClosingTag(
2561
+ tagName,
2562
+ nextCloseStart
2563
+ );
2564
+ if (closeAdvance === -1) {
2565
+ return -1;
2566
+ }
2567
+ searchStart = closeAdvance;
2568
+ if (depth === 0) {
2569
+ return searchStart;
2570
+ }
1686
2571
  }
1687
- const elementXml = this.buffer.slice(0, elementEnd);
1688
- try {
1689
- const tokenizer = new XMLTokenizer(elementXml, this.parseOptions);
1690
- const node = tokenizer.parseNode();
1691
- this.emitElementAndChildren(node);
1692
- this.buffer = this.buffer.slice(elementEnd);
1693
- } catch (e) {
1694
- this.emit("error", new RXMLStreamError("Parse error", e));
1695
- return;
2572
+ }
2573
+ return -1;
2574
+ }
2575
+ findNextOpeningTag(tagName, searchStart) {
2576
+ let nextOpen = this.buffer.indexOf(`<${tagName}`, searchStart);
2577
+ while (nextOpen !== -1) {
2578
+ const after = this.buffer[nextOpen + tagName.length + 1];
2579
+ if (after === void 0 || after === ">" || WHITESPACE_REGEX2.test(after)) {
2580
+ break;
1696
2581
  }
2582
+ nextOpen = this.buffer.indexOf(`<${tagName}`, nextOpen + 1);
2583
+ }
2584
+ return nextOpen;
2585
+ }
2586
+ advancePastClosingTag(tagName, nextCloseStart) {
2587
+ let p = nextCloseStart + 2 + tagName.length;
2588
+ while (p < this.buffer.length && WHITESPACE_REGEX2.test(this.buffer[p])) {
2589
+ p += 1;
2590
+ }
2591
+ if (this.buffer[p] !== ">") {
2592
+ return -1;
1697
2593
  }
2594
+ return p + 1;
1698
2595
  }
1699
2596
  /**
1700
2597
  * Emit an element and recursively emit its children as separate events
@@ -1703,12 +2600,12 @@ var XMLTransformStream = class extends Transform {
1703
2600
  if (typeof node === "string") {
1704
2601
  if (this.parseOptions.keepComments && node.includes("<!--")) {
1705
2602
  this.push(node);
1706
- this.emittedCount++;
2603
+ this.emittedCount += 1;
1707
2604
  }
1708
2605
  return;
1709
2606
  }
1710
2607
  this.push(node);
1711
- this.emittedCount++;
2608
+ this.emittedCount += 1;
1712
2609
  for (const child of node.children) {
1713
2610
  this.emitElementAndChildren(child);
1714
2611
  }
@@ -1717,7 +2614,7 @@ var XMLTransformStream = class extends Transform {
1717
2614
  function createXMLStream(offset, parseOptions) {
1718
2615
  return new XMLTransformStream(offset, parseOptions);
1719
2616
  }
1720
- async function parseFromStream(stream, offset, parseOptions) {
2617
+ function parseFromStream(stream, offset, parseOptions) {
1721
2618
  return new Promise((resolve, reject) => {
1722
2619
  const results = [];
1723
2620
  const transformStream = createXMLStream(offset, parseOptions);
@@ -1780,7 +2677,10 @@ async function* processXMLStream(stream, offset, parseOptions) {
1780
2677
  throw new RXMLStreamError("Stream processing error", error);
1781
2678
  }
1782
2679
  if (queue.length > 0) {
1783
- yield queue.shift();
2680
+ const item = queue.shift();
2681
+ if (item !== void 0) {
2682
+ yield item;
2683
+ }
1784
2684
  continue;
1785
2685
  }
1786
2686
  if (ended) {
@@ -1815,224 +2715,6 @@ async function* findElementsByClassStream(stream, className, offset, parseOption
1815
2715
  }
1816
2716
  }
1817
2717
  }
1818
-
1819
- // src/builders/stringify.ts
1820
- function stringify(rootTag, obj, options = {}) {
1821
- var _a, _b, _c, _d;
1822
- try {
1823
- const format = (_a = options.format) != null ? _a : true;
1824
- const minimalEscaping = (_b = options.minimalEscaping) != null ? _b : false;
1825
- const suppressEmptyNode = (_c = options.suppressEmptyNode) != null ? _c : false;
1826
- const strictBooleanAttributes = (_d = options.strictBooleanAttributes) != null ? _d : false;
1827
- let result = "";
1828
- if (format) {
1829
- result += '<?xml version="1.0" encoding="UTF-8"?>\n';
1830
- }
1831
- result += stringifyValue(
1832
- rootTag,
1833
- obj,
1834
- 0,
1835
- format,
1836
- suppressEmptyNode,
1837
- minimalEscaping,
1838
- strictBooleanAttributes
1839
- );
1840
- return result;
1841
- } catch (error) {
1842
- throw new RXMLStringifyError("Failed to stringify XML", error);
1843
- }
1844
- }
1845
- function stringifyValue(tagName, value, depth, format, suppressEmptyNode, minimalEscaping, strictBooleanAttributes) {
1846
- const indent = format ? " ".repeat(depth) : "";
1847
- const newline = format ? "\n" : "";
1848
- if (value === null || value === void 0) {
1849
- if (suppressEmptyNode) return "";
1850
- return `${indent}<${tagName}/>${newline}`;
1851
- }
1852
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1853
- const content2 = minimalEscaping ? escapeXmlMinimalText(String(value)) : escapeXml(String(value));
1854
- if (content2 === "" && suppressEmptyNode) return "";
1855
- return `${indent}<${tagName}>${content2}</${tagName}>${newline}`;
1856
- }
1857
- if (Array.isArray(value)) {
1858
- let result = "";
1859
- for (const item of value) {
1860
- result += stringifyValue(
1861
- tagName,
1862
- item,
1863
- depth,
1864
- format,
1865
- suppressEmptyNode,
1866
- minimalEscaping,
1867
- strictBooleanAttributes
1868
- );
1869
- }
1870
- return result;
1871
- }
1872
- if (typeof value === "object") {
1873
- return stringifyObject(
1874
- tagName,
1875
- value,
1876
- depth,
1877
- format,
1878
- suppressEmptyNode,
1879
- minimalEscaping,
1880
- strictBooleanAttributes
1881
- );
1882
- }
1883
- const content = minimalEscaping ? escapeXmlMinimalText(String(value)) : escapeXml(String(value));
1884
- if (content === "" && suppressEmptyNode) return "";
1885
- return `${indent}<${tagName}>${content}</${tagName}>${newline}`;
1886
- }
1887
- function stringifyObject(tagName, obj, depth, format, suppressEmptyNode, minimalEscaping, strictBooleanAttributes) {
1888
- const indent = format ? " ".repeat(depth) : "";
1889
- const newline = format ? "\n" : "";
1890
- const childIndent = format ? " ".repeat(depth + 1) : "";
1891
- const attributes = {};
1892
- const elements = {};
1893
- let textContent;
1894
- for (const [key, value] of Object.entries(obj)) {
1895
- if (key.startsWith("@")) {
1896
- attributes[key.substring(1)] = value;
1897
- } else if (key === "#text" || key === "_text") {
1898
- textContent = String(value);
1899
- } else if (key === "_attributes") {
1900
- if (typeof value === "object" && value !== null) {
1901
- Object.assign(attributes, value);
1902
- }
1903
- } else {
1904
- elements[key] = value;
1905
- }
1906
- }
1907
- let openTag = `<${tagName}`;
1908
- for (const [attrName, attrValue] of Object.entries(attributes)) {
1909
- if (attrValue === null) {
1910
- if (strictBooleanAttributes) {
1911
- openTag += ` ${attrName}="${attrName}"`;
1912
- } else {
1913
- openTag += ` ${attrName}`;
1914
- }
1915
- } else {
1916
- const valueStr = String(attrValue);
1917
- if (valueStr.indexOf('"') === -1) {
1918
- const escaped = minimalEscaping ? escapeXmlMinimalAttr(valueStr, '"') : escapeXml(valueStr);
1919
- openTag += ` ${attrName}="${escaped}"`;
1920
- } else {
1921
- const escaped = minimalEscaping ? escapeXmlMinimalAttr(valueStr, "'") : escapeXml(valueStr);
1922
- openTag += ` ${attrName}='${escaped}'`;
1923
- }
1924
- }
1925
- }
1926
- const hasElements = Object.keys(elements).length > 0;
1927
- const hasTextContent = textContent !== void 0 && textContent !== "";
1928
- if (!hasElements && !hasTextContent) {
1929
- if (suppressEmptyNode) return "";
1930
- return `${indent}${openTag}/>${newline}`;
1931
- }
1932
- openTag += ">";
1933
- if (!hasElements && hasTextContent && textContent) {
1934
- const content = minimalEscaping ? escapeXmlMinimalText(textContent) : escapeXml(textContent);
1935
- return `${indent}${openTag}${content}</${tagName}>${newline}`;
1936
- }
1937
- let result = `${indent}${openTag}`;
1938
- if (hasTextContent && textContent) {
1939
- const content = minimalEscaping ? escapeXmlMinimalText(textContent) : escapeXml(textContent);
1940
- if (format) result += `${newline}${childIndent}${content}`;
1941
- else result += content;
1942
- }
1943
- if (hasElements) {
1944
- if (format) result += newline;
1945
- for (const [elementName, elementValue] of Object.entries(elements)) {
1946
- result += stringifyValue(
1947
- elementName,
1948
- elementValue,
1949
- depth + 1,
1950
- format,
1951
- suppressEmptyNode,
1952
- minimalEscaping,
1953
- strictBooleanAttributes
1954
- );
1955
- }
1956
- if (format) result += indent;
1957
- }
1958
- result += `</${tagName}>${newline}`;
1959
- return result;
1960
- }
1961
- function stringifyNodes(nodes, format = true, options = {}) {
1962
- let result = "";
1963
- for (const node of nodes) {
1964
- if (typeof node === "string") {
1965
- result += node;
1966
- } else {
1967
- result += stringifyNode(node, 0, format, options);
1968
- }
1969
- }
1970
- return result;
1971
- }
1972
- function stringifyNode(node, depth = 0, format = true, options = {}) {
1973
- var _a, _b;
1974
- const indent = format ? " ".repeat(depth) : "";
1975
- const newline = format ? "\n" : "";
1976
- const minimalEscaping = (_a = options.minimalEscaping) != null ? _a : false;
1977
- const strictBooleanAttributes = (_b = options.strictBooleanAttributes) != null ? _b : false;
1978
- let result = `${indent}<${node.tagName}`;
1979
- for (const [attrName, attrValue] of Object.entries(node.attributes)) {
1980
- if (attrValue === null) {
1981
- if (strictBooleanAttributes) {
1982
- result += ` ${attrName}="${attrName}"`;
1983
- } else {
1984
- result += ` ${attrName}`;
1985
- }
1986
- } else if (attrValue.indexOf('"') === -1) {
1987
- const escaped = minimalEscaping ? escapeXmlMinimalAttr(attrValue, '"') : escapeXml(attrValue);
1988
- result += ` ${attrName}="${escaped}"`;
1989
- } else {
1990
- const escaped = minimalEscaping ? escapeXmlMinimalAttr(attrValue, "'") : escapeXml(attrValue);
1991
- result += ` ${attrName}='${escaped}'`;
1992
- }
1993
- }
1994
- if (node.tagName[0] === "?") {
1995
- result += "?>";
1996
- return result + newline;
1997
- }
1998
- if (node.children.length === 0) {
1999
- result += "/>";
2000
- return result + newline;
2001
- }
2002
- result += ">";
2003
- let hasElementChildren = false;
2004
- for (const child of node.children) {
2005
- if (typeof child === "string") {
2006
- result += minimalEscaping ? escapeXmlMinimalText(child) : escapeXml(child);
2007
- } else {
2008
- if (!hasElementChildren && format) {
2009
- result += newline;
2010
- hasElementChildren = true;
2011
- }
2012
- result += stringifyNode(child, depth + 1, format, options);
2013
- }
2014
- }
2015
- if (hasElementChildren && format) {
2016
- result += indent;
2017
- }
2018
- result += `</${node.tagName}>`;
2019
- if (format) {
2020
- result += newline;
2021
- }
2022
- return result;
2023
- }
2024
- function toContentString(nodes) {
2025
- let result = "";
2026
- for (const node of nodes) {
2027
- if (typeof node === "string") {
2028
- result += " " + node;
2029
- } else {
2030
- result += " " + toContentString(node.children);
2031
- }
2032
- result = result.trim();
2033
- }
2034
- return result;
2035
- }
2036
2718
  export {
2037
2719
  RXMLCoercionError,
2038
2720
  RXMLDuplicateStringTagError,
@@ -2041,16 +2723,19 @@ export {
2041
2723
  RXMLStringifyError,
2042
2724
  XMLTokenizer,
2043
2725
  XMLTransformStream,
2726
+ coerceBySchema,
2044
2727
  coerceDomBySchema,
2045
2728
  countTagOccurrences,
2046
2729
  createXMLStream,
2047
2730
  domToObject,
2048
2731
  extractRawInner,
2049
2732
  filter,
2733
+ findAllTopLevelRanges,
2050
2734
  findElementByIdStream,
2051
2735
  findElementsByClassStream,
2052
2736
  findFirstTopLevelRange,
2053
2737
  getPropertySchema,
2738
+ getSchemaType,
2054
2739
  getStringTypedProperties,
2055
2740
  parse,
2056
2741
  parseFromStream,
@@ -2063,6 +2748,8 @@ export {
2063
2748
  stringify,
2064
2749
  stringifyNode,
2065
2750
  stringifyNodes,
2066
- toContentString
2751
+ toContentString,
2752
+ unescapeXml,
2753
+ unwrapJsonSchema
2067
2754
  };
2068
2755
  //# sourceMappingURL=index.js.map