@e-mc/document 0.13.10 → 0.14.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/README.md +18 -18
- package/asset.js +4 -2
- package/index.js +221 -189
- package/package.json +5 -5
- package/parse/dom.js +41 -42
- package/parse/index.js +54 -52
- package/transform/index.js +23 -22
- package/util.d.ts +2 -1
- package/util.js +40 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/document",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Document constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
"license": "BSD-3-Clause",
|
|
20
20
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@e-mc/core": "0.
|
|
23
|
-
"@e-mc/db": "0.
|
|
24
|
-
"@e-mc/types": "0.
|
|
22
|
+
"@e-mc/core": "0.14.0",
|
|
23
|
+
"@e-mc/db": "0.14.0",
|
|
24
|
+
"@e-mc/types": "0.14.0",
|
|
25
25
|
"chalk": "4.1.2",
|
|
26
26
|
"domhandler": "^5.0.3",
|
|
27
27
|
"domutils": "^3.2.2",
|
|
28
|
-
"htmlparser2": "^10.
|
|
28
|
+
"htmlparser2": "^10.1.0",
|
|
29
29
|
"js-yaml": "^4.1.1",
|
|
30
30
|
"picomatch": "^4.0.4"
|
|
31
31
|
}
|
package/parse/dom.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const util_1 = require("@e-mc/document/util");
|
|
10
|
-
const Parser = htmlparser2.Parser;
|
|
11
|
-
const DomHandler = domhandler.DomHandler;
|
|
2
|
+
|
|
3
|
+
const { Parser } = require('htmlparser2');
|
|
4
|
+
const { DomHandler } = require('domhandler');
|
|
5
|
+
const { findOne, getElementsByTagName } = require('domutils');
|
|
6
|
+
const { escapePattern } = require('@e-mc/types');
|
|
7
|
+
const { IGNORE_FLAG, XmlElement, XmlWriter } = require('@e-mc/document/parse');
|
|
8
|
+
const { getNewline } = require('@e-mc/document/util');
|
|
12
9
|
const TAG_VOID = ['area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'isindex', 'keygen', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
|
13
|
-
const REGEXP_VOID = TAG_VOID.map(tagName => new RegExp(`(\\s*)</${tagName}\\s*>` +
|
|
14
|
-
const REGEXP_TAGNAME = new RegExp(`^${
|
|
15
|
-
const
|
|
16
|
-
class DomWriter extends
|
|
10
|
+
const REGEXP_VOID = TAG_VOID.map(tagName => new RegExp(`(\\s*)</${tagName}\\s*>` + XmlWriter.PATTERN_TRAILINGSPACE, 'gi'));
|
|
11
|
+
const REGEXP_TAGNAME = new RegExp(`^${XmlWriter.PATTERN_TAGNAME}$`);
|
|
12
|
+
const parserOptions = () => ({ xmlMode: false, decodeEntities: false });
|
|
13
|
+
class DomWriter extends XmlWriter {
|
|
17
14
|
static hasInnerXml(tagName, ignoreCase) {
|
|
18
15
|
if (ignoreCase) {
|
|
19
16
|
tagName = tagName.toLowerCase();
|
|
@@ -26,21 +23,21 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
26
23
|
({ newline, ignoreTagGroup, escapeEntities, ignoreChar = '' } = options);
|
|
27
24
|
}
|
|
28
25
|
for (const tag of REGEXP_VOID) {
|
|
29
|
-
source = source.replace(tag, (...capture) =>
|
|
26
|
+
source = source.replace(tag, (...capture) => XmlWriter.getNewlineString(capture[1], capture[2], newline));
|
|
30
27
|
}
|
|
31
28
|
const tagGroup = [];
|
|
32
29
|
if (ignoreTagGroup) {
|
|
33
30
|
for (let i = 0, length = ignoreTagGroup.length; i < length; i += 2) {
|
|
34
31
|
const start = ignoreTagGroup[i];
|
|
35
32
|
if (start.startsWith('<')) {
|
|
36
|
-
tagGroup.push(new RegExp('^' +
|
|
33
|
+
tagGroup.push(new RegExp('^' + escapePattern(start)));
|
|
37
34
|
}
|
|
38
35
|
if (ignoreTagGroup[i + 1]?.at(-1) === '>') {
|
|
39
|
-
tagGroup.push(new RegExp(
|
|
36
|
+
tagGroup.push(new RegExp(escapePattern(start) + '$'));
|
|
40
37
|
}
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
|
-
const pattern = new RegExp(`<(?:!--.*?--|([^\\s<>/${ignoreChar}]+)(${
|
|
40
|
+
const pattern = new RegExp(`<(?:!--.*?--|([^\\s<>/${ignoreChar}]+)(${XmlWriter.PATTERN_TAGOPEN}*?)(\\s*\\/?\\s*)|\\/([^\\s>]+)(\\s*))>`, 'gs');
|
|
44
41
|
let match;
|
|
45
42
|
while (match = pattern.exec(source)) {
|
|
46
43
|
let tag;
|
|
@@ -50,17 +47,17 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
50
47
|
if (match[1].toUpperCase() === '!DOCTYPE') {
|
|
51
48
|
continue;
|
|
52
49
|
}
|
|
53
|
-
tag = '<!--' + match[1].
|
|
50
|
+
tag = '<!--' + match[1].slice(1) + match[2] + '-->';
|
|
54
51
|
}
|
|
55
52
|
else if (tagGroup.length === 0 || !tagGroup.some(item => item.test(match[0]))) {
|
|
56
|
-
tag =
|
|
53
|
+
tag = XmlWriter.escapeXmlString(match[0]);
|
|
57
54
|
}
|
|
58
55
|
}
|
|
59
56
|
else {
|
|
60
57
|
const trailing = match[match.length - 3];
|
|
61
58
|
if (escapeEntities) {
|
|
62
59
|
const outerTag = '<' + match[1] + match[2] + '>';
|
|
63
|
-
tag =
|
|
60
|
+
tag = XmlWriter.escapeAttributes(outerTag);
|
|
64
61
|
if (!trailing && tag === outerTag) {
|
|
65
62
|
continue;
|
|
66
63
|
}
|
|
@@ -79,7 +76,7 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
79
76
|
}
|
|
80
77
|
}
|
|
81
78
|
if (tag) {
|
|
82
|
-
source = source.
|
|
79
|
+
source = source.slice(0, match.index) + tag + source.slice(match.index + match[0].length);
|
|
83
80
|
pattern.lastIndex += tag.length - match[0].length;
|
|
84
81
|
}
|
|
85
82
|
}
|
|
@@ -89,7 +86,7 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
89
86
|
const result = { element: null, error: null };
|
|
90
87
|
new Parser(new DomHandler((err, dom) => {
|
|
91
88
|
if (!err) {
|
|
92
|
-
result.element =
|
|
89
|
+
result.element = findOne(elem => elem.tagName === "html", dom);
|
|
93
90
|
}
|
|
94
91
|
else {
|
|
95
92
|
result.error = err;
|
|
@@ -98,7 +95,7 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
98
95
|
return result;
|
|
99
96
|
}
|
|
100
97
|
static getElementsByTagName(tagName, nodes, recurse, limit) {
|
|
101
|
-
return
|
|
98
|
+
return getElementsByTagName(tagName, nodes, recurse, limit);
|
|
102
99
|
}
|
|
103
100
|
documentElement = null;
|
|
104
101
|
ignoreTagName = "title|style|script";
|
|
@@ -106,7 +103,7 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
106
103
|
rootName = "html";
|
|
107
104
|
ignoreCaseTagName = true;
|
|
108
105
|
constructor(documentName, source, elements, options = {}) {
|
|
109
|
-
const { normalize, escapeEntities, stripComments, ignoreTagGroup, parser =
|
|
106
|
+
const { normalize, escapeEntities, stripComments, ignoreTagGroup, parser = parserOptions() } = options;
|
|
110
107
|
super(documentName, source, elements, { parser });
|
|
111
108
|
const items = [];
|
|
112
109
|
let outerXml = '', documentElement, offsetMap, startIndex = -1;
|
|
@@ -128,7 +125,7 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
128
125
|
source = DomWriter.normalize(source, { newline: this.newline, ignoreChar: typeof normalize === 'string' ? normalize : '', ignoreTagGroup, escapeEntities });
|
|
129
126
|
}
|
|
130
127
|
else if (escapeEntities) {
|
|
131
|
-
source =
|
|
128
|
+
source = XmlWriter.escapeAttributes(source);
|
|
132
129
|
}
|
|
133
130
|
}
|
|
134
131
|
else {
|
|
@@ -137,10 +134,10 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
137
134
|
const html = /^(\s*(?:<\?xml[^>]+>\s*)?(?:<!DOCTYPE[^>]+>\s*)?)<html[\s>]/i.exec(source) || /^(.*)<html[\s>]/is.exec(source);
|
|
138
135
|
if (html) {
|
|
139
136
|
const index = html[1] ? html[1].length : 0;
|
|
140
|
-
const endIndex =
|
|
137
|
+
const endIndex = XmlWriter.findCloseTag(source, index);
|
|
141
138
|
if (endIndex !== -1) {
|
|
142
139
|
startIndex = index;
|
|
143
|
-
outerXml = source.
|
|
140
|
+
outerXml = source.slice(startIndex, endIndex + 1);
|
|
144
141
|
}
|
|
145
142
|
}
|
|
146
143
|
if (documentElement) {
|
|
@@ -152,11 +149,11 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
152
149
|
leading += outerXml;
|
|
153
150
|
}
|
|
154
151
|
else {
|
|
155
|
-
leading = source.
|
|
152
|
+
leading = source.slice(0, startIndex + outerXml.length);
|
|
156
153
|
}
|
|
157
154
|
source = documentElement.innerXml;
|
|
158
155
|
if (escapeEntities) {
|
|
159
|
-
source =
|
|
156
|
+
source = XmlWriter.escapeAttributes(source);
|
|
160
157
|
}
|
|
161
158
|
source = leading + this.newline + source + this.newline + '</html>';
|
|
162
159
|
this.documentElement = documentElement;
|
|
@@ -167,8 +164,8 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
167
164
|
const match = /<\/body\s*>\s*<\/html\s*>.*$/is.exec(source) || /<\/body\s*>.*$/is.exec(source);
|
|
168
165
|
if (match) {
|
|
169
166
|
const textContent = trailing.reduce((a, b) => a + b.textContent, '');
|
|
170
|
-
offsetMap =
|
|
171
|
-
source = source.
|
|
167
|
+
offsetMap = XmlWriter.getTagOffset(textContent, { ignoreCase: this.ignoreCaseTagName, ignoreTagName: this.ignoreTagName, parser: this.parser });
|
|
168
|
+
source = source.slice(0, match.index) + textContent + source.slice(match.index);
|
|
172
169
|
for (const item of trailing) {
|
|
173
170
|
delete item.textContent;
|
|
174
171
|
}
|
|
@@ -195,8 +192,8 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
195
192
|
let innerXml;
|
|
196
193
|
for (const item of this.elements) {
|
|
197
194
|
if (item.tagName === "html") {
|
|
198
|
-
if (!innerXml &&
|
|
199
|
-
innerXml = this.source.
|
|
195
|
+
if (!innerXml && XmlWriter.isIndex(item.endIndex)) {
|
|
196
|
+
innerXml = this.source.slice(item.endIndex + 1, this.source.length - 7).trim();
|
|
200
197
|
}
|
|
201
198
|
item.innerXml = innerXml;
|
|
202
199
|
}
|
|
@@ -206,7 +203,7 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
206
203
|
}
|
|
207
204
|
close() {
|
|
208
205
|
if (this.documentElement || this._appendCount > 0) {
|
|
209
|
-
this.source = this.source.replace(new RegExp(
|
|
206
|
+
this.source = this.source.replace(new RegExp(XmlWriter.getPatternId(this.nameOfId), 'g'), '');
|
|
210
207
|
}
|
|
211
208
|
return super.close();
|
|
212
209
|
}
|
|
@@ -214,14 +211,13 @@ class DomWriter extends index_1.XmlWriter {
|
|
|
214
211
|
return new HtmlElement(this.documentName, node);
|
|
215
212
|
}
|
|
216
213
|
setNewline(value) {
|
|
217
|
-
this.newline =
|
|
214
|
+
this.newline = getNewline(value);
|
|
218
215
|
}
|
|
219
216
|
}
|
|
220
|
-
|
|
221
|
-
class HtmlElement extends index_1.XmlElement {
|
|
217
|
+
class HtmlElement extends XmlElement {
|
|
222
218
|
_documentType = "HTML";
|
|
223
219
|
constructor(documentName, node, attributes, options = {}) {
|
|
224
|
-
options.parser ||=
|
|
220
|
+
options.parser ||= parserOptions();
|
|
225
221
|
super(documentName, node, attributes, { ...options, tagVoid: TAG_VOID.includes(node.tagName) });
|
|
226
222
|
}
|
|
227
223
|
getTagOffset(source) {
|
|
@@ -236,15 +232,18 @@ class HtmlElement extends index_1.XmlElement {
|
|
|
236
232
|
}
|
|
237
233
|
}
|
|
238
234
|
findIndexOf(source) {
|
|
239
|
-
const { element } =
|
|
235
|
+
const { element } = XmlWriter.findElement(source, this.node, { document: this.documentName, id: this.id, locatorAttr: 'id', parser: this.parser });
|
|
240
236
|
if (element) {
|
|
241
237
|
return { startIndex: element.startIndex, endIndex: element.endIndex };
|
|
242
238
|
}
|
|
243
239
|
}
|
|
244
240
|
get outerXml() {
|
|
245
241
|
const [tagName, items, innerXml] = this.getOuterContent();
|
|
246
|
-
return '<' + tagName + HtmlElement.writeAttributes(items) + '>' + (DomWriter.hasInnerXml(tagName, this.ignoreCase) && tagName !== "html" ? (tagName === 'title' ?
|
|
242
|
+
return '<' + tagName + HtmlElement.writeAttributes(items) + '>' + (DomWriter.hasInnerXml(tagName, this.ignoreCase) && tagName !== "html" ? (tagName === 'title' ? XmlWriter.escapeXmlString(innerXml) : innerXml) + `</${tagName}>` : '');
|
|
247
243
|
}
|
|
248
244
|
}
|
|
245
|
+
XmlWriter.namesOfTagVoid("HTML", TAG_VOID);
|
|
246
|
+
|
|
247
|
+
exports.DomWriter = DomWriter;
|
|
249
248
|
exports.HtmlElement = HtmlElement;
|
|
250
|
-
|
|
249
|
+
exports.IGNORE_FLAG = IGNORE_FLAG;
|
package/parse/index.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
2
|
+
|
|
3
|
+
const { randomUUID } = require('node:crypto');
|
|
4
|
+
const { Parser } = require('htmlparser2');
|
|
5
|
+
const { DomHandler } = require('domhandler');
|
|
6
|
+
const { findAll, getElementsByTagName } = require('domutils');
|
|
7
|
+
const { errorValue, escapePattern, isArray, isObject, isPlainObject } = require('@e-mc/types');
|
|
8
|
+
const Module = require('@e-mc/module');
|
|
9
|
+
const { spliceMatch } = require('@e-mc/document/util');
|
|
10
|
+
exports.IGNORE_FLAG = void 0;
|
|
11
11
|
(function (IGNORE_FLAG) {
|
|
12
12
|
IGNORE_FLAG[IGNORE_FLAG["NONE"] = 0] = "NONE";
|
|
13
13
|
IGNORE_FLAG[IGNORE_FLAG["INTERIOR"] = 1] = "INTERIOR";
|
|
14
14
|
IGNORE_FLAG[IGNORE_FLAG["LOCATOR"] = 2] = "LOCATOR";
|
|
15
|
-
})(IGNORE_FLAG || (exports.IGNORE_FLAG =
|
|
16
|
-
const Parser = htmlparser2.Parser;
|
|
17
|
-
const DomHandler = domhandler.DomHandler;
|
|
15
|
+
})(exports.IGNORE_FLAG || (exports.IGNORE_FLAG = {}));
|
|
18
16
|
const CACHE_TAGNAME = {};
|
|
19
17
|
const CACHE_TAGOFFSET = {};
|
|
20
18
|
const CACHE_TAGVOID = {};
|
|
@@ -104,7 +102,7 @@ function getParserDOM(source, parser) {
|
|
|
104
102
|
}
|
|
105
103
|
const isIndex = (value) => typeof value === 'number' && value >= 0 && value !== Infinity;
|
|
106
104
|
const isCount = (value) => typeof value === 'number' && value > 0 && value !== Infinity;
|
|
107
|
-
const hasId = (id, source, startIndex, endIndex) => source.
|
|
105
|
+
const hasId = (id, source, startIndex, endIndex) => source.slice(startIndex, endIndex).indexOf(id) !== -1;
|
|
108
106
|
const escapeTagName = (value) => value.replace(/[-.]/g, capture => capture === '-' ? '\\x2d' : '\\' + capture);
|
|
109
107
|
class XmlWriter {
|
|
110
108
|
documentName;
|
|
@@ -140,9 +138,9 @@ class XmlWriter {
|
|
|
140
138
|
pattern = content;
|
|
141
139
|
content = '';
|
|
142
140
|
}
|
|
143
|
-
let index = match.index, leading = index > 0 ? source.
|
|
141
|
+
let index = match.index, leading = index > 0 ? source.slice(0, index) : '', trailing = source.slice(index + match[0].length);
|
|
144
142
|
if (options) {
|
|
145
|
-
if (
|
|
143
|
+
if (isPlainObject(options)) {
|
|
146
144
|
if (options.trimLeading) {
|
|
147
145
|
const length = leading.length;
|
|
148
146
|
leading = leading.trimEnd();
|
|
@@ -186,7 +184,7 @@ class XmlWriter {
|
|
|
186
184
|
const value = attribute[2] || attribute[3] || attribute[4];
|
|
187
185
|
const escaped = this.escapeXmlString(value);
|
|
188
186
|
if (value !== escaped) {
|
|
189
|
-
output =
|
|
187
|
+
output = spliceMatch(output, attribute, attribute[1] + `="${escaped}"`, REGEXP_ATTRVALUE);
|
|
190
188
|
modified = true;
|
|
191
189
|
}
|
|
192
190
|
}
|
|
@@ -252,7 +250,7 @@ class XmlWriter {
|
|
|
252
250
|
static findElement(source, node, options = {}) {
|
|
253
251
|
const { document, id, tagCount = node.tagCount, locatorAttr, parser } = options;
|
|
254
252
|
let outDom = options.outDom, error;
|
|
255
|
-
if (!
|
|
253
|
+
if (!isArray(outDom)) {
|
|
256
254
|
({ outDom, error } = getParserDOM(source, parser));
|
|
257
255
|
}
|
|
258
256
|
const result = { element: null, error: null };
|
|
@@ -260,7 +258,7 @@ class XmlWriter {
|
|
|
260
258
|
result.error = error;
|
|
261
259
|
return result;
|
|
262
260
|
}
|
|
263
|
-
const nodes =
|
|
261
|
+
const nodes = getElementsByTagName(node.tagName, outDom, true);
|
|
264
262
|
if (!parser?.xmlMode) {
|
|
265
263
|
nodes.filter(item => item.next && item.next.startIndex <= item.endIndex).forEach(item => {
|
|
266
264
|
for (let i = 0, length = nodes.length; i < length; ++i) {
|
|
@@ -280,7 +278,8 @@ class XmlWriter {
|
|
|
280
278
|
let index = -1;
|
|
281
279
|
if (document && id) {
|
|
282
280
|
const documentId = this.getNameOfId(document);
|
|
283
|
-
|
|
281
|
+
index = nodes.findIndex(elem => elem.attribs[documentId] === id);
|
|
282
|
+
if (index !== -1) {
|
|
284
283
|
result.element = nodes[index];
|
|
285
284
|
}
|
|
286
285
|
}
|
|
@@ -312,28 +311,28 @@ class XmlWriter {
|
|
|
312
311
|
}
|
|
313
312
|
static locateElement(source, locator, attr, options = {}) {
|
|
314
313
|
let { parser, outDom } = options, error;
|
|
315
|
-
if (!
|
|
314
|
+
if (!isArray(outDom)) {
|
|
316
315
|
({ outDom, error } = getParserDOM(source, parser));
|
|
317
316
|
}
|
|
318
317
|
if (error) {
|
|
319
318
|
return { element: null, error };
|
|
320
319
|
}
|
|
321
320
|
const { id, count = 1, index = 0 } = locator;
|
|
322
|
-
const nodes =
|
|
321
|
+
const nodes = findAll(elem => elem.attribs[attr] === id, outDom);
|
|
323
322
|
const element = nodes.length === count && nodes[index] || null;
|
|
324
323
|
return { element, parser, outDom, error: null };
|
|
325
324
|
}
|
|
326
325
|
static getTagOffset(source, replacement, options) {
|
|
327
|
-
if (
|
|
326
|
+
if (isObject(replacement)) {
|
|
328
327
|
options = replacement;
|
|
329
328
|
replacement = undefined;
|
|
330
329
|
}
|
|
331
|
-
|
|
330
|
+
const parser = { xmlMode: true, decodeEntities: false, lowerCaseAttributeNames: false };
|
|
332
331
|
if (options) {
|
|
333
|
-
const {
|
|
332
|
+
const { ignoreTagName, ignoreTagGroup } = options;
|
|
334
333
|
if (ignoreTagName) {
|
|
335
|
-
const flags = ignoreCase ? '
|
|
336
|
-
source = source.replace(CACHE_TAGOFFSET[ignoreTagName + flags] ||= new RegExp(`<(?:${ignoreTagName.split('|').map(value => escapeTagName(value)).join('|')})${this.PATTERN_TAGOPEN}
|
|
334
|
+
const flags = options.ignoreCase ? 'gsi' : 'gs';
|
|
335
|
+
source = source.replace(CACHE_TAGOFFSET[ignoreTagName + flags] ||= new RegExp(`<(?:${ignoreTagName.split('|').map(value => escapeTagName(value)).join('|')})${this.PATTERN_TAGOPEN}*>.*?<\\/\\1\\s*>`, flags), '');
|
|
337
336
|
}
|
|
338
337
|
if (ignoreTagGroup) {
|
|
339
338
|
for (let i = 0, length = ignoreTagGroup.length; i < length; i += 2) {
|
|
@@ -344,15 +343,17 @@ class XmlWriter {
|
|
|
344
343
|
}
|
|
345
344
|
}
|
|
346
345
|
}
|
|
347
|
-
|
|
346
|
+
if (options.parser) {
|
|
347
|
+
Object.assign(parser, options.parser);
|
|
348
|
+
}
|
|
348
349
|
}
|
|
349
350
|
const result = {};
|
|
350
351
|
new Parser({
|
|
351
352
|
onopentag(name) {
|
|
352
353
|
result[name] = (result[name] || 0) + 1;
|
|
353
354
|
}
|
|
354
|
-
},
|
|
355
|
-
if (
|
|
355
|
+
}, parser).end(source);
|
|
356
|
+
if (replacement) {
|
|
356
357
|
const next = this.getTagOffset(replacement, options);
|
|
357
358
|
let modified = false;
|
|
358
359
|
for (const tagName of new Set([...Object.keys(result), ...Object.keys(next)])) {
|
|
@@ -380,7 +381,7 @@ class XmlWriter {
|
|
|
380
381
|
return `data-${document}-id`;
|
|
381
382
|
}
|
|
382
383
|
static getPatternId(name) {
|
|
383
|
-
return CACHE_PATTERNID[name] ||= new RegExp(`\\s${
|
|
384
|
+
return CACHE_PATTERNID[name] ||= new RegExp(`\\s${escapePattern(name)}="([^"]+)"`);
|
|
384
385
|
}
|
|
385
386
|
static getCommentsAndCDATA(source, tagPattern = '', ignoreCase, stripXml) {
|
|
386
387
|
let tagGroup;
|
|
@@ -399,8 +400,8 @@ class XmlWriter {
|
|
|
399
400
|
}
|
|
400
401
|
}
|
|
401
402
|
const result = [];
|
|
402
|
-
const flags = ignoreCase ? '
|
|
403
|
-
let pattern = CACHE_TAGNAME[tagPattern + flags] ||= new RegExp(`<(?:(
|
|
403
|
+
const flags = ignoreCase ? 'gsi' : 'gs';
|
|
404
|
+
let pattern = CACHE_TAGNAME[tagPattern + flags] ||= new RegExp(`<(?:(!--.*?--)|(!\\[CDATA\\[.*?\\]\\])` + (tagPattern ? '|' + `(${tagPattern})${this.PATTERN_TAGOPEN}*` : '') + ')>', flags), match;
|
|
404
405
|
while (match = pattern.exec(source)) {
|
|
405
406
|
if (stripXml) {
|
|
406
407
|
source = this.replaceMatch(match, source, '', { pattern, trimLeading: true });
|
|
@@ -413,7 +414,7 @@ class XmlWriter {
|
|
|
413
414
|
result.push({ type, outerXml: match[0], startIndex, endIndex: endIndex - 1 });
|
|
414
415
|
}
|
|
415
416
|
else if ((endIndex = findCloseIndex(source, match[3], endIndex, ignoreCase)[0]) !== -1) {
|
|
416
|
-
result.push({ type, outerXml: source.
|
|
417
|
+
result.push({ type, outerXml: source.slice(startIndex, endIndex + 1), startIndex, endIndex });
|
|
417
418
|
}
|
|
418
419
|
}
|
|
419
420
|
}
|
|
@@ -505,7 +506,7 @@ class XmlWriter {
|
|
|
505
506
|
}
|
|
506
507
|
}
|
|
507
508
|
getInvalidArea() {
|
|
508
|
-
if ((this._ignoreFlag & IGNORE_FLAG.INTERIOR) === 0 && this._hasInvalidContent) {
|
|
509
|
+
if ((this._ignoreFlag & exports.IGNORE_FLAG.INTERIOR) === 0 && this._hasInvalidContent) {
|
|
509
510
|
const startIndex = this.#writeStartIndex;
|
|
510
511
|
if (isIndex(startIndex) && this._invalidContent && !this._invalidContent.some(item => item.startIndex >= startIndex)) {
|
|
511
512
|
return this._invalidContent;
|
|
@@ -578,7 +579,7 @@ class XmlWriter {
|
|
|
578
579
|
this.elements.splice(index, 1);
|
|
579
580
|
}
|
|
580
581
|
++this.failCount;
|
|
581
|
-
this.errors.push(
|
|
582
|
+
this.errors.push(errorValue(`Unable to ${append.prepend ? 'prepend' : 'append'} element`, append.tagName.toUpperCase() + (isIndex(node.index) ? ' @ ' + node.index : '')));
|
|
582
583
|
}
|
|
583
584
|
return null;
|
|
584
585
|
}
|
|
@@ -646,7 +647,7 @@ class XmlWriter {
|
|
|
646
647
|
element.reset();
|
|
647
648
|
return true;
|
|
648
649
|
}
|
|
649
|
-
if (node.locator && (this._ignoreFlag & IGNORE_FLAG.LOCATOR)) {
|
|
650
|
+
if (node.locator && (this._ignoreFlag & exports.IGNORE_FLAG.LOCATOR)) {
|
|
650
651
|
return true;
|
|
651
652
|
}
|
|
652
653
|
if (error) {
|
|
@@ -950,7 +951,7 @@ class XmlWriter {
|
|
|
950
951
|
}
|
|
951
952
|
}
|
|
952
953
|
else if (value.startsWith('|')) {
|
|
953
|
-
value = value.
|
|
954
|
+
value = value.slice(1);
|
|
954
955
|
}
|
|
955
956
|
this.ignoreTagName = tagName + value;
|
|
956
957
|
this.#patternIgnore = null;
|
|
@@ -973,7 +974,7 @@ class XmlWriter {
|
|
|
973
974
|
({ tagName, tagVoid } = options);
|
|
974
975
|
}
|
|
975
976
|
const source = this.source;
|
|
976
|
-
const match = new RegExp(`<(${tagName && escapeTagName(tagName) || '[^\\s>]+'})${XmlWriter.PATTERN_TAGOPEN}+?${
|
|
977
|
+
const match = new RegExp(`<(${tagName && escapeTagName(tagName) || '[^\\s>]+'})${XmlWriter.PATTERN_TAGOPEN}+?${escapePattern(this.nameOfId)}="${escapePattern(id)}"`, ignoreCase ? 'i' : '').exec(source);
|
|
977
978
|
if (match) {
|
|
978
979
|
tagName ||= match[1];
|
|
979
980
|
const startIndex = match.index;
|
|
@@ -985,7 +986,7 @@ class XmlWriter {
|
|
|
985
986
|
endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
986
987
|
}
|
|
987
988
|
if (endIndex !== -1) {
|
|
988
|
-
return { tagName, id, outerXml: source.
|
|
989
|
+
return { tagName, id, outerXml: source.slice(startIndex, endIndex + 1), startIndex, endIndex, ignoreCase };
|
|
989
990
|
}
|
|
990
991
|
}
|
|
991
992
|
}
|
|
@@ -1008,7 +1009,7 @@ class XmlWriter {
|
|
|
1008
1009
|
if (!tagVoid) {
|
|
1009
1010
|
const [index, closeTag] = findCloseIndex(source, tagName, endIndex + 1, ignoreCase);
|
|
1010
1011
|
if (index !== -1) {
|
|
1011
|
-
outerXml = source.
|
|
1012
|
+
outerXml = source.slice(startIndex, index + 1);
|
|
1012
1013
|
endIndex = index;
|
|
1013
1014
|
}
|
|
1014
1015
|
else if (closeTag > 0) {
|
|
@@ -1025,7 +1026,7 @@ class XmlWriter {
|
|
|
1025
1026
|
return startIndex !== -1 ? this.spliceRawString({ startIndex, endIndex: startIndex + targetXml.length - 1, outerXml }) : '';
|
|
1026
1027
|
}
|
|
1027
1028
|
getRawString(index) {
|
|
1028
|
-
return this.source.
|
|
1029
|
+
return this.source.slice(index.startIndex, index.endIndex + 1);
|
|
1029
1030
|
}
|
|
1030
1031
|
spliceRawString(content, reset = true) {
|
|
1031
1032
|
const { startIndex, endIndex, outerXml } = content;
|
|
@@ -1033,7 +1034,7 @@ class XmlWriter {
|
|
|
1033
1034
|
this.resetPosition(startIndex);
|
|
1034
1035
|
}
|
|
1035
1036
|
++this.modifyCount;
|
|
1036
|
-
return this.source = this.source.
|
|
1037
|
+
return this.source = this.source.slice(0, startIndex) + outerXml + this.source.slice(endIndex + 1);
|
|
1037
1038
|
}
|
|
1038
1039
|
getComments() {
|
|
1039
1040
|
return this._invalidContent ? this._invalidContent.filter(item => item.type === 'comment') : null;
|
|
@@ -1048,7 +1049,7 @@ class XmlWriter {
|
|
|
1048
1049
|
this.resetPosition();
|
|
1049
1050
|
}
|
|
1050
1051
|
get newId() {
|
|
1051
|
-
return
|
|
1052
|
+
return randomUUID();
|
|
1052
1053
|
}
|
|
1053
1054
|
get nameOfId() {
|
|
1054
1055
|
return XmlWriter.getNameOfId(this.documentName);
|
|
@@ -1069,7 +1070,6 @@ class XmlWriter {
|
|
|
1069
1070
|
return this.modifyCount > 0;
|
|
1070
1071
|
}
|
|
1071
1072
|
}
|
|
1072
|
-
exports.XmlWriter = XmlWriter;
|
|
1073
1073
|
class XmlElement {
|
|
1074
1074
|
documentName;
|
|
1075
1075
|
node;
|
|
@@ -1083,7 +1083,7 @@ class XmlElement {
|
|
|
1083
1083
|
if (value === null) {
|
|
1084
1084
|
continue;
|
|
1085
1085
|
}
|
|
1086
|
-
result += '="' + (typeof value === 'string' ? escapeEntities ? XmlWriter.escapeXmlString(value) : value.
|
|
1086
|
+
result += '="' + (typeof value === 'string' ? escapeEntities ? XmlWriter.escapeXmlString(value) : value.replace(/"/g, '"') : Module.asString(value)) + '"';
|
|
1087
1087
|
}
|
|
1088
1088
|
return result;
|
|
1089
1089
|
}
|
|
@@ -1123,7 +1123,7 @@ class XmlElement {
|
|
|
1123
1123
|
if (!attrs.has(key)) {
|
|
1124
1124
|
attrs.set(key, match[2] || match[3] || match[4] || '');
|
|
1125
1125
|
}
|
|
1126
|
-
source =
|
|
1126
|
+
source = spliceMatch(source, match, '', REGEXP_ATTRVALUE);
|
|
1127
1127
|
}
|
|
1128
1128
|
for (const attr of source.matchAll(REGEXP_ATTRNAME)) {
|
|
1129
1129
|
const key = ignoreCase ? attr[1].toLowerCase() : attr[1];
|
|
@@ -1160,10 +1160,10 @@ class XmlElement {
|
|
|
1160
1160
|
}
|
|
1161
1161
|
let lastIndex = -1;
|
|
1162
1162
|
if (tagVoid === true || (lastIndex = value.lastIndexOf('<')) && lastIndex < endIndex) {
|
|
1163
|
-
return [value.
|
|
1163
|
+
return [value.slice(0, endIndex), '', true];
|
|
1164
1164
|
}
|
|
1165
|
-
tagStart = value.
|
|
1166
|
-
innerXml = value.
|
|
1165
|
+
tagStart = value.slice(0, endIndex);
|
|
1166
|
+
innerXml = value.slice(endIndex, lastIndex);
|
|
1167
1167
|
}
|
|
1168
1168
|
}
|
|
1169
1169
|
return [tagStart || `<${this.tagName}>`, innerXml || '', false];
|
|
@@ -1198,7 +1198,7 @@ class XmlElement {
|
|
|
1198
1198
|
if (outerXml) {
|
|
1199
1199
|
const index = XmlWriter.findCloseTag(outerXml);
|
|
1200
1200
|
if (index !== -1) {
|
|
1201
|
-
return XmlWriter.getPatternId(this.nameOfId).exec(outerXml.
|
|
1201
|
+
return XmlWriter.getPatternId(this.nameOfId).exec(outerXml.slice(0, index))?.[1] || '';
|
|
1202
1202
|
}
|
|
1203
1203
|
}
|
|
1204
1204
|
}
|
|
@@ -1279,7 +1279,7 @@ class XmlElement {
|
|
|
1279
1279
|
node.startIndex = startIndex + leading.length;
|
|
1280
1280
|
node.endIndex = node.startIndex + outerXml.length - 1;
|
|
1281
1281
|
}
|
|
1282
|
-
return [source.
|
|
1282
|
+
return [source.slice(0, startIndex) + leading + outerXml + trailing + source.slice(endIndex), outerXml];
|
|
1283
1283
|
}
|
|
1284
1284
|
write(source, invalid) {
|
|
1285
1285
|
if (!this._modified) {
|
|
@@ -1380,7 +1380,7 @@ class XmlElement {
|
|
|
1380
1380
|
}
|
|
1381
1381
|
return this.replace(source, position);
|
|
1382
1382
|
}
|
|
1383
|
-
return ['', '',
|
|
1383
|
+
return ['', '', errorValue('Element was not found', tagName.toUpperCase() + (isIndex(tagIndex) ? ' @ ' + tagIndex : ''))];
|
|
1384
1384
|
}
|
|
1385
1385
|
save(source, invalid) {
|
|
1386
1386
|
const [output, outerXml, error] = this.write(source, invalid || XmlWriter.getCommentsAndCDATA(source));
|
|
@@ -1502,4 +1502,6 @@ class XmlElement {
|
|
|
1502
1502
|
return this._modified;
|
|
1503
1503
|
}
|
|
1504
1504
|
}
|
|
1505
|
+
|
|
1505
1506
|
exports.XmlElement = XmlElement;
|
|
1507
|
+
exports.XmlWriter = XmlWriter;
|