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