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