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