@ai-sdk-tool/rxml 0.1.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/LICENSE +13 -0
- package/README.md +53 -0
- package/dist/index.cjs +2124 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +295 -0
- package/dist/index.d.ts +295 -0
- package/dist/index.js +2068 -0
- package/dist/index.js.map +1 -0
- package/index.d.ts +12 -0
- package/package.json +54 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
RXMLCoercionError: () => RXMLCoercionError,
|
|
24
|
+
RXMLDuplicateStringTagError: () => RXMLDuplicateStringTagError,
|
|
25
|
+
RXMLParseError: () => RXMLParseError,
|
|
26
|
+
RXMLStreamError: () => RXMLStreamError,
|
|
27
|
+
RXMLStringifyError: () => RXMLStringifyError,
|
|
28
|
+
XMLTokenizer: () => XMLTokenizer,
|
|
29
|
+
XMLTransformStream: () => XMLTransformStream,
|
|
30
|
+
coerceDomBySchema: () => coerceDomBySchema,
|
|
31
|
+
countTagOccurrences: () => countTagOccurrences,
|
|
32
|
+
createXMLStream: () => createXMLStream,
|
|
33
|
+
domToObject: () => domToObject,
|
|
34
|
+
extractRawInner: () => extractRawInner,
|
|
35
|
+
filter: () => filter,
|
|
36
|
+
findElementByIdStream: () => findElementByIdStream,
|
|
37
|
+
findElementsByClassStream: () => findElementsByClassStream,
|
|
38
|
+
findFirstTopLevelRange: () => findFirstTopLevelRange,
|
|
39
|
+
getPropertySchema: () => getPropertySchema,
|
|
40
|
+
getStringTypedProperties: () => getStringTypedProperties,
|
|
41
|
+
parse: () => parse,
|
|
42
|
+
parseFromStream: () => parseFromStream,
|
|
43
|
+
parseNode: () => parseNode,
|
|
44
|
+
parseWithoutSchema: () => parseWithoutSchema,
|
|
45
|
+
processArrayContent: () => processArrayContent,
|
|
46
|
+
processIndexedTuple: () => processIndexedTuple,
|
|
47
|
+
processXMLStream: () => processXMLStream,
|
|
48
|
+
simplify: () => simplify,
|
|
49
|
+
stringify: () => stringify,
|
|
50
|
+
stringifyNode: () => stringifyNode,
|
|
51
|
+
stringifyNodes: () => stringifyNodes,
|
|
52
|
+
toContentString: () => toContentString
|
|
53
|
+
});
|
|
54
|
+
module.exports = __toCommonJS(index_exports);
|
|
55
|
+
|
|
56
|
+
// src/errors/types.ts
|
|
57
|
+
var RXMLParseError = class extends Error {
|
|
58
|
+
constructor(message, cause, line, column) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.cause = cause;
|
|
61
|
+
this.line = line;
|
|
62
|
+
this.column = column;
|
|
63
|
+
this.name = "RXMLParseError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var RXMLDuplicateStringTagError = class extends Error {
|
|
67
|
+
constructor(message) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.name = "RXMLDuplicateStringTagError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var RXMLCoercionError = class extends Error {
|
|
73
|
+
constructor(message, cause) {
|
|
74
|
+
super(message);
|
|
75
|
+
this.cause = cause;
|
|
76
|
+
this.name = "RXMLCoercionError";
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var RXMLStringifyError = class extends Error {
|
|
80
|
+
constructor(message, cause) {
|
|
81
|
+
super(message);
|
|
82
|
+
this.cause = cause;
|
|
83
|
+
this.name = "RXMLStringifyError";
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var RXMLStreamError = class extends Error {
|
|
87
|
+
constructor(message, cause) {
|
|
88
|
+
super(message);
|
|
89
|
+
this.cause = cause;
|
|
90
|
+
this.name = "RXMLStreamError";
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
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
|
+
// src/core/types.ts
|
|
454
|
+
var CharCodes = {
|
|
455
|
+
OPEN_BRACKET: "<".charCodeAt(0),
|
|
456
|
+
CLOSE_BRACKET: ">".charCodeAt(0),
|
|
457
|
+
MINUS: "-".charCodeAt(0),
|
|
458
|
+
SLASH: "/".charCodeAt(0),
|
|
459
|
+
EXCLAMATION: "!".charCodeAt(0),
|
|
460
|
+
QUESTION: "?".charCodeAt(0),
|
|
461
|
+
SINGLE_QUOTE: "'".charCodeAt(0),
|
|
462
|
+
DOUBLE_QUOTE: '"'.charCodeAt(0),
|
|
463
|
+
OPEN_CORNER_BRACKET: "[".charCodeAt(0),
|
|
464
|
+
CLOSE_CORNER_BRACKET: "]".charCodeAt(0),
|
|
465
|
+
SPACE: " ".charCodeAt(0),
|
|
466
|
+
TAB: " ".charCodeAt(0),
|
|
467
|
+
NEWLINE: "\n".charCodeAt(0),
|
|
468
|
+
CARRIAGE_RETURN: "\r".charCodeAt(0)
|
|
469
|
+
};
|
|
470
|
+
var DEFAULT_NO_CHILD_NODES = [
|
|
471
|
+
"img",
|
|
472
|
+
"br",
|
|
473
|
+
"input",
|
|
474
|
+
"meta",
|
|
475
|
+
"link",
|
|
476
|
+
"hr",
|
|
477
|
+
"area",
|
|
478
|
+
"base",
|
|
479
|
+
"col",
|
|
480
|
+
"embed",
|
|
481
|
+
"param",
|
|
482
|
+
"source",
|
|
483
|
+
"track",
|
|
484
|
+
"wbr"
|
|
485
|
+
];
|
|
486
|
+
var NAME_SPACER = "\r\n >/= ";
|
|
487
|
+
|
|
488
|
+
// src/utils/helpers.ts
|
|
489
|
+
function isNameStartChar(ch) {
|
|
490
|
+
return /[A-Za-z_:]/.test(ch);
|
|
491
|
+
}
|
|
492
|
+
function isNameChar(ch) {
|
|
493
|
+
return /[A-Za-z0-9_.:-]/.test(ch);
|
|
494
|
+
}
|
|
495
|
+
function skipQuoted(s, i) {
|
|
496
|
+
const quote = s[i];
|
|
497
|
+
i++;
|
|
498
|
+
while (i < s.length) {
|
|
499
|
+
const ch = s[i];
|
|
500
|
+
if (ch === "\\") {
|
|
501
|
+
i += 2;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (ch === quote) return i + 1;
|
|
505
|
+
i++;
|
|
506
|
+
}
|
|
507
|
+
return i;
|
|
508
|
+
}
|
|
509
|
+
function parseName(s, pos) {
|
|
510
|
+
const start = pos;
|
|
511
|
+
while (NAME_SPACER.indexOf(s[pos]) === -1 && s[pos]) {
|
|
512
|
+
pos++;
|
|
513
|
+
}
|
|
514
|
+
return { name: s.slice(start, pos), newPos: pos };
|
|
515
|
+
}
|
|
516
|
+
function parseString(s, pos) {
|
|
517
|
+
const startChar = s[pos];
|
|
518
|
+
const startPos = pos + 1;
|
|
519
|
+
const endPos = s.indexOf(startChar, startPos);
|
|
520
|
+
if (endPos === -1) {
|
|
521
|
+
const tagEnd = s.indexOf(">", startPos);
|
|
522
|
+
if (tagEnd !== -1) {
|
|
523
|
+
return { value: s.slice(startPos, tagEnd), newPos: tagEnd };
|
|
524
|
+
}
|
|
525
|
+
return { value: s.slice(startPos), newPos: s.length };
|
|
526
|
+
}
|
|
527
|
+
return { value: s.slice(startPos, endPos), newPos: endPos + 1 };
|
|
528
|
+
}
|
|
529
|
+
function getLineColumn(s, pos) {
|
|
530
|
+
let line = 1;
|
|
531
|
+
let column = 1;
|
|
532
|
+
for (let i = 0; i < pos && i < s.length; i++) {
|
|
533
|
+
if (s[i] === "\n") {
|
|
534
|
+
line++;
|
|
535
|
+
column = 1;
|
|
536
|
+
} else {
|
|
537
|
+
column++;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return { line, column };
|
|
541
|
+
}
|
|
542
|
+
function escapeXml(text) {
|
|
543
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
544
|
+
}
|
|
545
|
+
function escapeXmlMinimalText(text) {
|
|
546
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/]]>/g, "]]>");
|
|
547
|
+
}
|
|
548
|
+
function escapeXmlMinimalAttr(value, wrapper = '"') {
|
|
549
|
+
let escaped = value.replace(/&/g, "&").replace(/</g, "<");
|
|
550
|
+
if (wrapper === '"') {
|
|
551
|
+
escaped = escaped.replace(/"/g, """);
|
|
552
|
+
} else {
|
|
553
|
+
escaped = escaped.replace(/'/g, "'");
|
|
554
|
+
}
|
|
555
|
+
return escaped;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// src/schema/extraction.ts
|
|
559
|
+
function extractRawInner(xmlContent, tagName) {
|
|
560
|
+
const len = xmlContent.length;
|
|
561
|
+
const target = tagName;
|
|
562
|
+
let bestStart = -1;
|
|
563
|
+
let bestEnd = -1;
|
|
564
|
+
let bestDepth = Number.POSITIVE_INFINITY;
|
|
565
|
+
let i = 0;
|
|
566
|
+
let depth = 0;
|
|
567
|
+
while (i < len) {
|
|
568
|
+
const lt = xmlContent.indexOf("<", i);
|
|
569
|
+
if (lt === -1) return void 0;
|
|
570
|
+
i = lt + 1;
|
|
571
|
+
if (i >= len) return void 0;
|
|
572
|
+
const ch = xmlContent[i];
|
|
573
|
+
if (ch === "!") {
|
|
574
|
+
if (xmlContent.startsWith("!--", i + 1)) {
|
|
575
|
+
const close = xmlContent.indexOf("-->", i + 4);
|
|
576
|
+
i = close === -1 ? len : close + 3;
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
if (xmlContent.startsWith("![CDATA[", i + 1)) {
|
|
580
|
+
const close = xmlContent.indexOf("]]>", i + 9);
|
|
581
|
+
i = close === -1 ? len : close + 3;
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
const gt = xmlContent.indexOf(">", i + 1);
|
|
585
|
+
i = gt === -1 ? len : gt + 1;
|
|
586
|
+
continue;
|
|
587
|
+
} else if (ch === "?") {
|
|
588
|
+
const close = xmlContent.indexOf("?>", i + 1);
|
|
589
|
+
i = close === -1 ? len : close + 2;
|
|
590
|
+
continue;
|
|
591
|
+
} else if (ch === "/") {
|
|
592
|
+
const gt = xmlContent.indexOf(">", i + 1);
|
|
593
|
+
i = gt === -1 ? len : gt + 1;
|
|
594
|
+
depth = Math.max(0, depth - 1);
|
|
595
|
+
continue;
|
|
596
|
+
} else {
|
|
597
|
+
let j = i;
|
|
598
|
+
if (j < len && isNameStartChar(xmlContent[j])) {
|
|
599
|
+
j++;
|
|
600
|
+
while (j < len && isNameChar(xmlContent[j])) j++;
|
|
601
|
+
}
|
|
602
|
+
const name = xmlContent.slice(i, j);
|
|
603
|
+
let k = j;
|
|
604
|
+
let isSelfClosing = false;
|
|
605
|
+
while (k < len) {
|
|
606
|
+
const c = xmlContent[k];
|
|
607
|
+
if (c === '"' || c === "'") {
|
|
608
|
+
k = skipQuoted(xmlContent, k);
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
if (c === ">") break;
|
|
612
|
+
if (c === "/" && xmlContent[k + 1] === ">") {
|
|
613
|
+
isSelfClosing = true;
|
|
614
|
+
k++;
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
k++;
|
|
618
|
+
}
|
|
619
|
+
const tagEnd = k;
|
|
620
|
+
if (name === target) {
|
|
621
|
+
const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
|
|
622
|
+
if (isSelfClosing) {
|
|
623
|
+
if (depth < bestDepth) {
|
|
624
|
+
bestStart = contentStart;
|
|
625
|
+
bestEnd = contentStart;
|
|
626
|
+
bestDepth = depth;
|
|
627
|
+
}
|
|
628
|
+
} else {
|
|
629
|
+
let pos = contentStart;
|
|
630
|
+
let sameDepth = 1;
|
|
631
|
+
while (pos < len) {
|
|
632
|
+
const nextLt = xmlContent.indexOf("<", pos);
|
|
633
|
+
if (nextLt === -1) break;
|
|
634
|
+
const nx = nextLt + 1;
|
|
635
|
+
if (nx >= len) break;
|
|
636
|
+
const h = xmlContent[nx];
|
|
637
|
+
if (h === "!") {
|
|
638
|
+
if (xmlContent.startsWith("!--", nx + 1)) {
|
|
639
|
+
const close = xmlContent.indexOf("-->", nx + 4);
|
|
640
|
+
pos = close === -1 ? len : close + 3;
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (xmlContent.startsWith("![CDATA[", nx + 1)) {
|
|
644
|
+
const close = xmlContent.indexOf("]]>", nx + 9);
|
|
645
|
+
pos = close === -1 ? len : close + 3;
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
const gt2 = xmlContent.indexOf(">", nx + 1);
|
|
649
|
+
pos = gt2 === -1 ? len : gt2 + 1;
|
|
650
|
+
continue;
|
|
651
|
+
} else if (h === "?") {
|
|
652
|
+
const close = xmlContent.indexOf("?>", nx + 1);
|
|
653
|
+
pos = close === -1 ? len : close + 2;
|
|
654
|
+
continue;
|
|
655
|
+
} else if (h === "/") {
|
|
656
|
+
let t = nx + 1;
|
|
657
|
+
if (t < len && isNameStartChar(xmlContent[t])) {
|
|
658
|
+
t++;
|
|
659
|
+
while (t < len && isNameChar(xmlContent[t])) t++;
|
|
660
|
+
}
|
|
661
|
+
const endName = xmlContent.slice(nx + 1, t);
|
|
662
|
+
const gt2 = xmlContent.indexOf(">", t);
|
|
663
|
+
if (endName === target) {
|
|
664
|
+
sameDepth--;
|
|
665
|
+
if (sameDepth === 0) {
|
|
666
|
+
if (depth < bestDepth) {
|
|
667
|
+
bestStart = contentStart;
|
|
668
|
+
bestEnd = nextLt;
|
|
669
|
+
bestDepth = depth;
|
|
670
|
+
}
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
pos = gt2 === -1 ? len : gt2 + 1;
|
|
675
|
+
continue;
|
|
676
|
+
} else {
|
|
677
|
+
let t = nx;
|
|
678
|
+
if (t < len && isNameStartChar(xmlContent[t])) {
|
|
679
|
+
t++;
|
|
680
|
+
while (t < len && isNameChar(xmlContent[t])) t++;
|
|
681
|
+
}
|
|
682
|
+
let u = t;
|
|
683
|
+
let isSelfClosingNested = false;
|
|
684
|
+
while (u < len) {
|
|
685
|
+
const cu = xmlContent[u];
|
|
686
|
+
if (cu === '"' || cu === "'") {
|
|
687
|
+
u = skipQuoted(xmlContent, u);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
if (cu === ">") break;
|
|
691
|
+
if (cu === "/" && xmlContent[u + 1] === ">") {
|
|
692
|
+
isSelfClosingNested = true;
|
|
693
|
+
u++;
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
u++;
|
|
697
|
+
}
|
|
698
|
+
const startName = xmlContent.slice(nx, t);
|
|
699
|
+
if (startName === target && !isSelfClosingNested) {
|
|
700
|
+
sameDepth++;
|
|
701
|
+
}
|
|
702
|
+
pos = xmlContent[u] === ">" ? u + 1 : u + 1;
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
|
|
709
|
+
depth += isSelfClosing ? 0 : 1;
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (bestStart !== -1) {
|
|
714
|
+
return xmlContent.slice(bestStart, bestEnd);
|
|
715
|
+
}
|
|
716
|
+
return void 0;
|
|
717
|
+
}
|
|
718
|
+
function findFirstTopLevelRange(xmlContent, tagName) {
|
|
719
|
+
const len = xmlContent.length;
|
|
720
|
+
const target = tagName;
|
|
721
|
+
let i = 0;
|
|
722
|
+
let depth = 0;
|
|
723
|
+
while (i < len) {
|
|
724
|
+
const lt = xmlContent.indexOf("<", i);
|
|
725
|
+
if (lt === -1) return void 0;
|
|
726
|
+
i = lt + 1;
|
|
727
|
+
if (i >= len) return void 0;
|
|
728
|
+
const ch = xmlContent[i];
|
|
729
|
+
if (ch === "!") {
|
|
730
|
+
if (xmlContent.startsWith("!--", i + 1)) {
|
|
731
|
+
const close = xmlContent.indexOf("-->", i + 4);
|
|
732
|
+
i = close === -1 ? len : close + 3;
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
if (xmlContent.startsWith("![CDATA[", i + 1)) {
|
|
736
|
+
const close = xmlContent.indexOf("]]>", i + 9);
|
|
737
|
+
i = close === -1 ? len : close + 3;
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
const gt = xmlContent.indexOf(">", i + 1);
|
|
741
|
+
i = gt === -1 ? len : gt + 1;
|
|
742
|
+
continue;
|
|
743
|
+
} else if (ch === "?") {
|
|
744
|
+
const close = xmlContent.indexOf("?>", i + 1);
|
|
745
|
+
i = close === -1 ? len : close + 2;
|
|
746
|
+
continue;
|
|
747
|
+
} else if (ch === "/") {
|
|
748
|
+
const gt = xmlContent.indexOf(">", i + 1);
|
|
749
|
+
i = gt === -1 ? len : gt + 1;
|
|
750
|
+
depth = Math.max(0, depth - 1);
|
|
751
|
+
continue;
|
|
752
|
+
} else {
|
|
753
|
+
let j = i;
|
|
754
|
+
if (j < len && isNameStartChar(xmlContent[j])) {
|
|
755
|
+
j++;
|
|
756
|
+
while (j < len && isNameChar(xmlContent[j])) j++;
|
|
757
|
+
}
|
|
758
|
+
const name = xmlContent.slice(i, j);
|
|
759
|
+
let k = j;
|
|
760
|
+
let isSelfClosing = false;
|
|
761
|
+
while (k < len) {
|
|
762
|
+
const c = xmlContent[k];
|
|
763
|
+
if (c === '"' || c === "'") {
|
|
764
|
+
k = skipQuoted(xmlContent, k);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (c === ">") break;
|
|
768
|
+
if (c === "/" && xmlContent[k + 1] === ">") {
|
|
769
|
+
isSelfClosing = true;
|
|
770
|
+
k++;
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
k++;
|
|
774
|
+
}
|
|
775
|
+
const tagEnd = k;
|
|
776
|
+
if (depth === 0 && name === target) {
|
|
777
|
+
const contentStart = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
|
|
778
|
+
if (isSelfClosing) return { start: contentStart, end: contentStart };
|
|
779
|
+
let pos = contentStart;
|
|
780
|
+
let sameDepth = 1;
|
|
781
|
+
while (pos < len) {
|
|
782
|
+
const nextLt = xmlContent.indexOf("<", pos);
|
|
783
|
+
if (nextLt === -1) break;
|
|
784
|
+
const nx = nextLt + 1;
|
|
785
|
+
if (nx >= len) break;
|
|
786
|
+
const h = xmlContent[nx];
|
|
787
|
+
if (h === "!") {
|
|
788
|
+
if (xmlContent.startsWith("!--", nx + 1)) {
|
|
789
|
+
const close = xmlContent.indexOf("-->", nx + 4);
|
|
790
|
+
pos = close === -1 ? len : close + 3;
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
if (xmlContent.startsWith("![CDATA[", nx + 1)) {
|
|
794
|
+
const close = xmlContent.indexOf("]]>", nx + 9);
|
|
795
|
+
pos = close === -1 ? len : close + 3;
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
const gt2 = xmlContent.indexOf(">", nx + 1);
|
|
799
|
+
pos = gt2 === -1 ? len : gt2 + 1;
|
|
800
|
+
continue;
|
|
801
|
+
} else if (h === "?") {
|
|
802
|
+
const close = xmlContent.indexOf("?>", nx + 1);
|
|
803
|
+
pos = close === -1 ? len : close + 2;
|
|
804
|
+
continue;
|
|
805
|
+
} else if (h === "/") {
|
|
806
|
+
let t = nx + 1;
|
|
807
|
+
if (t < len && isNameStartChar(xmlContent[t])) {
|
|
808
|
+
t++;
|
|
809
|
+
while (t < len && isNameChar(xmlContent[t])) t++;
|
|
810
|
+
}
|
|
811
|
+
const endName = xmlContent.slice(nx + 1, t);
|
|
812
|
+
const gt2 = xmlContent.indexOf(">", t);
|
|
813
|
+
if (endName === target) {
|
|
814
|
+
sameDepth--;
|
|
815
|
+
if (sameDepth === 0) {
|
|
816
|
+
return { start: contentStart, end: nextLt };
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
pos = gt2 === -1 ? len : gt2 + 1;
|
|
820
|
+
continue;
|
|
821
|
+
} else {
|
|
822
|
+
let t = nx;
|
|
823
|
+
if (t < len && isNameStartChar(xmlContent[t])) {
|
|
824
|
+
t++;
|
|
825
|
+
while (t < len && isNameChar(xmlContent[t])) t++;
|
|
826
|
+
}
|
|
827
|
+
const startName = xmlContent.slice(nx, t);
|
|
828
|
+
let u = t;
|
|
829
|
+
let isSelfClosingNested = false;
|
|
830
|
+
while (u < len) {
|
|
831
|
+
const cu = xmlContent[u];
|
|
832
|
+
if (cu === '"' || cu === "'") {
|
|
833
|
+
u = skipQuoted(xmlContent, u);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (cu === ">") break;
|
|
837
|
+
if (cu === "/" && xmlContent[u + 1] === ">") {
|
|
838
|
+
isSelfClosingNested = true;
|
|
839
|
+
u++;
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
u++;
|
|
843
|
+
}
|
|
844
|
+
if (startName === target && !isSelfClosingNested) {
|
|
845
|
+
sameDepth++;
|
|
846
|
+
}
|
|
847
|
+
pos = xmlContent[u] === ">" ? u + 1 : u + 1;
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return void 0;
|
|
852
|
+
}
|
|
853
|
+
i = xmlContent[tagEnd] === ">" ? tagEnd + 1 : tagEnd + 1;
|
|
854
|
+
depth += isSelfClosing ? 0 : 1;
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return void 0;
|
|
859
|
+
}
|
|
860
|
+
function countTagOccurrences(xmlContent, tagName, excludeRanges, shouldSkipFirst = true) {
|
|
861
|
+
const len = xmlContent.length;
|
|
862
|
+
const target = tagName;
|
|
863
|
+
let i = 0;
|
|
864
|
+
let count = 0;
|
|
865
|
+
let skipFirstLocal = shouldSkipFirst;
|
|
866
|
+
const isExcluded = (pos) => {
|
|
867
|
+
if (!excludeRanges || excludeRanges.length === 0) return false;
|
|
868
|
+
for (const r of excludeRanges) {
|
|
869
|
+
if (pos >= r.start && pos < r.end) return true;
|
|
870
|
+
}
|
|
871
|
+
return false;
|
|
872
|
+
};
|
|
873
|
+
while (i < len) {
|
|
874
|
+
const lt = xmlContent.indexOf("<", i);
|
|
875
|
+
if (lt === -1) break;
|
|
876
|
+
i = lt + 1;
|
|
877
|
+
if (i >= len) break;
|
|
878
|
+
const ch = xmlContent[i];
|
|
879
|
+
if (ch === "!") {
|
|
880
|
+
if (xmlContent.startsWith("!--", i + 1)) {
|
|
881
|
+
const close = xmlContent.indexOf("-->", i + 4);
|
|
882
|
+
i = close === -1 ? len : close + 3;
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
if (xmlContent.startsWith("![CDATA[", i + 1)) {
|
|
886
|
+
const close = xmlContent.indexOf("]]>", i + 9);
|
|
887
|
+
i = close === -1 ? len : close + 3;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
const gt = xmlContent.indexOf(">", i + 1);
|
|
891
|
+
i = gt === -1 ? len : gt + 1;
|
|
892
|
+
continue;
|
|
893
|
+
} else if (ch === "?") {
|
|
894
|
+
const close = xmlContent.indexOf("?>", i + 1);
|
|
895
|
+
i = close === -1 ? len : close + 2;
|
|
896
|
+
continue;
|
|
897
|
+
} else if (ch === "/") {
|
|
898
|
+
const gt = xmlContent.indexOf(">", i + 1);
|
|
899
|
+
i = gt === -1 ? len : gt + 1;
|
|
900
|
+
continue;
|
|
901
|
+
} else {
|
|
902
|
+
let j = i;
|
|
903
|
+
if (j < len && isNameStartChar(xmlContent[j])) {
|
|
904
|
+
j++;
|
|
905
|
+
while (j < len && isNameChar(xmlContent[j])) j++;
|
|
906
|
+
}
|
|
907
|
+
const name = xmlContent.slice(i, j);
|
|
908
|
+
let k = j;
|
|
909
|
+
while (k < len) {
|
|
910
|
+
const c = xmlContent[k];
|
|
911
|
+
if (c === '"' || c === "'") {
|
|
912
|
+
k = skipQuoted(xmlContent, k);
|
|
913
|
+
continue;
|
|
914
|
+
}
|
|
915
|
+
if (c === ">") break;
|
|
916
|
+
if (c === "/" && xmlContent[k + 1] === ">") {
|
|
917
|
+
k++;
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
k++;
|
|
921
|
+
}
|
|
922
|
+
if (name === target && !isExcluded(lt)) {
|
|
923
|
+
if (skipFirstLocal) {
|
|
924
|
+
skipFirstLocal = false;
|
|
925
|
+
} else {
|
|
926
|
+
count++;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
i = k + 1;
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
return count;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// src/core/tokenizer.ts
|
|
937
|
+
var XMLTokenizer = class {
|
|
938
|
+
constructor(xmlString, options = {}) {
|
|
939
|
+
this.pos = 0;
|
|
940
|
+
this.xmlString = xmlString;
|
|
941
|
+
this.options = {
|
|
942
|
+
keepComments: false,
|
|
943
|
+
keepWhitespace: false,
|
|
944
|
+
noChildNodes: DEFAULT_NO_CHILD_NODES.slice(),
|
|
945
|
+
textNodeName: "#text",
|
|
946
|
+
throwOnDuplicateStringTags: true,
|
|
947
|
+
...options
|
|
948
|
+
};
|
|
949
|
+
this.pos = options.pos || 0;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Parse XML children recursively
|
|
953
|
+
*/
|
|
954
|
+
parseChildren(tagName) {
|
|
955
|
+
const children = [];
|
|
956
|
+
let consumedToEnd = false;
|
|
957
|
+
while (this.xmlString[this.pos]) {
|
|
958
|
+
if (this.xmlString.charCodeAt(this.pos) === CharCodes.OPEN_BRACKET) {
|
|
959
|
+
if (this.xmlString.charCodeAt(this.pos + 1) === CharCodes.SLASH) {
|
|
960
|
+
const closeStart = this.pos + 2;
|
|
961
|
+
this.pos = this.xmlString.indexOf(">", this.pos);
|
|
962
|
+
const closeTag = this.xmlString.substring(closeStart, this.pos);
|
|
963
|
+
if (tagName && closeTag.trim() !== tagName) {
|
|
964
|
+
const { line, column } = getLineColumn(this.xmlString, this.pos);
|
|
965
|
+
throw new RXMLParseError(
|
|
966
|
+
`Unexpected close tag at line ${line}, column ${column}. Expected </${tagName}>, found </${closeTag}>`,
|
|
967
|
+
void 0,
|
|
968
|
+
line,
|
|
969
|
+
column
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
if (this.pos !== -1) this.pos += 1;
|
|
973
|
+
return children;
|
|
974
|
+
} else if (this.xmlString.charCodeAt(this.pos + 1) === CharCodes.EXCLAMATION) {
|
|
975
|
+
const prevPos = this.pos;
|
|
976
|
+
this.handleSpecialContent(children);
|
|
977
|
+
if (this.pos >= this.xmlString.length && prevPos < this.xmlString.length) {
|
|
978
|
+
consumedToEnd = true;
|
|
979
|
+
}
|
|
980
|
+
} else {
|
|
981
|
+
const node = this.parseNode();
|
|
982
|
+
children.push(node);
|
|
983
|
+
if (node.tagName[0] === "?") {
|
|
984
|
+
children.push(...node.children);
|
|
985
|
+
node.children = [];
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
} else {
|
|
989
|
+
const text = this.parseText();
|
|
990
|
+
if (this.options.keepWhitespace) {
|
|
991
|
+
if (text.length > 0) {
|
|
992
|
+
children.push(text);
|
|
993
|
+
}
|
|
994
|
+
} else {
|
|
995
|
+
const trimmed = text.trim();
|
|
996
|
+
if (trimmed.length > 0) {
|
|
997
|
+
children.push(trimmed);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
this.pos++;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (tagName && this.pos >= this.xmlString.length && !consumedToEnd) {
|
|
1004
|
+
const { line, column } = getLineColumn(this.xmlString, this.pos - 1);
|
|
1005
|
+
throw new RXMLParseError(
|
|
1006
|
+
`Unclosed tag at line ${line}, column ${column}. Expected closing tag </${tagName}>`,
|
|
1007
|
+
void 0,
|
|
1008
|
+
line,
|
|
1009
|
+
column
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
return children;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Parse a single XML node
|
|
1016
|
+
*/
|
|
1017
|
+
parseNode() {
|
|
1018
|
+
var _a;
|
|
1019
|
+
this.pos++;
|
|
1020
|
+
const { name: tagName, newPos } = parseName(this.xmlString, this.pos);
|
|
1021
|
+
this.pos = newPos;
|
|
1022
|
+
const attributes = {};
|
|
1023
|
+
let children = [];
|
|
1024
|
+
while (this.xmlString.charCodeAt(this.pos) !== CharCodes.CLOSE_BRACKET && this.xmlString[this.pos]) {
|
|
1025
|
+
const c = this.xmlString.charCodeAt(this.pos);
|
|
1026
|
+
if (c === CharCodes.SPACE || c === CharCodes.TAB || c === CharCodes.NEWLINE || c === CharCodes.CARRIAGE_RETURN) {
|
|
1027
|
+
this.pos++;
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
if (c > 64 && c < 91 || c > 96 && c < 123) {
|
|
1031
|
+
const { name: attrName, newPos: nameEnd } = parseName(
|
|
1032
|
+
this.xmlString,
|
|
1033
|
+
this.pos
|
|
1034
|
+
);
|
|
1035
|
+
this.pos = nameEnd;
|
|
1036
|
+
while (this.pos < this.xmlString.length && (this.xmlString.charCodeAt(this.pos) === CharCodes.SPACE || this.xmlString.charCodeAt(this.pos) === CharCodes.TAB || this.xmlString.charCodeAt(this.pos) === CharCodes.NEWLINE || this.xmlString.charCodeAt(this.pos) === CharCodes.CARRIAGE_RETURN)) {
|
|
1037
|
+
this.pos++;
|
|
1038
|
+
}
|
|
1039
|
+
let value = null;
|
|
1040
|
+
if (this.pos < this.xmlString.length && this.xmlString[this.pos] === "=") {
|
|
1041
|
+
this.pos++;
|
|
1042
|
+
while (this.pos < this.xmlString.length && (this.xmlString.charCodeAt(this.pos) === CharCodes.SPACE || this.xmlString.charCodeAt(this.pos) === CharCodes.TAB || this.xmlString.charCodeAt(this.pos) === CharCodes.NEWLINE || this.xmlString.charCodeAt(this.pos) === CharCodes.CARRIAGE_RETURN)) {
|
|
1043
|
+
this.pos++;
|
|
1044
|
+
}
|
|
1045
|
+
const code = this.xmlString.charCodeAt(this.pos);
|
|
1046
|
+
if (code === CharCodes.SINGLE_QUOTE || code === CharCodes.DOUBLE_QUOTE) {
|
|
1047
|
+
const { value: parsedValue, newPos: valueEnd } = parseString(
|
|
1048
|
+
this.xmlString,
|
|
1049
|
+
this.pos
|
|
1050
|
+
);
|
|
1051
|
+
value = parsedValue;
|
|
1052
|
+
this.pos = valueEnd;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
attributes[attrName] = value;
|
|
1056
|
+
} else {
|
|
1057
|
+
this.pos++;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
const isSelfClosing = this.xmlString.charCodeAt(this.pos - 1) === CharCodes.SLASH || tagName[0] === "?" && this.xmlString.charCodeAt(this.pos - 1) === CharCodes.QUESTION;
|
|
1061
|
+
if (!isSelfClosing) {
|
|
1062
|
+
if (tagName === "script") {
|
|
1063
|
+
const start = this.pos + 1;
|
|
1064
|
+
this.pos = this.xmlString.indexOf("</script>", this.pos);
|
|
1065
|
+
if (this.pos === -1) {
|
|
1066
|
+
children = [this.xmlString.slice(start)];
|
|
1067
|
+
this.pos = this.xmlString.length;
|
|
1068
|
+
} else {
|
|
1069
|
+
children = [this.xmlString.slice(start, this.pos)];
|
|
1070
|
+
this.pos += 9;
|
|
1071
|
+
}
|
|
1072
|
+
} else if (tagName === "style") {
|
|
1073
|
+
const start = this.pos + 1;
|
|
1074
|
+
this.pos = this.xmlString.indexOf("</style>", this.pos);
|
|
1075
|
+
if (this.pos === -1) {
|
|
1076
|
+
children = [this.xmlString.slice(start)];
|
|
1077
|
+
this.pos = this.xmlString.length;
|
|
1078
|
+
} else {
|
|
1079
|
+
children = [this.xmlString.slice(start, this.pos)];
|
|
1080
|
+
this.pos += 8;
|
|
1081
|
+
}
|
|
1082
|
+
} else if (((_a = this.options.noChildNodes) == null ? void 0 : _a.indexOf(tagName)) === -1) {
|
|
1083
|
+
this.pos++;
|
|
1084
|
+
children = this.parseChildren(tagName);
|
|
1085
|
+
} else {
|
|
1086
|
+
this.pos++;
|
|
1087
|
+
if (DEFAULT_NO_CHILD_NODES.includes(tagName)) {
|
|
1088
|
+
} else {
|
|
1089
|
+
const closingTag = `</${tagName}>`;
|
|
1090
|
+
const closingPos = this.xmlString.indexOf(closingTag, this.pos);
|
|
1091
|
+
if (closingPos !== -1) {
|
|
1092
|
+
this.pos = closingPos + closingTag.length;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
} else {
|
|
1097
|
+
this.pos++;
|
|
1098
|
+
}
|
|
1099
|
+
return { tagName, attributes, children };
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Parse text content until next tag
|
|
1103
|
+
*/
|
|
1104
|
+
parseText() {
|
|
1105
|
+
const start = this.pos;
|
|
1106
|
+
this.pos = this.xmlString.indexOf("<", this.pos) - 1;
|
|
1107
|
+
if (this.pos === -2) {
|
|
1108
|
+
this.pos = this.xmlString.length;
|
|
1109
|
+
}
|
|
1110
|
+
return this.xmlString.slice(start, this.pos + 1);
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Handle comments, CDATA, and DOCTYPE declarations
|
|
1114
|
+
*/
|
|
1115
|
+
handleSpecialContent(children) {
|
|
1116
|
+
if (this.xmlString.charCodeAt(this.pos + 2) === CharCodes.MINUS) {
|
|
1117
|
+
this.handleComment(children);
|
|
1118
|
+
} else if (this.xmlString.charCodeAt(this.pos + 2) === CharCodes.OPEN_CORNER_BRACKET && this.xmlString.charCodeAt(this.pos + 8) === CharCodes.OPEN_CORNER_BRACKET && this.xmlString.substr(this.pos + 3, 5).toLowerCase() === "cdata") {
|
|
1119
|
+
this.handleCData(children);
|
|
1120
|
+
} else {
|
|
1121
|
+
this.handleDoctype(children);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Handle XML comments
|
|
1126
|
+
*/
|
|
1127
|
+
handleComment(children) {
|
|
1128
|
+
const startCommentPos = this.pos;
|
|
1129
|
+
while (this.pos !== -1 && !(this.xmlString.charCodeAt(this.pos) === CharCodes.CLOSE_BRACKET && this.xmlString.charCodeAt(this.pos - 1) === CharCodes.MINUS && this.xmlString.charCodeAt(this.pos - 2) === CharCodes.MINUS)) {
|
|
1130
|
+
this.pos = this.xmlString.indexOf(">", this.pos + 1);
|
|
1131
|
+
}
|
|
1132
|
+
if (this.pos === -1) {
|
|
1133
|
+
this.pos = this.xmlString.length;
|
|
1134
|
+
}
|
|
1135
|
+
if (this.options.keepComments) {
|
|
1136
|
+
children.push(this.xmlString.substring(startCommentPos, this.pos + 1));
|
|
1137
|
+
}
|
|
1138
|
+
this.pos++;
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Handle CDATA sections
|
|
1142
|
+
*/
|
|
1143
|
+
handleCData(children) {
|
|
1144
|
+
const cdataEndIndex = this.xmlString.indexOf("]]>", this.pos);
|
|
1145
|
+
if (cdataEndIndex === -1) {
|
|
1146
|
+
children.push(this.xmlString.substr(this.pos + 9));
|
|
1147
|
+
this.pos = this.xmlString.length;
|
|
1148
|
+
} else {
|
|
1149
|
+
children.push(this.xmlString.substring(this.pos + 9, cdataEndIndex));
|
|
1150
|
+
this.pos = cdataEndIndex + 3;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Handle DOCTYPE declarations
|
|
1155
|
+
*/
|
|
1156
|
+
handleDoctype(children) {
|
|
1157
|
+
const startDoctype = this.pos + 1;
|
|
1158
|
+
this.pos += 2;
|
|
1159
|
+
let encapsulated = false;
|
|
1160
|
+
while ((this.xmlString.charCodeAt(this.pos) !== CharCodes.CLOSE_BRACKET || encapsulated) && this.xmlString[this.pos]) {
|
|
1161
|
+
if (this.xmlString.charCodeAt(this.pos) === CharCodes.OPEN_CORNER_BRACKET) {
|
|
1162
|
+
encapsulated = true;
|
|
1163
|
+
} else if (encapsulated && this.xmlString.charCodeAt(this.pos) === CharCodes.CLOSE_CORNER_BRACKET) {
|
|
1164
|
+
encapsulated = false;
|
|
1165
|
+
}
|
|
1166
|
+
this.pos++;
|
|
1167
|
+
}
|
|
1168
|
+
children.push(this.xmlString.substring(startDoctype, this.pos));
|
|
1169
|
+
this.pos++;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Get current position
|
|
1173
|
+
*/
|
|
1174
|
+
getPosition() {
|
|
1175
|
+
return this.pos;
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Set position
|
|
1179
|
+
*/
|
|
1180
|
+
setPosition(pos) {
|
|
1181
|
+
this.pos = pos;
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
// src/core/parser.ts
|
|
1186
|
+
function parse(xmlInner, schema, options = {}) {
|
|
1187
|
+
var _a, _b, _c;
|
|
1188
|
+
const textNodeName = (_a = options.textNodeName) != null ? _a : "#text";
|
|
1189
|
+
const throwDup = (_b = options.throwOnDuplicateStringTags) != null ? _b : true;
|
|
1190
|
+
let actualXmlInner = xmlInner.trim();
|
|
1191
|
+
if (actualXmlInner.startsWith("<") && actualXmlInner.endsWith(">")) {
|
|
1192
|
+
const s = actualXmlInner;
|
|
1193
|
+
let i = 0;
|
|
1194
|
+
let rootStart = -1;
|
|
1195
|
+
let rootName = "";
|
|
1196
|
+
while (i < s.length) {
|
|
1197
|
+
const lt = s.indexOf("<", i);
|
|
1198
|
+
if (lt === -1) break;
|
|
1199
|
+
const next = s[lt + 1];
|
|
1200
|
+
if (next === "?") {
|
|
1201
|
+
const end = s.indexOf("?>", lt + 2);
|
|
1202
|
+
i = end === -1 ? s.length : end + 2;
|
|
1203
|
+
continue;
|
|
1204
|
+
}
|
|
1205
|
+
if (next === "!") {
|
|
1206
|
+
if (s.startsWith("!--", lt + 2)) {
|
|
1207
|
+
const end2 = s.indexOf("-->", lt + 5);
|
|
1208
|
+
i = end2 === -1 ? s.length : end2 + 3;
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
if (s.startsWith("![CDATA[", lt + 2)) {
|
|
1212
|
+
const end2 = s.indexOf("]]>", lt + 9);
|
|
1213
|
+
i = end2 === -1 ? s.length : end2 + 3;
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
const end = s.indexOf(">", lt + 2);
|
|
1217
|
+
i = end === -1 ? s.length : end + 1;
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
if (next === "/") {
|
|
1221
|
+
break;
|
|
1222
|
+
}
|
|
1223
|
+
let j = lt + 1;
|
|
1224
|
+
while (j < s.length && s[j] !== " " && s[j] !== "\n" && s[j] !== "\r" && s[j] !== " " && s[j] !== "/" && s[j] !== ">") {
|
|
1225
|
+
j++;
|
|
1226
|
+
}
|
|
1227
|
+
rootStart = lt;
|
|
1228
|
+
rootName = s.slice(lt + 1, j);
|
|
1229
|
+
break;
|
|
1230
|
+
}
|
|
1231
|
+
if (rootStart === 0 && rootName) {
|
|
1232
|
+
const range = findFirstTopLevelRange(s, rootName);
|
|
1233
|
+
if (range) {
|
|
1234
|
+
let fullEnd = range.end + `</${rootName}>`.length;
|
|
1235
|
+
const closeHead = s.indexOf(`</${rootName}`, range.end);
|
|
1236
|
+
if (closeHead === range.end) {
|
|
1237
|
+
let p = closeHead + 2 + rootName.length;
|
|
1238
|
+
while (p < s.length && /\s/.test(s[p])) p++;
|
|
1239
|
+
if (s[p] === ">") fullEnd = p + 1;
|
|
1240
|
+
}
|
|
1241
|
+
if (fullEnd === s.length) {
|
|
1242
|
+
const unwrapped = unwrapJsonSchema(schema);
|
|
1243
|
+
const schemaProps = unwrapped && typeof unwrapped === "object" ? unwrapped.properties : void 0;
|
|
1244
|
+
if (schemaProps && !Object.prototype.hasOwnProperty.call(schemaProps, rootName)) {
|
|
1245
|
+
actualXmlInner = s.slice(range.start, range.end);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
const stringTypedProps = getStringTypedProperties(schema);
|
|
1252
|
+
const duplicateKeys = /* @__PURE__ */ new Set();
|
|
1253
|
+
for (const key of stringTypedProps) {
|
|
1254
|
+
const excludeRanges = [];
|
|
1255
|
+
for (const other of stringTypedProps) {
|
|
1256
|
+
if (other === key) continue;
|
|
1257
|
+
const range = findFirstTopLevelRange(actualXmlInner, other);
|
|
1258
|
+
if (range) excludeRanges.push(range);
|
|
1259
|
+
}
|
|
1260
|
+
const occurrences = countTagOccurrences(
|
|
1261
|
+
actualXmlInner,
|
|
1262
|
+
key,
|
|
1263
|
+
excludeRanges,
|
|
1264
|
+
true
|
|
1265
|
+
);
|
|
1266
|
+
if (occurrences > 0 && throwDup) {
|
|
1267
|
+
throw new RXMLDuplicateStringTagError(
|
|
1268
|
+
`Duplicate string tags for <${key}> detected`
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
if (occurrences > 0 && !throwDup) {
|
|
1272
|
+
duplicateKeys.add(key);
|
|
1273
|
+
if (options.onError) {
|
|
1274
|
+
options.onError(
|
|
1275
|
+
`RXML: Duplicate string tags for <${key}> detected; using first occurrence.`,
|
|
1276
|
+
{ tag: key, occurrences }
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
let xmlInnerForParsing = actualXmlInner;
|
|
1282
|
+
const originalContentMap = /* @__PURE__ */ new Map();
|
|
1283
|
+
try {
|
|
1284
|
+
const ranges = [];
|
|
1285
|
+
for (const key of stringTypedProps) {
|
|
1286
|
+
const r = findFirstTopLevelRange(actualXmlInner, key);
|
|
1287
|
+
if (r && r.end > r.start) ranges.push({ ...r, key });
|
|
1288
|
+
}
|
|
1289
|
+
if (ranges.length > 0) {
|
|
1290
|
+
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
1291
|
+
const filtered = [];
|
|
1292
|
+
for (const r of sorted) {
|
|
1293
|
+
const last = filtered[filtered.length - 1];
|
|
1294
|
+
if (last && r.start >= last.start && r.end <= last.end) {
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1297
|
+
filtered.push(r);
|
|
1298
|
+
}
|
|
1299
|
+
if (filtered.length > 0) {
|
|
1300
|
+
filtered.sort((a, b) => a.start - b.start);
|
|
1301
|
+
let rebuilt = "";
|
|
1302
|
+
let cursor = 0;
|
|
1303
|
+
for (const r of filtered) {
|
|
1304
|
+
if (cursor < r.start)
|
|
1305
|
+
rebuilt += actualXmlInner.slice(cursor, r.start);
|
|
1306
|
+
const placeholder = `__RXML_PLACEHOLDER_${r.key}__`;
|
|
1307
|
+
const originalContent = actualXmlInner.slice(r.start, r.end);
|
|
1308
|
+
originalContentMap.set(placeholder, originalContent);
|
|
1309
|
+
rebuilt += placeholder;
|
|
1310
|
+
cursor = r.end;
|
|
1311
|
+
}
|
|
1312
|
+
if (cursor < actualXmlInner.length)
|
|
1313
|
+
rebuilt += actualXmlInner.slice(cursor);
|
|
1314
|
+
xmlInnerForParsing = rebuilt;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
} catch (error) {
|
|
1318
|
+
if (options.onError) {
|
|
1319
|
+
options.onError(
|
|
1320
|
+
"RXML: Failed to replace string placeholders, falling back to original XML.",
|
|
1321
|
+
{ error }
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
xmlInnerForParsing = actualXmlInner;
|
|
1325
|
+
}
|
|
1326
|
+
let parsedNodes;
|
|
1327
|
+
try {
|
|
1328
|
+
const wrappedXml = `<root>${xmlInnerForParsing}</root>`;
|
|
1329
|
+
const tokenizer = new XMLTokenizer(wrappedXml, {
|
|
1330
|
+
...options,
|
|
1331
|
+
textNodeName
|
|
1332
|
+
});
|
|
1333
|
+
const rootNode = tokenizer.parseNode();
|
|
1334
|
+
parsedNodes = rootNode.children;
|
|
1335
|
+
} catch (cause) {
|
|
1336
|
+
throw new RXMLParseError("Failed to parse XML", cause);
|
|
1337
|
+
}
|
|
1338
|
+
const parsedArgs = domToObject(parsedNodes, schema, textNodeName);
|
|
1339
|
+
const args = {};
|
|
1340
|
+
for (const k of Object.keys(parsedArgs || {})) {
|
|
1341
|
+
const v = parsedArgs[k];
|
|
1342
|
+
let val = v;
|
|
1343
|
+
const propSchema = getPropertySchema(schema, k);
|
|
1344
|
+
const propType = getSchemaType(propSchema);
|
|
1345
|
+
if (propType === "string" && duplicateKeys.has(k) && Array.isArray(v)) {
|
|
1346
|
+
const firstValue = v[0];
|
|
1347
|
+
if (typeof firstValue === "string" && firstValue.startsWith("__RXML_PLACEHOLDER_")) {
|
|
1348
|
+
const originalContent = originalContentMap.get(firstValue);
|
|
1349
|
+
if (originalContent !== void 0) {
|
|
1350
|
+
args[k] = originalContent;
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
} else {
|
|
1354
|
+
args[k] = firstValue;
|
|
1355
|
+
continue;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (propType === "string" && !Array.isArray(v)) {
|
|
1359
|
+
const placeholderUsed = typeof v === "string" && v.startsWith("__RXML_PLACEHOLDER_") || v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, textNodeName) && typeof v[textNodeName] === "string" && v[textNodeName].startsWith(
|
|
1360
|
+
"__RXML_PLACEHOLDER_"
|
|
1361
|
+
);
|
|
1362
|
+
if (placeholderUsed) {
|
|
1363
|
+
let placeholderKey;
|
|
1364
|
+
if (typeof v === "string") {
|
|
1365
|
+
placeholderKey = v;
|
|
1366
|
+
} else {
|
|
1367
|
+
placeholderKey = v[textNodeName];
|
|
1368
|
+
}
|
|
1369
|
+
const originalContent = originalContentMap.get(placeholderKey);
|
|
1370
|
+
if (originalContent !== void 0) {
|
|
1371
|
+
args[k] = originalContent;
|
|
1372
|
+
continue;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
const raw = extractRawInner(actualXmlInner, k);
|
|
1376
|
+
if (typeof raw === "string") {
|
|
1377
|
+
args[k] = raw;
|
|
1378
|
+
continue;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
if (v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, textNodeName)) {
|
|
1382
|
+
val = v[textNodeName];
|
|
1383
|
+
}
|
|
1384
|
+
if (Array.isArray(v)) {
|
|
1385
|
+
if (propType === "string") {
|
|
1386
|
+
const mapped = v.map((item) => {
|
|
1387
|
+
if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, textNodeName)) {
|
|
1388
|
+
const textVal = item[textNodeName];
|
|
1389
|
+
return typeof textVal === "string" ? textVal : String(textVal);
|
|
1390
|
+
}
|
|
1391
|
+
return typeof item === "string" ? item : String(item);
|
|
1392
|
+
});
|
|
1393
|
+
if (mapped.length > 1 && throwDup) {
|
|
1394
|
+
throw new RXMLDuplicateStringTagError(
|
|
1395
|
+
`Duplicate string tags for <${k}> detected`
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
if (mapped.length > 1 && !throwDup && options.onError) {
|
|
1399
|
+
options.onError(
|
|
1400
|
+
`RXML: Duplicate string tags for <${k}> detected; using first occurrence.`,
|
|
1401
|
+
{ tag: k, occurrences: mapped.length }
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
args[k] = (_c = mapped[0]) != null ? _c : "";
|
|
1405
|
+
continue;
|
|
1406
|
+
} else {
|
|
1407
|
+
val = processArrayContent(v, propSchema, textNodeName);
|
|
1408
|
+
}
|
|
1409
|
+
} else if (v && typeof v === "object" && !Object.prototype.hasOwnProperty.call(v, textNodeName)) {
|
|
1410
|
+
const obj = v;
|
|
1411
|
+
const keys2 = Object.keys(obj);
|
|
1412
|
+
if (keys2.length === 1 && keys2[0] === "item") {
|
|
1413
|
+
const itemValue = obj.item;
|
|
1414
|
+
if (Array.isArray(itemValue)) {
|
|
1415
|
+
val = itemValue.map((item) => {
|
|
1416
|
+
let currentVal = item;
|
|
1417
|
+
if (item && typeof item === "object" && Object.prototype.hasOwnProperty.call(item, textNodeName)) {
|
|
1418
|
+
currentVal = item[textNodeName];
|
|
1419
|
+
}
|
|
1420
|
+
const trimmed = typeof currentVal === "string" ? currentVal.trim() : currentVal;
|
|
1421
|
+
if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
|
|
1422
|
+
const num = Number(trimmed);
|
|
1423
|
+
if (Number.isFinite(num)) return num;
|
|
1424
|
+
}
|
|
1425
|
+
return trimmed;
|
|
1426
|
+
});
|
|
1427
|
+
} else {
|
|
1428
|
+
const trimmed = typeof itemValue === "string" ? itemValue.trim() : itemValue;
|
|
1429
|
+
if (typeof trimmed === "string" && /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(trimmed)) {
|
|
1430
|
+
const num = Number(trimmed);
|
|
1431
|
+
val = Number.isFinite(num) ? num : trimmed;
|
|
1432
|
+
} else {
|
|
1433
|
+
val = trimmed;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
} else {
|
|
1437
|
+
let isIndexedTuple = false;
|
|
1438
|
+
if (keys2.length > 0 && keys2.every((key) => /^\d+$/.test(key))) {
|
|
1439
|
+
const indices = keys2.map((k2) => parseInt(k2, 10)).sort((a, b) => a - b);
|
|
1440
|
+
isIndexedTuple = indices[0] === 0 && indices.every((val2, idx) => val2 === idx);
|
|
1441
|
+
}
|
|
1442
|
+
if (isIndexedTuple) {
|
|
1443
|
+
val = processIndexedTuple(obj, textNodeName);
|
|
1444
|
+
} else {
|
|
1445
|
+
val = v;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
args[k] = typeof val === "string" ? val.trim() : val;
|
|
1450
|
+
}
|
|
1451
|
+
for (const key of stringTypedProps) {
|
|
1452
|
+
if (!Object.prototype.hasOwnProperty.call(args, key)) {
|
|
1453
|
+
const raw = extractRawInner(actualXmlInner, key);
|
|
1454
|
+
if (typeof raw === "string") {
|
|
1455
|
+
args[key] = raw;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
let dataToCoerce = args;
|
|
1460
|
+
const keys = Object.keys(args);
|
|
1461
|
+
if (keys.length === 1) {
|
|
1462
|
+
const rootKey = keys[0];
|
|
1463
|
+
const rootValue = args[rootKey];
|
|
1464
|
+
const unwrapped = unwrapJsonSchema(schema);
|
|
1465
|
+
if (unwrapped && typeof unwrapped === "object") {
|
|
1466
|
+
const schemaProps = unwrapped.properties;
|
|
1467
|
+
if (schemaProps && !Object.prototype.hasOwnProperty.call(schemaProps, rootKey)) {
|
|
1468
|
+
dataToCoerce = rootValue;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
try {
|
|
1473
|
+
const coerced = coerceDomBySchema(dataToCoerce, schema);
|
|
1474
|
+
return coerced;
|
|
1475
|
+
} catch (error) {
|
|
1476
|
+
throw new RXMLCoercionError("Failed to coerce by schema", error);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function parseWithoutSchema(xmlString, options = {}) {
|
|
1480
|
+
try {
|
|
1481
|
+
const tokenizer = new XMLTokenizer(xmlString, options);
|
|
1482
|
+
return tokenizer.parseChildren();
|
|
1483
|
+
} catch (error) {
|
|
1484
|
+
if (error instanceof RXMLParseError) {
|
|
1485
|
+
const isSimple = xmlString.split("<").length < 6;
|
|
1486
|
+
if (error.message.includes("Unexpected close tag") && isSimple || error.message.includes("Unclosed tag") && isSimple) {
|
|
1487
|
+
throw new RXMLParseError(
|
|
1488
|
+
error.message,
|
|
1489
|
+
error.cause,
|
|
1490
|
+
error.line,
|
|
1491
|
+
error.column
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (options.onError) {
|
|
1496
|
+
options.onError("Failed to parse XML without schema", { error });
|
|
1497
|
+
}
|
|
1498
|
+
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
|
+
}
|
|
1512
|
+
if (partialResults.length > 0) {
|
|
1513
|
+
return partialResults;
|
|
1514
|
+
}
|
|
1515
|
+
} catch (e) {
|
|
1516
|
+
}
|
|
1517
|
+
return [xmlString.trim()];
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
function parseNode(xmlString, options = {}) {
|
|
1521
|
+
try {
|
|
1522
|
+
const tokenizer = new XMLTokenizer(xmlString, options);
|
|
1523
|
+
return tokenizer.parseNode();
|
|
1524
|
+
} catch (error) {
|
|
1525
|
+
throw new RXMLParseError("Failed to parse XML node", error);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
function simplify(children) {
|
|
1529
|
+
if (!children.length) {
|
|
1530
|
+
return "";
|
|
1531
|
+
}
|
|
1532
|
+
if (children.length === 1 && typeof children[0] === "string") {
|
|
1533
|
+
return children[0];
|
|
1534
|
+
}
|
|
1535
|
+
const out = {};
|
|
1536
|
+
children.forEach((child) => {
|
|
1537
|
+
if (typeof child !== "object") {
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
if (!out[child.tagName]) {
|
|
1541
|
+
out[child.tagName] = [];
|
|
1542
|
+
}
|
|
1543
|
+
const kids = simplify(child.children);
|
|
1544
|
+
let nodeValue = kids;
|
|
1545
|
+
if (Object.keys(child.attributes).length) {
|
|
1546
|
+
if (typeof kids === "string") {
|
|
1547
|
+
nodeValue = kids;
|
|
1548
|
+
if (kids !== "") {
|
|
1549
|
+
nodeValue = { _attributes: child.attributes, value: kids };
|
|
1550
|
+
} else {
|
|
1551
|
+
nodeValue = { _attributes: child.attributes };
|
|
1552
|
+
}
|
|
1553
|
+
} else if (typeof kids === "object" && kids !== null) {
|
|
1554
|
+
kids._attributes = child.attributes;
|
|
1555
|
+
nodeValue = kids;
|
|
1556
|
+
} else {
|
|
1557
|
+
nodeValue = { _attributes: child.attributes };
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
out[child.tagName].push(nodeValue);
|
|
1561
|
+
});
|
|
1562
|
+
for (const key in out) {
|
|
1563
|
+
const value = out[key];
|
|
1564
|
+
if (Array.isArray(value) && value.length === 1) {
|
|
1565
|
+
out[key] = value[0];
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
return out;
|
|
1569
|
+
}
|
|
1570
|
+
function filter(children, filterFn, depth = 0, path = "") {
|
|
1571
|
+
const out = [];
|
|
1572
|
+
children.forEach((child, i) => {
|
|
1573
|
+
if (typeof child === "object" && filterFn(child, i, depth, path)) {
|
|
1574
|
+
out.push(child);
|
|
1575
|
+
}
|
|
1576
|
+
if (typeof child === "object" && child.children) {
|
|
1577
|
+
const kids = filter(
|
|
1578
|
+
child.children,
|
|
1579
|
+
filterFn,
|
|
1580
|
+
depth + 1,
|
|
1581
|
+
(path ? path + "." : "") + i + "." + child.tagName
|
|
1582
|
+
);
|
|
1583
|
+
out.push(...kids);
|
|
1584
|
+
}
|
|
1585
|
+
});
|
|
1586
|
+
return out;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// src/core/stream.ts
|
|
1590
|
+
var import_stream = require("stream");
|
|
1591
|
+
var XMLTransformStream = class extends import_stream.Transform {
|
|
1592
|
+
constructor(offset, parseOptions = {}) {
|
|
1593
|
+
super({ readableObjectMode: true });
|
|
1594
|
+
this.buffer = "";
|
|
1595
|
+
this.emittedCount = 0;
|
|
1596
|
+
this.sawTagChar = false;
|
|
1597
|
+
if (typeof offset === "string") {
|
|
1598
|
+
this.position = offset.length;
|
|
1599
|
+
} else {
|
|
1600
|
+
this.position = offset || 0;
|
|
1601
|
+
}
|
|
1602
|
+
this.parseOptions = {
|
|
1603
|
+
keepComments: false,
|
|
1604
|
+
keepWhitespace: false,
|
|
1605
|
+
...parseOptions
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
_transform(chunk, encoding, callback) {
|
|
1609
|
+
try {
|
|
1610
|
+
const incoming = chunk.toString();
|
|
1611
|
+
if (incoming.includes("<")) this.sawTagChar = true;
|
|
1612
|
+
this.buffer += incoming;
|
|
1613
|
+
this.processBuffer();
|
|
1614
|
+
callback();
|
|
1615
|
+
} catch (error) {
|
|
1616
|
+
callback(new RXMLStreamError("Transform error", error));
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
_flush(callback) {
|
|
1620
|
+
try {
|
|
1621
|
+
if (this.buffer.length > 0) {
|
|
1622
|
+
this.processBuffer(true);
|
|
1623
|
+
}
|
|
1624
|
+
if (this.sawTagChar && this.emittedCount === 0) {
|
|
1625
|
+
throw new RXMLStreamError(
|
|
1626
|
+
"Flush error",
|
|
1627
|
+
new Error("No XML elements could be parsed from stream")
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1630
|
+
callback();
|
|
1631
|
+
} catch (error) {
|
|
1632
|
+
callback(new RXMLStreamError("Flush error", error));
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
processBuffer(isFlush = false) {
|
|
1636
|
+
while (this.buffer.length > 0) {
|
|
1637
|
+
const openBracket = this.buffer.indexOf("<");
|
|
1638
|
+
if (openBracket === -1) {
|
|
1639
|
+
if (isFlush) this.buffer = "";
|
|
1640
|
+
break;
|
|
1641
|
+
}
|
|
1642
|
+
if (openBracket > 0) {
|
|
1643
|
+
this.buffer = this.buffer.slice(openBracket);
|
|
1644
|
+
}
|
|
1645
|
+
if (this.buffer.startsWith("<?") || this.buffer.startsWith("<!--") || this.buffer.startsWith("<![CDATA[")) {
|
|
1646
|
+
const endMarkers = {
|
|
1647
|
+
"<?": "?>",
|
|
1648
|
+
"<!--": "-->",
|
|
1649
|
+
"<![CDATA[": "]]>"
|
|
1650
|
+
};
|
|
1651
|
+
let endMarker = "";
|
|
1652
|
+
for (const [start, end] of Object.entries(endMarkers)) {
|
|
1653
|
+
if (this.buffer.startsWith(start)) {
|
|
1654
|
+
endMarker = end;
|
|
1655
|
+
break;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
const endPos = endMarker ? this.buffer.indexOf(endMarker) : -1;
|
|
1659
|
+
if (endPos === -1) {
|
|
1660
|
+
if (!isFlush) break;
|
|
1661
|
+
this.buffer = "";
|
|
1662
|
+
break;
|
|
1663
|
+
}
|
|
1664
|
+
if (this.parseOptions.keepComments && this.buffer.startsWith("<!--")) {
|
|
1665
|
+
this.push(this.buffer.slice(0, endPos + endMarker.length));
|
|
1666
|
+
}
|
|
1667
|
+
this.buffer = this.buffer.slice(endPos + endMarker.length);
|
|
1668
|
+
continue;
|
|
1669
|
+
}
|
|
1670
|
+
if (this.buffer.startsWith("</")) {
|
|
1671
|
+
const closeEnd = this.buffer.indexOf(">");
|
|
1672
|
+
if (closeEnd === -1) {
|
|
1673
|
+
if (!isFlush) break;
|
|
1674
|
+
this.buffer = "";
|
|
1675
|
+
break;
|
|
1676
|
+
}
|
|
1677
|
+
this.buffer = this.buffer.slice(closeEnd + 1);
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1680
|
+
const openTagEnd = this.buffer.indexOf(">");
|
|
1681
|
+
if (openTagEnd === -1) {
|
|
1682
|
+
if (!isFlush) break;
|
|
1683
|
+
this.buffer = "";
|
|
1684
|
+
break;
|
|
1685
|
+
}
|
|
1686
|
+
const openTagContent = this.buffer.slice(1, openTagEnd);
|
|
1687
|
+
const nameMatch = openTagContent.match(/^([a-zA-Z_][\w.-]*)/);
|
|
1688
|
+
if (!nameMatch) {
|
|
1689
|
+
this.buffer = this.buffer.slice(1);
|
|
1690
|
+
continue;
|
|
1691
|
+
}
|
|
1692
|
+
const tagName = nameMatch[1];
|
|
1693
|
+
const isSelfClosing = this.buffer[openTagEnd - 1] === "/";
|
|
1694
|
+
if (isSelfClosing) {
|
|
1695
|
+
const elementEnd2 = openTagEnd + 1;
|
|
1696
|
+
const elementXml2 = this.buffer.slice(0, elementEnd2);
|
|
1697
|
+
try {
|
|
1698
|
+
const tokenizer = new XMLTokenizer(elementXml2, this.parseOptions);
|
|
1699
|
+
const node = tokenizer.parseNode();
|
|
1700
|
+
this.emitElementAndChildren(node);
|
|
1701
|
+
this.buffer = this.buffer.slice(elementEnd2);
|
|
1702
|
+
continue;
|
|
1703
|
+
} catch (e) {
|
|
1704
|
+
this.buffer = this.buffer.slice(1);
|
|
1705
|
+
continue;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
const closingTag = `</${tagName}>`;
|
|
1709
|
+
let depth = 1;
|
|
1710
|
+
let searchStart = openTagEnd + 1;
|
|
1711
|
+
let elementEnd = -1;
|
|
1712
|
+
while (searchStart < this.buffer.length) {
|
|
1713
|
+
let nextOpen = this.buffer.indexOf(`<${tagName}`, searchStart);
|
|
1714
|
+
while (nextOpen !== -1) {
|
|
1715
|
+
const after = this.buffer[nextOpen + tagName.length + 1];
|
|
1716
|
+
if (after === void 0 || after === ">" || /\s/.test(after)) break;
|
|
1717
|
+
nextOpen = this.buffer.indexOf(`<${tagName}`, nextOpen + 1);
|
|
1718
|
+
}
|
|
1719
|
+
const nextCloseStart = this.buffer.indexOf(`</${tagName}`, searchStart);
|
|
1720
|
+
if (nextCloseStart === -1) break;
|
|
1721
|
+
if (nextOpen !== -1 && nextOpen < nextCloseStart) {
|
|
1722
|
+
depth++;
|
|
1723
|
+
searchStart = nextOpen + 1;
|
|
1724
|
+
} else {
|
|
1725
|
+
depth--;
|
|
1726
|
+
let p = nextCloseStart + 2 + tagName.length;
|
|
1727
|
+
while (p < this.buffer.length && /\s/.test(this.buffer[p])) p++;
|
|
1728
|
+
if (this.buffer[p] !== ">") break;
|
|
1729
|
+
const closeAdvance = p + 1;
|
|
1730
|
+
searchStart = closeAdvance;
|
|
1731
|
+
if (depth === 0) {
|
|
1732
|
+
elementEnd = searchStart;
|
|
1733
|
+
break;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
if (elementEnd === -1) {
|
|
1738
|
+
if (!isFlush) break;
|
|
1739
|
+
this.buffer = this.buffer.slice(1);
|
|
1740
|
+
continue;
|
|
1741
|
+
}
|
|
1742
|
+
const elementXml = this.buffer.slice(0, elementEnd);
|
|
1743
|
+
try {
|
|
1744
|
+
const tokenizer = new XMLTokenizer(elementXml, this.parseOptions);
|
|
1745
|
+
const node = tokenizer.parseNode();
|
|
1746
|
+
this.emitElementAndChildren(node);
|
|
1747
|
+
this.buffer = this.buffer.slice(elementEnd);
|
|
1748
|
+
} catch (e) {
|
|
1749
|
+
this.emit("error", new RXMLStreamError("Parse error", e));
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Emit an element and recursively emit its children as separate events
|
|
1756
|
+
*/
|
|
1757
|
+
emitElementAndChildren(node) {
|
|
1758
|
+
if (typeof node === "string") {
|
|
1759
|
+
if (this.parseOptions.keepComments && node.includes("<!--")) {
|
|
1760
|
+
this.push(node);
|
|
1761
|
+
this.emittedCount++;
|
|
1762
|
+
}
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
this.push(node);
|
|
1766
|
+
this.emittedCount++;
|
|
1767
|
+
for (const child of node.children) {
|
|
1768
|
+
this.emitElementAndChildren(child);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
function createXMLStream(offset, parseOptions) {
|
|
1773
|
+
return new XMLTransformStream(offset, parseOptions);
|
|
1774
|
+
}
|
|
1775
|
+
async function parseFromStream(stream, offset, parseOptions) {
|
|
1776
|
+
return new Promise((resolve, reject) => {
|
|
1777
|
+
const results = [];
|
|
1778
|
+
const transformStream = createXMLStream(offset, parseOptions);
|
|
1779
|
+
const onSourceError = (err) => {
|
|
1780
|
+
transformStream.destroy(err);
|
|
1781
|
+
};
|
|
1782
|
+
stream.on("error", onSourceError);
|
|
1783
|
+
transformStream.on("data", (element) => {
|
|
1784
|
+
results.push(element);
|
|
1785
|
+
});
|
|
1786
|
+
transformStream.on("end", () => {
|
|
1787
|
+
stream.off("error", onSourceError);
|
|
1788
|
+
resolve(results);
|
|
1789
|
+
});
|
|
1790
|
+
transformStream.on("error", (error) => {
|
|
1791
|
+
stream.off("error", onSourceError);
|
|
1792
|
+
reject(new RXMLStreamError("Stream parsing failed", error));
|
|
1793
|
+
});
|
|
1794
|
+
stream.pipe(transformStream);
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
async function* processXMLStream(stream, offset, parseOptions) {
|
|
1798
|
+
const transformStream = createXMLStream(offset, parseOptions);
|
|
1799
|
+
let ended = false;
|
|
1800
|
+
let error = null;
|
|
1801
|
+
const queue = [];
|
|
1802
|
+
let resolveNext = null;
|
|
1803
|
+
const onSourceError = (err) => {
|
|
1804
|
+
error = err;
|
|
1805
|
+
transformStream.destroy(err);
|
|
1806
|
+
};
|
|
1807
|
+
stream.on("error", onSourceError);
|
|
1808
|
+
transformStream.on("data", (element) => {
|
|
1809
|
+
if (resolveNext) {
|
|
1810
|
+
resolveNext({ value: element, done: false });
|
|
1811
|
+
resolveNext = null;
|
|
1812
|
+
} else {
|
|
1813
|
+
queue.push(element);
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1816
|
+
transformStream.on("end", () => {
|
|
1817
|
+
ended = true;
|
|
1818
|
+
if (resolveNext) {
|
|
1819
|
+
resolveNext({ value: void 0, done: true });
|
|
1820
|
+
resolveNext = null;
|
|
1821
|
+
}
|
|
1822
|
+
stream.off("error", onSourceError);
|
|
1823
|
+
});
|
|
1824
|
+
transformStream.on("error", (err) => {
|
|
1825
|
+
error = err;
|
|
1826
|
+
if (resolveNext) {
|
|
1827
|
+
resolveNext({ value: void 0, done: true });
|
|
1828
|
+
resolveNext = null;
|
|
1829
|
+
}
|
|
1830
|
+
stream.off("error", onSourceError);
|
|
1831
|
+
});
|
|
1832
|
+
stream.pipe(transformStream);
|
|
1833
|
+
while (true) {
|
|
1834
|
+
if (error) {
|
|
1835
|
+
throw new RXMLStreamError("Stream processing error", error);
|
|
1836
|
+
}
|
|
1837
|
+
if (queue.length > 0) {
|
|
1838
|
+
yield queue.shift();
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
if (ended) {
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
const result = await new Promise(
|
|
1845
|
+
(resolve) => {
|
|
1846
|
+
resolveNext = resolve;
|
|
1847
|
+
}
|
|
1848
|
+
);
|
|
1849
|
+
if (result.done) {
|
|
1850
|
+
if (error) {
|
|
1851
|
+
throw new RXMLStreamError("Stream processing error", error);
|
|
1852
|
+
}
|
|
1853
|
+
break;
|
|
1854
|
+
}
|
|
1855
|
+
yield result.value;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
async function* findElementByIdStream(stream, id, offset, parseOptions) {
|
|
1859
|
+
for await (const element of processXMLStream(stream, offset, parseOptions)) {
|
|
1860
|
+
if (typeof element === "object" && element.attributes.id === id) {
|
|
1861
|
+
yield element;
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
async function* findElementsByClassStream(stream, className, offset, parseOptions) {
|
|
1866
|
+
const classRegex = new RegExp(`\\b${className}\\b`);
|
|
1867
|
+
for await (const element of processXMLStream(stream, offset, parseOptions)) {
|
|
1868
|
+
if (typeof element === "object" && element.attributes.class && classRegex.test(element.attributes.class)) {
|
|
1869
|
+
yield element;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
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
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2092
|
+
0 && (module.exports = {
|
|
2093
|
+
RXMLCoercionError,
|
|
2094
|
+
RXMLDuplicateStringTagError,
|
|
2095
|
+
RXMLParseError,
|
|
2096
|
+
RXMLStreamError,
|
|
2097
|
+
RXMLStringifyError,
|
|
2098
|
+
XMLTokenizer,
|
|
2099
|
+
XMLTransformStream,
|
|
2100
|
+
coerceDomBySchema,
|
|
2101
|
+
countTagOccurrences,
|
|
2102
|
+
createXMLStream,
|
|
2103
|
+
domToObject,
|
|
2104
|
+
extractRawInner,
|
|
2105
|
+
filter,
|
|
2106
|
+
findElementByIdStream,
|
|
2107
|
+
findElementsByClassStream,
|
|
2108
|
+
findFirstTopLevelRange,
|
|
2109
|
+
getPropertySchema,
|
|
2110
|
+
getStringTypedProperties,
|
|
2111
|
+
parse,
|
|
2112
|
+
parseFromStream,
|
|
2113
|
+
parseNode,
|
|
2114
|
+
parseWithoutSchema,
|
|
2115
|
+
processArrayContent,
|
|
2116
|
+
processIndexedTuple,
|
|
2117
|
+
processXMLStream,
|
|
2118
|
+
simplify,
|
|
2119
|
+
stringify,
|
|
2120
|
+
stringifyNode,
|
|
2121
|
+
stringifyNodes,
|
|
2122
|
+
toContentString
|
|
2123
|
+
});
|
|
2124
|
+
//# sourceMappingURL=index.cjs.map
|