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