@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/src/index.js
DELETED
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const emptyArray = Object.freeze([]);
|
|
4
|
-
const emptyObject = Object.freeze(Object.create(null));
|
|
5
|
-
|
|
6
|
-
const namedEntities = Object.freeze({
|
|
7
|
-
'&': '&',
|
|
8
|
-
''': "'",
|
|
9
|
-
'>': '>',
|
|
10
|
-
'<': '<',
|
|
11
|
-
'"': '"'
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
const NODE_TYPE_CDATA = 'cdata';
|
|
15
|
-
const NODE_TYPE_COMMENT = 'comment';
|
|
16
|
-
const NODE_TYPE_DOCUMENT = 'document';
|
|
17
|
-
const NODE_TYPE_ELEMENT = 'element';
|
|
18
|
-
const NODE_TYPE_TEXT = 'text';
|
|
19
|
-
|
|
20
|
-
let Syntax;
|
|
21
|
-
|
|
22
|
-
module.exports = function parseXml(xml, options = emptyObject) {
|
|
23
|
-
if (Syntax === void 0) {
|
|
24
|
-
// Lazy require to defer regex parsing until first use.
|
|
25
|
-
Syntax = require('./lib/syntax');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (xml[0] === '\uFEFF') {
|
|
29
|
-
// Strip byte order mark.
|
|
30
|
-
xml = xml.slice(1);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
xml = xml.replace(/\r\n?/g, '\n'); // Normalize CRLF and CR to LF.
|
|
34
|
-
|
|
35
|
-
let doc = {
|
|
36
|
-
type: NODE_TYPE_DOCUMENT,
|
|
37
|
-
children: [],
|
|
38
|
-
parent: null,
|
|
39
|
-
toJSON: nodeToJson
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
let state = {
|
|
43
|
-
length: xml.length,
|
|
44
|
-
options,
|
|
45
|
-
parent: doc,
|
|
46
|
-
pos: 0,
|
|
47
|
-
prevPos: 0,
|
|
48
|
-
xml
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
state.replaceReference = replaceReference.bind(state);
|
|
52
|
-
|
|
53
|
-
consumeProlog(state);
|
|
54
|
-
|
|
55
|
-
if (!consumeElement(state)) {
|
|
56
|
-
error(state, 'Root element is missing or invalid');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
while (consumeMisc(state)) {} // eslint-disable-line no-empty
|
|
60
|
-
|
|
61
|
-
if (!isEof(state)) {
|
|
62
|
-
error(state, `Extra content at the end of the document`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return doc;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// -- Private Functions --------------------------------------------------------
|
|
69
|
-
function addNode(state, node) {
|
|
70
|
-
node.parent = state.parent;
|
|
71
|
-
node.toJSON = nodeToJson;
|
|
72
|
-
|
|
73
|
-
state.parent.children.push(node);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function addText(state, text) {
|
|
77
|
-
let { children } = state.parent;
|
|
78
|
-
let prevNode = children[children.length - 1];
|
|
79
|
-
|
|
80
|
-
if (prevNode !== void 0 && prevNode.type === NODE_TYPE_TEXT) {
|
|
81
|
-
// The previous node is a text node, so we can append to it and avoid
|
|
82
|
-
// creating another node.
|
|
83
|
-
prevNode.text += text;
|
|
84
|
-
} else {
|
|
85
|
-
addNode(state, {
|
|
86
|
-
type: NODE_TYPE_TEXT,
|
|
87
|
-
text
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Each `consume*` function takes the current state as an argument and returns
|
|
93
|
-
// `true` if `state.pos` was advanced (meaning some XML was consumed) or `false`
|
|
94
|
-
// if nothing was consumed.
|
|
95
|
-
|
|
96
|
-
function consumeCDSect(state) {
|
|
97
|
-
let [ match, text ] = scan(state, Syntax.Anchored.CDSect);
|
|
98
|
-
|
|
99
|
-
if (match === void 0) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (state.options.preserveCdata) {
|
|
104
|
-
addNode(state, {
|
|
105
|
-
type: NODE_TYPE_CDATA,
|
|
106
|
-
text
|
|
107
|
-
});
|
|
108
|
-
} else {
|
|
109
|
-
addText(state, text);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function consumeCharData(state) {
|
|
116
|
-
let [ text ] = scan(state, Syntax.Anchored.CharData);
|
|
117
|
-
|
|
118
|
-
if (text === void 0) {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
let cdataCloseIndex = text.indexOf(']]>');
|
|
123
|
-
|
|
124
|
-
if (cdataCloseIndex !== -1) {
|
|
125
|
-
state.pos = state.prevPos + cdataCloseIndex;
|
|
126
|
-
error(state, 'Element content may not contain the CDATA section close delimiter `]]>`');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Note: XML 1.0 5th ed. says `CharData` is "any string of characters which
|
|
130
|
-
// does not contain the start-delimiter of any markup and does not include the
|
|
131
|
-
// CDATA-section-close delimiter", but the conformance test suite and
|
|
132
|
-
// well-established parsers like libxml seem to restrict `CharData` to
|
|
133
|
-
// characters that match the `Char` symbol, so that's what I've done here.
|
|
134
|
-
if (!Syntax.CharOnly.test(text)) {
|
|
135
|
-
state.pos = state.prevPos + text.search(new RegExp(`(?!${Syntax.Char.source})`));
|
|
136
|
-
error(state, 'Element content contains an invalid character');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
addText(state, text);
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function consumeComment(state) {
|
|
144
|
-
let [ , content ] = scan(state, Syntax.Anchored.Comment);
|
|
145
|
-
|
|
146
|
-
if (content === void 0) {
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (state.options.preserveComments) {
|
|
151
|
-
addNode(state, {
|
|
152
|
-
type: NODE_TYPE_COMMENT,
|
|
153
|
-
content: content.trim()
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function consumeDoctypeDecl(state) {
|
|
161
|
-
return scan(state, Syntax.Anchored.doctypedecl).length > 0;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function consumeElement(state) {
|
|
165
|
-
let [ tag, name, attrs ] = scan(state, Syntax.Anchored.EmptyElemTag);
|
|
166
|
-
let isEmpty = tag !== void 0;
|
|
167
|
-
|
|
168
|
-
if (!isEmpty) {
|
|
169
|
-
[ tag, name, attrs ] = scan(state, Syntax.Anchored.STag);
|
|
170
|
-
|
|
171
|
-
if (tag === void 0) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
let { parent } = state;
|
|
177
|
-
let parsedAttrs = parseAttrs(state, attrs);
|
|
178
|
-
|
|
179
|
-
let node = {
|
|
180
|
-
type: NODE_TYPE_ELEMENT,
|
|
181
|
-
name,
|
|
182
|
-
attributes: parsedAttrs,
|
|
183
|
-
children: []
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
let xmlSpace = parsedAttrs['xml:space'];
|
|
187
|
-
|
|
188
|
-
if (xmlSpace === 'preserve'
|
|
189
|
-
|| (xmlSpace !== 'default' && parent.preserveWhitespace)) {
|
|
190
|
-
|
|
191
|
-
node.preserveWhitespace = true;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (!isEmpty) {
|
|
195
|
-
state.parent = node;
|
|
196
|
-
|
|
197
|
-
consumeCharData(state);
|
|
198
|
-
|
|
199
|
-
while (
|
|
200
|
-
consumeElement(state)
|
|
201
|
-
|| consumeReference(state)
|
|
202
|
-
|| consumeCDSect(state)
|
|
203
|
-
|| consumePI(state)
|
|
204
|
-
|| consumeComment(state)
|
|
205
|
-
) {
|
|
206
|
-
consumeCharData(state);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let [ , endName ] = scan(state, Syntax.Anchored.ETag);
|
|
210
|
-
|
|
211
|
-
if (endName !== name) {
|
|
212
|
-
state.pos = state.prevPos;
|
|
213
|
-
error(state, `Missing end tag for element ${name}`);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
state.parent = parent;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
addNode(state, node);
|
|
220
|
-
return true;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function consumeMisc(state) {
|
|
224
|
-
return consumeComment(state)
|
|
225
|
-
|| consumePI(state)
|
|
226
|
-
|| consumeWhitespace(state);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function consumePI(state) {
|
|
230
|
-
let [ match, target ] = scan(state, Syntax.Anchored.PI);
|
|
231
|
-
|
|
232
|
-
if (match === void 0) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (target.toLowerCase() === 'xml') {
|
|
237
|
-
state.pos = state.prevPos;
|
|
238
|
-
error(state, 'XML declaration is only allowed at the start of the document');
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return true;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function consumeProlog(state) {
|
|
245
|
-
let { pos } = state;
|
|
246
|
-
|
|
247
|
-
scan(state, Syntax.Anchored.XMLDecl);
|
|
248
|
-
|
|
249
|
-
while (consumeMisc(state)) {} // eslint-disable-line no-empty
|
|
250
|
-
|
|
251
|
-
if (consumeDoctypeDecl(state)) {
|
|
252
|
-
while (consumeMisc(state)) {} // eslint-disable-line no-empty
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return state.pos > pos;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function consumeReference(state) {
|
|
259
|
-
let [ ref ] = scan(state, Syntax.Anchored.Reference);
|
|
260
|
-
|
|
261
|
-
if (ref === void 0) {
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
addText(state, state.replaceReference(ref));
|
|
266
|
-
return true;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function consumeWhitespace(state) {
|
|
270
|
-
return scan(state, Syntax.Anchored.S).length > 0;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function error(state, message) {
|
|
274
|
-
let { pos, xml } = state;
|
|
275
|
-
let column = 1;
|
|
276
|
-
let excerpt = '';
|
|
277
|
-
let line = 1;
|
|
278
|
-
|
|
279
|
-
// Find the line and column where the error occurred.
|
|
280
|
-
for (let i = 0; i < pos; ++i) {
|
|
281
|
-
let char = xml[i];
|
|
282
|
-
|
|
283
|
-
if (char === '\n') {
|
|
284
|
-
column = 1;
|
|
285
|
-
excerpt = '';
|
|
286
|
-
line += 1;
|
|
287
|
-
} else {
|
|
288
|
-
column += 1;
|
|
289
|
-
excerpt += char;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
let eol = xml.indexOf('\n', pos);
|
|
294
|
-
|
|
295
|
-
excerpt += eol === -1
|
|
296
|
-
? xml.slice(pos)
|
|
297
|
-
: xml.slice(pos, eol);
|
|
298
|
-
|
|
299
|
-
let excerptStart = 0;
|
|
300
|
-
|
|
301
|
-
// Keep the excerpt below 50 chars, but always keep the error position in
|
|
302
|
-
// view.
|
|
303
|
-
if (excerpt.length > 50) {
|
|
304
|
-
if (column < 40) {
|
|
305
|
-
excerpt = excerpt.slice(0, 50);
|
|
306
|
-
} else {
|
|
307
|
-
excerptStart = column - 20;
|
|
308
|
-
excerpt = excerpt.slice(excerptStart, column + 30);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
let err = new Error(
|
|
313
|
-
`${message} (line ${line}, column ${column})\n`
|
|
314
|
-
+ ` ${excerpt}\n`
|
|
315
|
-
+ ' '.repeat(column - excerptStart + 1) + '^\n'
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
err.column = column;
|
|
319
|
-
err.excerpt = excerpt;
|
|
320
|
-
err.line = line;
|
|
321
|
-
err.pos = pos;
|
|
322
|
-
|
|
323
|
-
throw err;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function isEof(state) {
|
|
327
|
-
return state.pos >= state.length - 1;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
function nodeToJson() {
|
|
331
|
-
let json = Object.assign(Object.create(null), this); // eslint-disable-line no-invalid-this
|
|
332
|
-
delete json.parent;
|
|
333
|
-
return json;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function normalizeAttrValue(state, value) {
|
|
337
|
-
return value
|
|
338
|
-
.replace(/[\x20\t\r\n]/g, ' ')
|
|
339
|
-
.replace(Syntax.Global.Reference, state.replaceReference);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function parseAttrs(state, attrs) {
|
|
343
|
-
let parsedAttrs = Object.create(null);
|
|
344
|
-
|
|
345
|
-
if (!attrs) {
|
|
346
|
-
return parsedAttrs;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
let attrPairs = attrs
|
|
350
|
-
.match(Syntax.Global.Attribute)
|
|
351
|
-
.sort();
|
|
352
|
-
|
|
353
|
-
for (let i = 0, len = attrPairs.length; i < len; ++i) {
|
|
354
|
-
let attrPair = attrPairs[i];
|
|
355
|
-
let eqMatch = attrPair.match(Syntax.Eq);
|
|
356
|
-
let name = attrPair.slice(0, eqMatch.index);
|
|
357
|
-
let value = attrPair.slice(eqMatch.index + eqMatch[0].length);
|
|
358
|
-
|
|
359
|
-
if (name in parsedAttrs) {
|
|
360
|
-
state.pos = state.prevPos;
|
|
361
|
-
error(state, `Attribute \`${name}\` redefined`);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
value = normalizeAttrValue(state, value.slice(1, -1));
|
|
365
|
-
|
|
366
|
-
if (name === 'xml:space') {
|
|
367
|
-
if (value !== 'default' && value !== 'preserve') {
|
|
368
|
-
state.pos = state.prevPos;
|
|
369
|
-
error(state, `Value of the \`xml:space\` attribute must be "default" or "preserve"`);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
parsedAttrs[name] = value;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return parsedAttrs;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function replaceReference(ref) {
|
|
380
|
-
let state = this; // eslint-disable-line no-invalid-this
|
|
381
|
-
|
|
382
|
-
if (ref[ref.length - 1] !== ';') {
|
|
383
|
-
error(state, `Invalid reference: \`${ref}\``);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (ref[1] === '#') {
|
|
387
|
-
// This is a character entity.
|
|
388
|
-
let codePoint;
|
|
389
|
-
|
|
390
|
-
if (ref[2] === 'x') {
|
|
391
|
-
codePoint = parseInt(ref.slice(3, -1), 16);
|
|
392
|
-
} else {
|
|
393
|
-
codePoint = parseInt(ref.slice(2, -1), 10);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (isNaN(codePoint)) {
|
|
397
|
-
state.pos = state.prevPos;
|
|
398
|
-
error(state, `Invalid character entity \`${ref}\``);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
let char = String.fromCodePoint(codePoint);
|
|
402
|
-
|
|
403
|
-
if (!Syntax.Char.test(char)) {
|
|
404
|
-
state.pos = state.prevPos;
|
|
405
|
-
error(state, `Invalid character entity \`${ref}\``);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return char;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// This is a named entity.
|
|
412
|
-
let value = namedEntities[ref];
|
|
413
|
-
|
|
414
|
-
if (value !== void 0) {
|
|
415
|
-
return value;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (state.options.resolveUndefinedEntity) {
|
|
419
|
-
let resolvedValue = state.options.resolveUndefinedEntity(ref);
|
|
420
|
-
|
|
421
|
-
if (resolvedValue !== null && resolvedValue !== void 0) {
|
|
422
|
-
return resolvedValue;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (state.options.ignoreUndefinedEntities) {
|
|
427
|
-
return ref;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
state.pos = state.prevPos;
|
|
431
|
-
error(state, `Named entity isn't defined: \`${ref}\``);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function scan(state, regex) {
|
|
435
|
-
let { pos, xml } = state;
|
|
436
|
-
|
|
437
|
-
let xmlToScan = pos > 0
|
|
438
|
-
? xml.slice(pos)
|
|
439
|
-
: xml;
|
|
440
|
-
|
|
441
|
-
let matches = xmlToScan.match(regex);
|
|
442
|
-
|
|
443
|
-
if (matches === null) {
|
|
444
|
-
return emptyArray;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
state.prevPos = state.pos;
|
|
448
|
-
state.pos += matches[0].length;
|
|
449
|
-
|
|
450
|
-
return matches;
|
|
451
|
-
}
|
package/src/lib/syntax.js
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// To improve readability, the regular expression patterns in this file are
|
|
4
|
-
// written as tagged template literals. The `regex` tag function strips literal
|
|
5
|
-
// whitespace characters and line comments beginning with `//` and returns a
|
|
6
|
-
// RegExp instance.
|
|
7
|
-
//
|
|
8
|
-
// Escape sequences are preserved as-is in the resulting regex, so
|
|
9
|
-
// double-escaping isn't necessary. A pattern may embed another pattern using
|
|
10
|
-
// `${}` interpolation.
|
|
11
|
-
|
|
12
|
-
// -- Common Symbols -----------------------------------------------------------
|
|
13
|
-
exports.Char = regex`
|
|
14
|
-
(?:
|
|
15
|
-
[
|
|
16
|
-
\t
|
|
17
|
-
\n
|
|
18
|
-
\r
|
|
19
|
-
\x20-\uD7FF
|
|
20
|
-
\uE000-\uFFFD
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
|
|
|
24
|
-
|
|
25
|
-
[\uD800-\uDBFF][\uDC00-\uDFFF]
|
|
26
|
-
)
|
|
27
|
-
`;
|
|
28
|
-
|
|
29
|
-
// Partial implementation.
|
|
30
|
-
//
|
|
31
|
-
// To be compliant, the matched text must result in an error if it contains the
|
|
32
|
-
// string `]]>`, but that can't be easily represented here so we do it in the
|
|
33
|
-
// parser.
|
|
34
|
-
exports.CharData = regex`
|
|
35
|
-
[^<&]+
|
|
36
|
-
`;
|
|
37
|
-
|
|
38
|
-
exports.NameStartChar = regex`
|
|
39
|
-
(?:
|
|
40
|
-
[
|
|
41
|
-
:
|
|
42
|
-
A-Z
|
|
43
|
-
_
|
|
44
|
-
a-z
|
|
45
|
-
\xC0-\xD6
|
|
46
|
-
\xD8-\xF6
|
|
47
|
-
\xF8-\u02FF
|
|
48
|
-
\u0370-\u037D
|
|
49
|
-
\u037F-\u1FFF
|
|
50
|
-
\u200C-\u200D
|
|
51
|
-
\u2070-\u218F
|
|
52
|
-
\u2C00-\u2FEF
|
|
53
|
-
\u3001-\uD7FF
|
|
54
|
-
\uF900-\uFDCF
|
|
55
|
-
\uFDF0-\uFFFD
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
|
|
|
59
|
-
|
|
60
|
-
[\uD800-\uDB7F][\uDC00-\uDFFF]
|
|
61
|
-
)
|
|
62
|
-
`;
|
|
63
|
-
|
|
64
|
-
exports.NameChar = regex`
|
|
65
|
-
(?:
|
|
66
|
-
${exports.NameStartChar}
|
|
67
|
-
|
|
68
|
-
|
|
|
69
|
-
|
|
70
|
-
[
|
|
71
|
-
.
|
|
72
|
-
0-9
|
|
73
|
-
\xB7
|
|
74
|
-
\u0300-\u036F
|
|
75
|
-
\u203F-\u2040
|
|
76
|
-
-
|
|
77
|
-
]
|
|
78
|
-
)
|
|
79
|
-
`;
|
|
80
|
-
|
|
81
|
-
exports.Name = regex`
|
|
82
|
-
${exports.NameStartChar}
|
|
83
|
-
(?:${exports.NameChar})*
|
|
84
|
-
`;
|
|
85
|
-
|
|
86
|
-
// Loose implementation. The entity will be validated in the `replaceReference`
|
|
87
|
-
// function.
|
|
88
|
-
exports.Reference = regex`
|
|
89
|
-
&[^\s&;]*;?
|
|
90
|
-
`;
|
|
91
|
-
|
|
92
|
-
exports.S = regex`
|
|
93
|
-
[\x20\t\r\n]+
|
|
94
|
-
`;
|
|
95
|
-
|
|
96
|
-
// -- Attributes ---------------------------------------------------------------
|
|
97
|
-
exports.Eq = regex`
|
|
98
|
-
(?:${exports.S})?
|
|
99
|
-
=
|
|
100
|
-
(?:${exports.S})?
|
|
101
|
-
`;
|
|
102
|
-
|
|
103
|
-
exports.Attribute = regex`
|
|
104
|
-
${exports.Name}
|
|
105
|
-
${exports.Eq}
|
|
106
|
-
|
|
107
|
-
(?:
|
|
108
|
-
"(?:
|
|
109
|
-
[^<"]
|
|
110
|
-
)*"
|
|
111
|
-
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
'(?:
|
|
115
|
-
[^<']
|
|
116
|
-
)*'
|
|
117
|
-
)
|
|
118
|
-
`;
|
|
119
|
-
|
|
120
|
-
// -- Elements -----------------------------------------------------------------
|
|
121
|
-
exports.CDSect = regex`
|
|
122
|
-
<!\[CDATA\[
|
|
123
|
-
// Group 1: CData text content (optional)
|
|
124
|
-
(
|
|
125
|
-
(?:${exports.Char})*?
|
|
126
|
-
)
|
|
127
|
-
\]\]>
|
|
128
|
-
`;
|
|
129
|
-
|
|
130
|
-
exports.EmptyElemTag = regex`
|
|
131
|
-
<
|
|
132
|
-
// Group 1: Element name
|
|
133
|
-
(${exports.Name})
|
|
134
|
-
|
|
135
|
-
// Group 2: Attributes (optional)
|
|
136
|
-
(
|
|
137
|
-
(?:
|
|
138
|
-
${exports.S}
|
|
139
|
-
${exports.Attribute}
|
|
140
|
-
)*
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
(?:${exports.S})?
|
|
144
|
-
/>
|
|
145
|
-
`;
|
|
146
|
-
|
|
147
|
-
exports.ETag = regex`
|
|
148
|
-
</
|
|
149
|
-
// Group 1: End tag name
|
|
150
|
-
(${exports.Name})
|
|
151
|
-
(?:${exports.S})?
|
|
152
|
-
>
|
|
153
|
-
`;
|
|
154
|
-
|
|
155
|
-
exports.STag = regex`
|
|
156
|
-
<
|
|
157
|
-
// Group 1: Start tag name
|
|
158
|
-
(${exports.Name})
|
|
159
|
-
|
|
160
|
-
// Group 2: Attributes (optional)
|
|
161
|
-
(
|
|
162
|
-
(?:
|
|
163
|
-
${exports.S}
|
|
164
|
-
${exports.Attribute}
|
|
165
|
-
)*
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
(?:${exports.S})?
|
|
169
|
-
>
|
|
170
|
-
`;
|
|
171
|
-
|
|
172
|
-
// -- Misc ---------------------------------------------------------------------
|
|
173
|
-
|
|
174
|
-
// Special pattern that matches an entire string consisting only of `Char`
|
|
175
|
-
// characters.
|
|
176
|
-
exports.CharOnly = regex`
|
|
177
|
-
^(?:${exports.Char})*$
|
|
178
|
-
`;
|
|
179
|
-
|
|
180
|
-
exports.Comment = regex`
|
|
181
|
-
<!--
|
|
182
|
-
// Group 1: Comment text (optional)
|
|
183
|
-
(
|
|
184
|
-
(?:
|
|
185
|
-
(?!-) ${exports.Char}
|
|
186
|
-
| - (?!-) ${exports.Char}
|
|
187
|
-
)*
|
|
188
|
-
)
|
|
189
|
-
-->
|
|
190
|
-
`;
|
|
191
|
-
|
|
192
|
-
// Loose implementation since doctype declarations are discarded.
|
|
193
|
-
//
|
|
194
|
-
// It's not possible to fully parse a doctype declaration with a regex, but
|
|
195
|
-
// since we just discard them we can skip parsing the fiddly inner bits and use
|
|
196
|
-
// a regex to speed things up.
|
|
197
|
-
exports.doctypedecl = regex`
|
|
198
|
-
<!DOCTYPE
|
|
199
|
-
${exports.S}
|
|
200
|
-
|
|
201
|
-
[^[>]*
|
|
202
|
-
|
|
203
|
-
(?:
|
|
204
|
-
\[ [\s\S]+? \]
|
|
205
|
-
(?:${exports.S})?
|
|
206
|
-
)?
|
|
207
|
-
>
|
|
208
|
-
`;
|
|
209
|
-
|
|
210
|
-
// Loose implementation since processing instructions are discarded.
|
|
211
|
-
exports.PI = regex`
|
|
212
|
-
<\?
|
|
213
|
-
// Group 1: PITarget
|
|
214
|
-
(
|
|
215
|
-
${exports.Name}
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
(?:
|
|
219
|
-
${exports.S}
|
|
220
|
-
(?:${exports.Char})*?
|
|
221
|
-
)?
|
|
222
|
-
\?>
|
|
223
|
-
`;
|
|
224
|
-
|
|
225
|
-
// Loose implementation since XML declarations are discarded.
|
|
226
|
-
exports.XMLDecl = regex`
|
|
227
|
-
<\?xml
|
|
228
|
-
${exports.S}
|
|
229
|
-
[\s\S]+?
|
|
230
|
-
\?>
|
|
231
|
-
`;
|
|
232
|
-
|
|
233
|
-
// -- Helpers ------------------------------------------------------------------
|
|
234
|
-
exports.Anchored = {};
|
|
235
|
-
exports.Global = {};
|
|
236
|
-
|
|
237
|
-
// Create anchored and global variations of each pattern.
|
|
238
|
-
Object.keys(exports).forEach(name => {
|
|
239
|
-
if (name !== 'Anchored' && name !== 'CharOnly' && name !== 'Global') {
|
|
240
|
-
let pattern = exports[name];
|
|
241
|
-
|
|
242
|
-
exports.Anchored[name] = new RegExp('^' + pattern.source);
|
|
243
|
-
exports.Global[name] = new RegExp(pattern.source, 'g');
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
function regex(strings, ...embeddedPatterns) {
|
|
248
|
-
let { length, raw } = strings;
|
|
249
|
-
let lastIndex = length - 1;
|
|
250
|
-
let pattern = '';
|
|
251
|
-
|
|
252
|
-
for (let i = 0; i < length; ++i) {
|
|
253
|
-
pattern += raw[i]
|
|
254
|
-
.replace(/(^|[^\\])\/\/.*$/gm, '$1') // remove end-of-line comments
|
|
255
|
-
.replace(/\s+/g, ''); // remove all whitespace
|
|
256
|
-
|
|
257
|
-
if (i < lastIndex) {
|
|
258
|
-
pattern += embeddedPatterns[i].source;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return new RegExp(pattern);
|
|
263
|
-
}
|