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