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