@rgrove/parse-xml 2.0.4 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +84 -337
- package/dist/browser.js +774 -0
- package/dist/browser.js.map +7 -0
- package/dist/global.min.js +10 -0
- package/dist/global.min.js.map +7 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/Parser.d.ts +218 -0
- package/dist/lib/Parser.d.ts.map +1 -0
- package/dist/lib/Parser.js +638 -0
- package/dist/lib/Parser.js.map +1 -0
- package/dist/lib/StringScanner.d.ts +97 -0
- package/dist/lib/StringScanner.d.ts.map +1 -0
- package/dist/lib/StringScanner.js +210 -0
- package/dist/lib/StringScanner.js.map +1 -0
- package/dist/lib/XmlCdata.d.ts +8 -0
- package/dist/lib/XmlCdata.d.ts.map +1 -0
- package/dist/lib/XmlCdata.js +15 -0
- package/dist/lib/XmlCdata.js.map +1 -0
- package/dist/lib/XmlComment.d.ts +16 -0
- package/dist/lib/XmlComment.d.ts.map +1 -0
- package/dist/lib/XmlComment.js +23 -0
- package/dist/lib/XmlComment.js.map +1 -0
- package/dist/lib/XmlDocument.d.ts +29 -0
- package/dist/lib/XmlDocument.d.ts.map +1 -0
- package/dist/lib/XmlDocument.js +47 -0
- package/dist/lib/XmlDocument.js.map +1 -0
- package/dist/lib/XmlElement.d.ts +40 -0
- package/dist/lib/XmlElement.d.ts.map +1 -0
- package/dist/lib/XmlElement.js +51 -0
- package/dist/lib/XmlElement.js.map +1 -0
- package/dist/lib/XmlNode.d.ts +74 -0
- package/dist/lib/XmlNode.d.ts.map +1 -0
- package/dist/lib/XmlNode.js +96 -0
- package/dist/lib/XmlNode.js.map +1 -0
- package/dist/lib/XmlProcessingInstruction.d.ts +22 -0
- package/dist/lib/XmlProcessingInstruction.d.ts.map +1 -0
- package/dist/lib/XmlProcessingInstruction.js +25 -0
- package/dist/lib/XmlProcessingInstruction.js.map +1 -0
- package/dist/lib/XmlText.d.ts +16 -0
- package/dist/lib/XmlText.d.ts.map +1 -0
- package/dist/lib/XmlText.js +23 -0
- package/dist/lib/XmlText.js.map +1 -0
- package/dist/lib/syntax.d.ts +69 -0
- package/dist/lib/syntax.d.ts.map +1 -0
- package/dist/lib/syntax.js +133 -0
- package/dist/lib/syntax.js.map +1 -0
- package/dist/lib/types.d.ts +5 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -0
- package/package.json +36 -22
- package/src/index.ts +30 -0
- package/src/lib/Parser.ts +819 -0
- package/src/lib/StringScanner.ts +254 -0
- package/src/lib/XmlCdata.ts +11 -0
- package/src/lib/XmlComment.ts +26 -0
- package/src/lib/XmlDocument.ts +57 -0
- package/src/lib/XmlElement.ts +81 -0
- package/src/lib/XmlNode.ts +107 -0
- package/src/lib/XmlProcessingInstruction.ts +35 -0
- package/src/lib/XmlText.ts +26 -0
- package/src/lib/syntax.ts +136 -0
- package/src/lib/types.ts +2 -0
- package/CHANGELOG.md +0 -89
- package/dist/commonjs/index.js +0 -434
- package/dist/commonjs/lib/syntax.js +0 -262
- package/dist/umd/parse-xml.min.js +0 -1
- package/src/index.js +0 -451
- package/src/lib/syntax.js +0 -263
package/dist/browser.js
ADDED
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
/*! @rgrove/parse-xml v4.0.0 | ISC License | Copyright Ryan Grove */
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var src_exports = {};
|
|
23
|
+
__export(src_exports, {
|
|
24
|
+
XmlCdata: () => XmlCdata,
|
|
25
|
+
XmlComment: () => XmlComment,
|
|
26
|
+
XmlDocument: () => XmlDocument,
|
|
27
|
+
XmlElement: () => XmlElement,
|
|
28
|
+
XmlNode: () => XmlNode,
|
|
29
|
+
XmlProcessingInstruction: () => XmlProcessingInstruction,
|
|
30
|
+
XmlText: () => XmlText,
|
|
31
|
+
parseXml: () => parseXml
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(src_exports);
|
|
34
|
+
|
|
35
|
+
// src/lib/StringScanner.ts
|
|
36
|
+
var emptyString = "";
|
|
37
|
+
var surrogatePair = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
38
|
+
var StringScanner = class {
|
|
39
|
+
constructor(string) {
|
|
40
|
+
this.h = this.m(string, true);
|
|
41
|
+
this.d = 0;
|
|
42
|
+
this.length = string.length;
|
|
43
|
+
this.j = this.h !== this.length;
|
|
44
|
+
this.string = string;
|
|
45
|
+
if (this.j) {
|
|
46
|
+
let charsToBytes = [];
|
|
47
|
+
for (let byteIndex = 0, charIndex = 0; charIndex < this.h; ++charIndex) {
|
|
48
|
+
charsToBytes[charIndex] = byteIndex;
|
|
49
|
+
byteIndex += string.codePointAt(byteIndex) > 65535 ? 2 : 1;
|
|
50
|
+
}
|
|
51
|
+
this.x = charsToBytes;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
get y() {
|
|
55
|
+
return this.d >= this.h;
|
|
56
|
+
}
|
|
57
|
+
n(charIndex = this.d) {
|
|
58
|
+
var _a;
|
|
59
|
+
return this.j ? (_a = this.x[charIndex]) != null ? _a : Infinity : charIndex;
|
|
60
|
+
}
|
|
61
|
+
m(string, multiByteSafe = this.j) {
|
|
62
|
+
return multiByteSafe ? string.replace(surrogatePair, "_").length : string.length;
|
|
63
|
+
}
|
|
64
|
+
f(count = 1) {
|
|
65
|
+
this.d = Math.min(this.h, this.d + count);
|
|
66
|
+
}
|
|
67
|
+
D(count = 1) {
|
|
68
|
+
let chars = this.g(count);
|
|
69
|
+
this.f(count);
|
|
70
|
+
return chars;
|
|
71
|
+
}
|
|
72
|
+
s(regex) {
|
|
73
|
+
if (!regex.sticky) {
|
|
74
|
+
throw new Error('`regex` must have a sticky flag ("y")');
|
|
75
|
+
}
|
|
76
|
+
regex.lastIndex = this.n();
|
|
77
|
+
let result = regex.exec(this.string);
|
|
78
|
+
if (result === null || result.length === 0) {
|
|
79
|
+
return emptyString;
|
|
80
|
+
}
|
|
81
|
+
let match = result[0];
|
|
82
|
+
this.f(this.m(match));
|
|
83
|
+
return match;
|
|
84
|
+
}
|
|
85
|
+
t(fn) {
|
|
86
|
+
let char;
|
|
87
|
+
let match = emptyString;
|
|
88
|
+
while ((char = this.g()) && fn(char)) {
|
|
89
|
+
match += char;
|
|
90
|
+
this.f();
|
|
91
|
+
}
|
|
92
|
+
return match;
|
|
93
|
+
}
|
|
94
|
+
N(stringToConsume) {
|
|
95
|
+
if (this.b(stringToConsume)) {
|
|
96
|
+
return stringToConsume;
|
|
97
|
+
}
|
|
98
|
+
if (this.j) {
|
|
99
|
+
let { length } = stringToConsume;
|
|
100
|
+
let charLengthToMatch = this.m(stringToConsume);
|
|
101
|
+
if (charLengthToMatch !== length && stringToConsume === this.g(charLengthToMatch)) {
|
|
102
|
+
this.f(charLengthToMatch);
|
|
103
|
+
return stringToConsume;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return emptyString;
|
|
107
|
+
}
|
|
108
|
+
b(stringToConsume) {
|
|
109
|
+
let { length } = stringToConsume;
|
|
110
|
+
if (this.g(length) === stringToConsume) {
|
|
111
|
+
this.f(length);
|
|
112
|
+
return stringToConsume;
|
|
113
|
+
}
|
|
114
|
+
return emptyString;
|
|
115
|
+
}
|
|
116
|
+
E(regex) {
|
|
117
|
+
let restOfString = this.string.slice(this.n());
|
|
118
|
+
let matchByteIndex = restOfString.search(regex);
|
|
119
|
+
if (matchByteIndex <= 0) {
|
|
120
|
+
return emptyString;
|
|
121
|
+
}
|
|
122
|
+
let result = restOfString.slice(0, matchByteIndex);
|
|
123
|
+
this.f(this.m(result));
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
p(searchString) {
|
|
127
|
+
let { string } = this;
|
|
128
|
+
let byteIndex = this.n();
|
|
129
|
+
let matchByteIndex = string.indexOf(searchString, byteIndex);
|
|
130
|
+
if (matchByteIndex <= 0) {
|
|
131
|
+
return emptyString;
|
|
132
|
+
}
|
|
133
|
+
let result = string.slice(byteIndex, matchByteIndex);
|
|
134
|
+
this.f(this.m(result));
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
g(count = 1) {
|
|
138
|
+
let { d: charIndex, j: multiByteMode, string } = this;
|
|
139
|
+
if (multiByteMode) {
|
|
140
|
+
if (charIndex >= this.h) {
|
|
141
|
+
return emptyString;
|
|
142
|
+
}
|
|
143
|
+
return string.slice(
|
|
144
|
+
this.n(charIndex),
|
|
145
|
+
this.n(charIndex + count)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
return string.slice(charIndex, charIndex + count);
|
|
149
|
+
}
|
|
150
|
+
o(index = 0) {
|
|
151
|
+
this.d = index >= 0 ? Math.min(this.h, index) : Math.max(0, this.d + index);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// src/lib/syntax.ts
|
|
156
|
+
var attValueCharDoubleQuote = /[^"&<]+/y;
|
|
157
|
+
var attValueCharSingleQuote = /[^'&<]+/y;
|
|
158
|
+
var attValueNormalizedWhitespace = /[\t\n]/g;
|
|
159
|
+
var endCharData = /<|&|]]>/;
|
|
160
|
+
var predefinedEntities = Object.freeze(Object.assign(/* @__PURE__ */ Object.create(null), {
|
|
161
|
+
amp: "&",
|
|
162
|
+
apos: "'",
|
|
163
|
+
gt: ">",
|
|
164
|
+
lt: "<",
|
|
165
|
+
quot: '"'
|
|
166
|
+
}));
|
|
167
|
+
function isNameChar(char) {
|
|
168
|
+
let cp = getCodePoint(char);
|
|
169
|
+
return cp >= 97 && cp <= 122 || cp >= 65 && cp <= 90 || cp >= 48 && cp <= 57 || cp === 45 || cp === 46 || cp === 183 || cp >= 768 && cp <= 879 || cp >= 8255 && cp <= 8256 || isNameStartChar(char, cp);
|
|
170
|
+
}
|
|
171
|
+
function isNameStartChar(char, cp = getCodePoint(char)) {
|
|
172
|
+
return cp >= 97 && cp <= 122 || cp >= 65 && cp <= 90 || cp === 58 || cp === 95 || cp >= 192 && cp <= 214 || cp >= 216 && cp <= 246 || cp >= 248 && cp <= 767 || cp >= 880 && cp <= 893 || cp >= 895 && cp <= 8191 || cp >= 8204 && cp <= 8205 || cp >= 8304 && cp <= 8591 || cp >= 11264 && cp <= 12271 || cp >= 12289 && cp <= 55295 || cp >= 63744 && cp <= 64975 || cp >= 65008 && cp <= 65533 || cp >= 65536 && cp <= 983039;
|
|
173
|
+
}
|
|
174
|
+
function isReferenceChar(char) {
|
|
175
|
+
return char === "#" || isNameChar(char);
|
|
176
|
+
}
|
|
177
|
+
function isWhitespace(char) {
|
|
178
|
+
let cp = getCodePoint(char);
|
|
179
|
+
return cp === 32 || cp === 9 || cp === 10 || cp === 13;
|
|
180
|
+
}
|
|
181
|
+
function isXmlCodePoint(cp) {
|
|
182
|
+
return cp === 9 || cp === 10 || cp === 13 || cp >= 32 && cp <= 55295 || cp >= 57344 && cp <= 65533 || cp >= 65536 && cp <= 1114111;
|
|
183
|
+
}
|
|
184
|
+
function getCodePoint(char) {
|
|
185
|
+
return char.codePointAt(0) || -1;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/lib/XmlNode.ts
|
|
189
|
+
var XmlNode = class {
|
|
190
|
+
constructor() {
|
|
191
|
+
this.parent = null;
|
|
192
|
+
}
|
|
193
|
+
get document() {
|
|
194
|
+
var _a, _b;
|
|
195
|
+
return (_b = (_a = this.parent) == null ? void 0 : _a.document) != null ? _b : null;
|
|
196
|
+
}
|
|
197
|
+
get isRootNode() {
|
|
198
|
+
return this.parent !== null && this.parent === this.document;
|
|
199
|
+
}
|
|
200
|
+
get preserveWhitespace() {
|
|
201
|
+
var _a;
|
|
202
|
+
return Boolean((_a = this.parent) == null ? void 0 : _a.preserveWhitespace);
|
|
203
|
+
}
|
|
204
|
+
get type() {
|
|
205
|
+
return "";
|
|
206
|
+
}
|
|
207
|
+
toJSON() {
|
|
208
|
+
let json = {
|
|
209
|
+
type: this.type
|
|
210
|
+
};
|
|
211
|
+
if (this.isRootNode) {
|
|
212
|
+
json.isRootNode = true;
|
|
213
|
+
}
|
|
214
|
+
if (this.preserveWhitespace) {
|
|
215
|
+
json.preserveWhitespace = true;
|
|
216
|
+
}
|
|
217
|
+
return json;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
XmlNode.TYPE_CDATA = "cdata";
|
|
221
|
+
XmlNode.TYPE_COMMENT = "comment";
|
|
222
|
+
XmlNode.TYPE_DOCUMENT = "document";
|
|
223
|
+
XmlNode.TYPE_ELEMENT = "element";
|
|
224
|
+
XmlNode.TYPE_PROCESSING_INSTRUCTION = "pi";
|
|
225
|
+
XmlNode.TYPE_TEXT = "text";
|
|
226
|
+
|
|
227
|
+
// src/lib/XmlText.ts
|
|
228
|
+
var XmlText = class extends XmlNode {
|
|
229
|
+
constructor(text = "") {
|
|
230
|
+
super();
|
|
231
|
+
this.text = text;
|
|
232
|
+
}
|
|
233
|
+
get type() {
|
|
234
|
+
return XmlNode.TYPE_TEXT;
|
|
235
|
+
}
|
|
236
|
+
toJSON() {
|
|
237
|
+
return Object.assign(XmlNode.prototype.toJSON.call(this), {
|
|
238
|
+
text: this.text
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/lib/XmlCdata.ts
|
|
244
|
+
var XmlCdata = class extends XmlText {
|
|
245
|
+
get type() {
|
|
246
|
+
return XmlNode.TYPE_CDATA;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/lib/XmlComment.ts
|
|
251
|
+
var XmlComment = class extends XmlNode {
|
|
252
|
+
constructor(content = "") {
|
|
253
|
+
super();
|
|
254
|
+
this.content = content;
|
|
255
|
+
}
|
|
256
|
+
get type() {
|
|
257
|
+
return XmlNode.TYPE_COMMENT;
|
|
258
|
+
}
|
|
259
|
+
toJSON() {
|
|
260
|
+
return Object.assign(XmlNode.prototype.toJSON.call(this), {
|
|
261
|
+
content: this.content
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// src/lib/XmlElement.ts
|
|
267
|
+
var XmlElement = class extends XmlNode {
|
|
268
|
+
constructor(name, attributes = /* @__PURE__ */ Object.create(null), children = []) {
|
|
269
|
+
super();
|
|
270
|
+
this.name = name;
|
|
271
|
+
this.attributes = attributes;
|
|
272
|
+
this.children = children;
|
|
273
|
+
}
|
|
274
|
+
get isEmpty() {
|
|
275
|
+
return this.children.length === 0;
|
|
276
|
+
}
|
|
277
|
+
get preserveWhitespace() {
|
|
278
|
+
let node = this;
|
|
279
|
+
while (node instanceof XmlElement) {
|
|
280
|
+
if ("xml:space" in node.attributes) {
|
|
281
|
+
return node.attributes["xml:space"] === "preserve";
|
|
282
|
+
}
|
|
283
|
+
node = node.parent;
|
|
284
|
+
}
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
get text() {
|
|
288
|
+
return this.children.map((child) => "text" in child ? child.text : "").join("");
|
|
289
|
+
}
|
|
290
|
+
get type() {
|
|
291
|
+
return XmlNode.TYPE_ELEMENT;
|
|
292
|
+
}
|
|
293
|
+
toJSON() {
|
|
294
|
+
return Object.assign(XmlNode.prototype.toJSON.call(this), {
|
|
295
|
+
name: this.name,
|
|
296
|
+
attributes: this.attributes,
|
|
297
|
+
children: this.children.map((child) => child.toJSON())
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// src/lib/XmlDocument.ts
|
|
303
|
+
var XmlDocument = class extends XmlNode {
|
|
304
|
+
constructor(children = []) {
|
|
305
|
+
super();
|
|
306
|
+
this.children = children;
|
|
307
|
+
}
|
|
308
|
+
get document() {
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
get root() {
|
|
312
|
+
for (let child of this.children) {
|
|
313
|
+
if (child instanceof XmlElement) {
|
|
314
|
+
return child;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
get text() {
|
|
320
|
+
return this.children.map((child) => "text" in child ? child.text : "").join("");
|
|
321
|
+
}
|
|
322
|
+
get type() {
|
|
323
|
+
return XmlNode.TYPE_DOCUMENT;
|
|
324
|
+
}
|
|
325
|
+
toJSON() {
|
|
326
|
+
return Object.assign(XmlNode.prototype.toJSON.call(this), {
|
|
327
|
+
children: this.children.map((child) => child.toJSON())
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// src/lib/XmlProcessingInstruction.ts
|
|
333
|
+
var XmlProcessingInstruction = class extends XmlNode {
|
|
334
|
+
constructor(name, content = "") {
|
|
335
|
+
super();
|
|
336
|
+
this.name = name;
|
|
337
|
+
this.content = content;
|
|
338
|
+
}
|
|
339
|
+
get type() {
|
|
340
|
+
return XmlNode.TYPE_PROCESSING_INSTRUCTION;
|
|
341
|
+
}
|
|
342
|
+
toJSON() {
|
|
343
|
+
return Object.assign(XmlNode.prototype.toJSON.call(this), {
|
|
344
|
+
name: this.name,
|
|
345
|
+
content: this.content
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/lib/Parser.ts
|
|
351
|
+
var emptyString2 = "";
|
|
352
|
+
var Parser = class {
|
|
353
|
+
constructor(xml, options = {}) {
|
|
354
|
+
this.document = new XmlDocument();
|
|
355
|
+
this.i = this.document;
|
|
356
|
+
this.options = options;
|
|
357
|
+
this.c = new StringScanner(normalizeXmlString(xml));
|
|
358
|
+
this.F();
|
|
359
|
+
if (!this.z()) {
|
|
360
|
+
throw this.a("Root element is missing or invalid");
|
|
361
|
+
}
|
|
362
|
+
while (this.u()) {
|
|
363
|
+
}
|
|
364
|
+
if (!this.c.y) {
|
|
365
|
+
throw this.a("Extra content at the end of the document");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
k(node) {
|
|
369
|
+
node.parent = this.i;
|
|
370
|
+
this.i.children.push(node);
|
|
371
|
+
}
|
|
372
|
+
v(text) {
|
|
373
|
+
let { children } = this.i;
|
|
374
|
+
let { length } = children;
|
|
375
|
+
if (length > 0) {
|
|
376
|
+
let prevNode = children[length - 1];
|
|
377
|
+
if (prevNode instanceof XmlText) {
|
|
378
|
+
prevNode.text += text;
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
this.k(new XmlText(text));
|
|
383
|
+
}
|
|
384
|
+
G() {
|
|
385
|
+
let attributes = /* @__PURE__ */ Object.create(null);
|
|
386
|
+
while (this.e()) {
|
|
387
|
+
let attrName = this.q();
|
|
388
|
+
if (!attrName) {
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
let attrValue = this.r() && this.H();
|
|
392
|
+
if (attrValue === false) {
|
|
393
|
+
throw this.a("Attribute value expected");
|
|
394
|
+
}
|
|
395
|
+
if (attrName in attributes) {
|
|
396
|
+
throw this.a(`Duplicate attribute: ${attrName}`);
|
|
397
|
+
}
|
|
398
|
+
if (attrName === "xml:space" && attrValue !== "default" && attrValue !== "preserve") {
|
|
399
|
+
throw this.a('Value of the `xml:space` attribute must be "default" or "preserve"');
|
|
400
|
+
}
|
|
401
|
+
attributes[attrName] = attrValue;
|
|
402
|
+
}
|
|
403
|
+
if (this.options.sortAttributes) {
|
|
404
|
+
let attrNames = Object.keys(attributes).sort();
|
|
405
|
+
let sortedAttributes = /* @__PURE__ */ Object.create(null);
|
|
406
|
+
for (let i = 0; i < attrNames.length; ++i) {
|
|
407
|
+
let attrName = attrNames[i];
|
|
408
|
+
sortedAttributes[attrName] = attributes[attrName];
|
|
409
|
+
}
|
|
410
|
+
attributes = sortedAttributes;
|
|
411
|
+
}
|
|
412
|
+
return attributes;
|
|
413
|
+
}
|
|
414
|
+
H() {
|
|
415
|
+
let { c: scanner } = this;
|
|
416
|
+
let quote = scanner.g();
|
|
417
|
+
if (quote !== '"' && quote !== "'") {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
scanner.f();
|
|
421
|
+
let chars;
|
|
422
|
+
let isClosed = false;
|
|
423
|
+
let value = emptyString2;
|
|
424
|
+
let regex = quote === '"' ? attValueCharDoubleQuote : attValueCharSingleQuote;
|
|
425
|
+
matchLoop:
|
|
426
|
+
while (!scanner.y) {
|
|
427
|
+
chars = scanner.s(regex);
|
|
428
|
+
if (chars) {
|
|
429
|
+
this.l(chars);
|
|
430
|
+
value += chars.replace(attValueNormalizedWhitespace, " ");
|
|
431
|
+
}
|
|
432
|
+
switch (scanner.g()) {
|
|
433
|
+
case quote:
|
|
434
|
+
isClosed = true;
|
|
435
|
+
break matchLoop;
|
|
436
|
+
case "&":
|
|
437
|
+
value += this.A();
|
|
438
|
+
continue;
|
|
439
|
+
case "<":
|
|
440
|
+
throw this.a("Unescaped `<` is not allowed in an attribute value");
|
|
441
|
+
case emptyString2:
|
|
442
|
+
break matchLoop;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (!isClosed) {
|
|
446
|
+
throw this.a("Unclosed attribute");
|
|
447
|
+
}
|
|
448
|
+
scanner.f();
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
I() {
|
|
452
|
+
let { c: scanner } = this;
|
|
453
|
+
if (!scanner.b("<![CDATA[")) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
let text = scanner.p("]]>");
|
|
457
|
+
this.l(text);
|
|
458
|
+
if (!scanner.b("]]>")) {
|
|
459
|
+
throw this.a("Unclosed CDATA section");
|
|
460
|
+
}
|
|
461
|
+
if (this.options.preserveCdata) {
|
|
462
|
+
this.k(new XmlCdata(text));
|
|
463
|
+
} else {
|
|
464
|
+
this.v(text);
|
|
465
|
+
}
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
J() {
|
|
469
|
+
let { c: scanner } = this;
|
|
470
|
+
let charData = scanner.E(endCharData);
|
|
471
|
+
if (!charData) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
this.l(charData);
|
|
475
|
+
if (scanner.g(3) === "]]>") {
|
|
476
|
+
throw this.a("Element content may not contain the CDATA section close delimiter `]]>`");
|
|
477
|
+
}
|
|
478
|
+
this.v(charData);
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
B() {
|
|
482
|
+
let { c: scanner } = this;
|
|
483
|
+
if (!scanner.b("<!--")) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
let content = scanner.p("--");
|
|
487
|
+
this.l(content);
|
|
488
|
+
if (!scanner.b("-->")) {
|
|
489
|
+
if (scanner.g(2) === "--") {
|
|
490
|
+
throw this.a("The string `--` isn't allowed inside a comment");
|
|
491
|
+
}
|
|
492
|
+
throw this.a("Unclosed comment");
|
|
493
|
+
}
|
|
494
|
+
if (this.options.preserveComments) {
|
|
495
|
+
this.k(new XmlComment(content.trim()));
|
|
496
|
+
}
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
K() {
|
|
500
|
+
let ref = this.A();
|
|
501
|
+
if (ref) {
|
|
502
|
+
this.v(ref);
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
L() {
|
|
508
|
+
let { c: scanner } = this;
|
|
509
|
+
if (!scanner.b("<!DOCTYPE") || !this.e()) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
scanner.s(/[^[>]+/y);
|
|
513
|
+
if (scanner.s(/\[[\s\S]+?\][\x20\t\r\n]*>/y)) {
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
if (!scanner.b(">")) {
|
|
517
|
+
throw this.a("Unclosed doctype declaration");
|
|
518
|
+
}
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
z() {
|
|
522
|
+
let { c: scanner } = this;
|
|
523
|
+
let mark = scanner.d;
|
|
524
|
+
if (!scanner.b("<")) {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
let name = this.q();
|
|
528
|
+
if (!name) {
|
|
529
|
+
scanner.o(mark);
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
let attributes = this.G();
|
|
533
|
+
let isEmpty = Boolean(scanner.b("/>"));
|
|
534
|
+
let element = new XmlElement(name, attributes);
|
|
535
|
+
element.parent = this.i;
|
|
536
|
+
if (!isEmpty) {
|
|
537
|
+
if (!scanner.b(">")) {
|
|
538
|
+
throw this.a(`Unclosed start tag for element \`${name}\``);
|
|
539
|
+
}
|
|
540
|
+
this.i = element;
|
|
541
|
+
do {
|
|
542
|
+
this.J();
|
|
543
|
+
} while (this.z() || this.K() || this.I() || this.C() || this.B());
|
|
544
|
+
let endTagMark = scanner.d;
|
|
545
|
+
let endTagName;
|
|
546
|
+
if (!scanner.b("</") || !(endTagName = this.q()) || endTagName !== name) {
|
|
547
|
+
scanner.o(endTagMark);
|
|
548
|
+
throw this.a(`Missing end tag for element ${name}`);
|
|
549
|
+
}
|
|
550
|
+
this.e();
|
|
551
|
+
if (!scanner.b(">")) {
|
|
552
|
+
throw this.a(`Unclosed end tag for element ${name}`);
|
|
553
|
+
}
|
|
554
|
+
this.i = element.parent;
|
|
555
|
+
}
|
|
556
|
+
this.k(element);
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
r() {
|
|
560
|
+
this.e();
|
|
561
|
+
if (this.c.b("=")) {
|
|
562
|
+
this.e();
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
u() {
|
|
568
|
+
return this.B() || this.C() || this.e();
|
|
569
|
+
}
|
|
570
|
+
q() {
|
|
571
|
+
return isNameStartChar(this.c.g()) ? this.c.t(isNameChar) : emptyString2;
|
|
572
|
+
}
|
|
573
|
+
C() {
|
|
574
|
+
let { c: scanner } = this;
|
|
575
|
+
let mark = scanner.d;
|
|
576
|
+
if (!scanner.b("<?")) {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
let name = this.q();
|
|
580
|
+
if (name) {
|
|
581
|
+
if (name.toLowerCase() === "xml") {
|
|
582
|
+
scanner.o(mark);
|
|
583
|
+
throw this.a("XML declaration isn't allowed here");
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
throw this.a("Invalid processing instruction");
|
|
587
|
+
}
|
|
588
|
+
if (!this.e()) {
|
|
589
|
+
if (scanner.b("?>")) {
|
|
590
|
+
this.k(new XmlProcessingInstruction(name));
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
throw this.a("Whitespace is required after a processing instruction name");
|
|
594
|
+
}
|
|
595
|
+
let content = scanner.p("?>");
|
|
596
|
+
this.l(content);
|
|
597
|
+
if (!scanner.b("?>")) {
|
|
598
|
+
throw this.a("Unterminated processing instruction");
|
|
599
|
+
}
|
|
600
|
+
this.k(new XmlProcessingInstruction(name, content));
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
F() {
|
|
604
|
+
let { c: scanner } = this;
|
|
605
|
+
let mark = scanner.d;
|
|
606
|
+
this.M();
|
|
607
|
+
while (this.u()) {
|
|
608
|
+
}
|
|
609
|
+
if (this.L()) {
|
|
610
|
+
while (this.u()) {
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return mark < scanner.d;
|
|
614
|
+
}
|
|
615
|
+
A() {
|
|
616
|
+
let { c: scanner } = this;
|
|
617
|
+
if (!scanner.b("&")) {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
let ref = scanner.t(isReferenceChar);
|
|
621
|
+
if (scanner.D() !== ";") {
|
|
622
|
+
throw this.a("Unterminated reference (a reference must end with `;`)");
|
|
623
|
+
}
|
|
624
|
+
let parsedValue;
|
|
625
|
+
if (ref[0] === "#") {
|
|
626
|
+
let codePoint = ref[1] === "x" ? parseInt(ref.slice(2), 16) : parseInt(ref.slice(1), 10);
|
|
627
|
+
if (isNaN(codePoint)) {
|
|
628
|
+
throw this.a("Invalid character reference");
|
|
629
|
+
}
|
|
630
|
+
if (!isXmlCodePoint(codePoint)) {
|
|
631
|
+
throw this.a("Character reference resolves to an invalid character");
|
|
632
|
+
}
|
|
633
|
+
parsedValue = String.fromCodePoint(codePoint);
|
|
634
|
+
} else {
|
|
635
|
+
parsedValue = predefinedEntities[ref];
|
|
636
|
+
if (parsedValue === void 0) {
|
|
637
|
+
let {
|
|
638
|
+
ignoreUndefinedEntities,
|
|
639
|
+
resolveUndefinedEntity
|
|
640
|
+
} = this.options;
|
|
641
|
+
let wrappedRef = `&${ref};`;
|
|
642
|
+
if (resolveUndefinedEntity) {
|
|
643
|
+
let resolvedValue = resolveUndefinedEntity(wrappedRef);
|
|
644
|
+
if (resolvedValue !== null && resolvedValue !== void 0) {
|
|
645
|
+
let type = typeof resolvedValue;
|
|
646
|
+
if (type !== "string") {
|
|
647
|
+
throw new TypeError(`\`resolveUndefinedEntity()\` must return a string, \`null\`, or \`undefined\`, but returned a value of type ${type}`);
|
|
648
|
+
}
|
|
649
|
+
return resolvedValue;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (ignoreUndefinedEntities) {
|
|
653
|
+
return wrappedRef;
|
|
654
|
+
}
|
|
655
|
+
scanner.o(-wrappedRef.length);
|
|
656
|
+
throw this.a(`Named entity isn't defined: ${wrappedRef}`);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return parsedValue;
|
|
660
|
+
}
|
|
661
|
+
w() {
|
|
662
|
+
let { c: scanner } = this;
|
|
663
|
+
let quote = scanner.b('"') || scanner.b("'");
|
|
664
|
+
if (!quote) {
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
let value = scanner.p(quote);
|
|
668
|
+
this.l(value);
|
|
669
|
+
if (!scanner.b(quote)) {
|
|
670
|
+
throw this.a("Missing end quote");
|
|
671
|
+
}
|
|
672
|
+
return value;
|
|
673
|
+
}
|
|
674
|
+
e() {
|
|
675
|
+
return Boolean(this.c.t(isWhitespace));
|
|
676
|
+
}
|
|
677
|
+
M() {
|
|
678
|
+
let { c: scanner } = this;
|
|
679
|
+
if (!scanner.b("<?xml")) {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
if (!this.e()) {
|
|
683
|
+
throw this.a("Invalid XML declaration");
|
|
684
|
+
}
|
|
685
|
+
let version = Boolean(scanner.b("version")) && this.r() && this.w();
|
|
686
|
+
if (version === false) {
|
|
687
|
+
throw this.a("XML version is missing or invalid");
|
|
688
|
+
} else if (!/^1\.[0-9]+$/.test(version)) {
|
|
689
|
+
throw this.a("Invalid character in version number");
|
|
690
|
+
}
|
|
691
|
+
if (this.e()) {
|
|
692
|
+
let encoding = Boolean(scanner.b("encoding")) && this.r() && this.w();
|
|
693
|
+
if (encoding) {
|
|
694
|
+
this.e();
|
|
695
|
+
}
|
|
696
|
+
let standalone = Boolean(scanner.b("standalone")) && this.r() && this.w();
|
|
697
|
+
if (standalone) {
|
|
698
|
+
if (standalone !== "yes" && standalone !== "no") {
|
|
699
|
+
throw this.a('Only "yes" and "no" are permitted as values of `standalone`');
|
|
700
|
+
}
|
|
701
|
+
this.e();
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (!scanner.b("?>")) {
|
|
705
|
+
throw this.a("Invalid or unclosed XML declaration");
|
|
706
|
+
}
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
709
|
+
a(message) {
|
|
710
|
+
let { d: charIndex, string: xml } = this.c;
|
|
711
|
+
let column = 1;
|
|
712
|
+
let excerpt = "";
|
|
713
|
+
let line = 1;
|
|
714
|
+
for (let i = 0; i < charIndex; ++i) {
|
|
715
|
+
let char = xml[i];
|
|
716
|
+
if (char === "\n") {
|
|
717
|
+
column = 1;
|
|
718
|
+
excerpt = "";
|
|
719
|
+
line += 1;
|
|
720
|
+
} else {
|
|
721
|
+
column += 1;
|
|
722
|
+
excerpt += char;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
let eol = xml.indexOf("\n", charIndex);
|
|
726
|
+
excerpt += eol === -1 ? xml.slice(charIndex) : xml.slice(charIndex, eol);
|
|
727
|
+
let excerptStart = 0;
|
|
728
|
+
if (excerpt.length > 50) {
|
|
729
|
+
if (column < 40) {
|
|
730
|
+
excerpt = excerpt.slice(0, 50);
|
|
731
|
+
} else {
|
|
732
|
+
excerptStart = column - 20;
|
|
733
|
+
excerpt = excerpt.slice(excerptStart, column + 30);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
let err = new Error(
|
|
737
|
+
`${message} (line ${line}, column ${column})
|
|
738
|
+
${excerpt}
|
|
739
|
+
` + " ".repeat(column - excerptStart + 1) + "^\n"
|
|
740
|
+
);
|
|
741
|
+
Object.assign(err, {
|
|
742
|
+
column,
|
|
743
|
+
excerpt,
|
|
744
|
+
line,
|
|
745
|
+
pos: charIndex
|
|
746
|
+
});
|
|
747
|
+
return err;
|
|
748
|
+
}
|
|
749
|
+
l(string) {
|
|
750
|
+
let { length } = string;
|
|
751
|
+
for (let i = 0; i < length; ++i) {
|
|
752
|
+
let cp = string.codePointAt(i);
|
|
753
|
+
if (!isXmlCodePoint(cp)) {
|
|
754
|
+
this.c.o(-([...string].length - i));
|
|
755
|
+
throw this.a("Invalid character");
|
|
756
|
+
}
|
|
757
|
+
if (cp > 65535) {
|
|
758
|
+
i += 1;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
function normalizeXmlString(xml) {
|
|
764
|
+
if (xml[0] === "\uFEFF") {
|
|
765
|
+
xml = xml.slice(1);
|
|
766
|
+
}
|
|
767
|
+
return xml.replace(/\r\n?/g, "\n");
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/index.ts
|
|
771
|
+
function parseXml(xml, options) {
|
|
772
|
+
return new Parser(xml, options).document;
|
|
773
|
+
}
|
|
774
|
+
//# sourceMappingURL=browser.js.map
|