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