@ai-sdk-tool/rxml 0.1.1 → 0.1.2

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