@e-mc/document 0.13.9 → 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 +223 -189
- package/package.json +6 -6
- package/parse/dom.js +41 -42
- package/parse/index.js +59 -57
- 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,14 +19,14 @@
|
|
|
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
|
-
"picomatch": "^4.0.
|
|
30
|
+
"picomatch": "^4.0.4"
|
|
31
31
|
}
|
|
32
32
|
}
|
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();
|
|
@@ -179,13 +177,14 @@ class XmlWriter {
|
|
|
179
177
|
});
|
|
180
178
|
}
|
|
181
179
|
static escapeAttributes(source) {
|
|
182
|
-
let
|
|
180
|
+
let match, attribute;
|
|
183
181
|
while (match = REGEXP_TAGATTR.exec(source)) {
|
|
184
182
|
let output = match[0], modified = false;
|
|
185
|
-
while (attribute = REGEXP_ATTRVALUE.exec(
|
|
183
|
+
while (attribute = REGEXP_ATTRVALUE.exec(output)) {
|
|
186
184
|
const value = attribute[2] || attribute[3] || attribute[4];
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
const escaped = this.escapeXmlString(value);
|
|
186
|
+
if (value !== escaped) {
|
|
187
|
+
output = spliceMatch(output, attribute, attribute[1] + `="${escaped}"`, REGEXP_ATTRVALUE);
|
|
189
188
|
modified = true;
|
|
190
189
|
}
|
|
191
190
|
}
|
|
@@ -251,7 +250,7 @@ class XmlWriter {
|
|
|
251
250
|
static findElement(source, node, options = {}) {
|
|
252
251
|
const { document, id, tagCount = node.tagCount, locatorAttr, parser } = options;
|
|
253
252
|
let outDom = options.outDom, error;
|
|
254
|
-
if (!
|
|
253
|
+
if (!isArray(outDom)) {
|
|
255
254
|
({ outDom, error } = getParserDOM(source, parser));
|
|
256
255
|
}
|
|
257
256
|
const result = { element: null, error: null };
|
|
@@ -259,7 +258,7 @@ class XmlWriter {
|
|
|
259
258
|
result.error = error;
|
|
260
259
|
return result;
|
|
261
260
|
}
|
|
262
|
-
const nodes =
|
|
261
|
+
const nodes = getElementsByTagName(node.tagName, outDom, true);
|
|
263
262
|
if (!parser?.xmlMode) {
|
|
264
263
|
nodes.filter(item => item.next && item.next.startIndex <= item.endIndex).forEach(item => {
|
|
265
264
|
for (let i = 0, length = nodes.length; i < length; ++i) {
|
|
@@ -279,7 +278,8 @@ class XmlWriter {
|
|
|
279
278
|
let index = -1;
|
|
280
279
|
if (document && id) {
|
|
281
280
|
const documentId = this.getNameOfId(document);
|
|
282
|
-
|
|
281
|
+
index = nodes.findIndex(elem => elem.attribs[documentId] === id);
|
|
282
|
+
if (index !== -1) {
|
|
283
283
|
result.element = nodes[index];
|
|
284
284
|
}
|
|
285
285
|
}
|
|
@@ -311,28 +311,28 @@ class XmlWriter {
|
|
|
311
311
|
}
|
|
312
312
|
static locateElement(source, locator, attr, options = {}) {
|
|
313
313
|
let { parser, outDom } = options, error;
|
|
314
|
-
if (!
|
|
314
|
+
if (!isArray(outDom)) {
|
|
315
315
|
({ outDom, error } = getParserDOM(source, parser));
|
|
316
316
|
}
|
|
317
317
|
if (error) {
|
|
318
318
|
return { element: null, error };
|
|
319
319
|
}
|
|
320
320
|
const { id, count = 1, index = 0 } = locator;
|
|
321
|
-
const nodes =
|
|
321
|
+
const nodes = findAll(elem => elem.attribs[attr] === id, outDom);
|
|
322
322
|
const element = nodes.length === count && nodes[index] || null;
|
|
323
323
|
return { element, parser, outDom, error: null };
|
|
324
324
|
}
|
|
325
325
|
static getTagOffset(source, replacement, options) {
|
|
326
|
-
if (
|
|
326
|
+
if (isObject(replacement)) {
|
|
327
327
|
options = replacement;
|
|
328
328
|
replacement = undefined;
|
|
329
329
|
}
|
|
330
|
-
|
|
330
|
+
const parser = { xmlMode: true, decodeEntities: false, lowerCaseAttributeNames: false };
|
|
331
331
|
if (options) {
|
|
332
|
-
const {
|
|
332
|
+
const { ignoreTagName, ignoreTagGroup } = options;
|
|
333
333
|
if (ignoreTagName) {
|
|
334
|
-
const flags = ignoreCase ? '
|
|
335
|
-
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), '');
|
|
336
336
|
}
|
|
337
337
|
if (ignoreTagGroup) {
|
|
338
338
|
for (let i = 0, length = ignoreTagGroup.length; i < length; i += 2) {
|
|
@@ -343,15 +343,17 @@ class XmlWriter {
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
|
-
|
|
346
|
+
if (options.parser) {
|
|
347
|
+
Object.assign(parser, options.parser);
|
|
348
|
+
}
|
|
347
349
|
}
|
|
348
350
|
const result = {};
|
|
349
351
|
new Parser({
|
|
350
352
|
onopentag(name) {
|
|
351
353
|
result[name] = (result[name] || 0) + 1;
|
|
352
354
|
}
|
|
353
|
-
},
|
|
354
|
-
if (
|
|
355
|
+
}, parser).end(source);
|
|
356
|
+
if (replacement) {
|
|
355
357
|
const next = this.getTagOffset(replacement, options);
|
|
356
358
|
let modified = false;
|
|
357
359
|
for (const tagName of new Set([...Object.keys(result), ...Object.keys(next)])) {
|
|
@@ -379,7 +381,7 @@ class XmlWriter {
|
|
|
379
381
|
return `data-${document}-id`;
|
|
380
382
|
}
|
|
381
383
|
static getPatternId(name) {
|
|
382
|
-
return CACHE_PATTERNID[name] ||= new RegExp(`\\s${
|
|
384
|
+
return CACHE_PATTERNID[name] ||= new RegExp(`\\s${escapePattern(name)}="([^"]+)"`);
|
|
383
385
|
}
|
|
384
386
|
static getCommentsAndCDATA(source, tagPattern = '', ignoreCase, stripXml) {
|
|
385
387
|
let tagGroup;
|
|
@@ -398,9 +400,8 @@ class XmlWriter {
|
|
|
398
400
|
}
|
|
399
401
|
}
|
|
400
402
|
const result = [];
|
|
401
|
-
const flags = ignoreCase ? '
|
|
402
|
-
let pattern = CACHE_TAGNAME[tagPattern + flags] ||= new RegExp(`<(?:(
|
|
403
|
-
pattern.lastIndex = 0;
|
|
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,10 +414,11 @@ 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
|
}
|
|
421
|
+
pattern.lastIndex = 0;
|
|
420
422
|
if (stripXml) {
|
|
421
423
|
return source;
|
|
422
424
|
}
|
|
@@ -504,7 +506,7 @@ class XmlWriter {
|
|
|
504
506
|
}
|
|
505
507
|
}
|
|
506
508
|
getInvalidArea() {
|
|
507
|
-
if ((this._ignoreFlag & IGNORE_FLAG.INTERIOR) === 0 && this._hasInvalidContent) {
|
|
509
|
+
if ((this._ignoreFlag & exports.IGNORE_FLAG.INTERIOR) === 0 && this._hasInvalidContent) {
|
|
508
510
|
const startIndex = this.#writeStartIndex;
|
|
509
511
|
if (isIndex(startIndex) && this._invalidContent && !this._invalidContent.some(item => item.startIndex >= startIndex)) {
|
|
510
512
|
return this._invalidContent;
|
|
@@ -577,7 +579,7 @@ class XmlWriter {
|
|
|
577
579
|
this.elements.splice(index, 1);
|
|
578
580
|
}
|
|
579
581
|
++this.failCount;
|
|
580
|
-
this.errors.push(
|
|
582
|
+
this.errors.push(errorValue(`Unable to ${append.prepend ? 'prepend' : 'append'} element`, append.tagName.toUpperCase() + (isIndex(node.index) ? ' @ ' + node.index : '')));
|
|
581
583
|
}
|
|
582
584
|
return null;
|
|
583
585
|
}
|
|
@@ -645,7 +647,7 @@ class XmlWriter {
|
|
|
645
647
|
element.reset();
|
|
646
648
|
return true;
|
|
647
649
|
}
|
|
648
|
-
if (node.locator && (this._ignoreFlag & IGNORE_FLAG.LOCATOR)) {
|
|
650
|
+
if (node.locator && (this._ignoreFlag & exports.IGNORE_FLAG.LOCATOR)) {
|
|
649
651
|
return true;
|
|
650
652
|
}
|
|
651
653
|
if (error) {
|
|
@@ -949,7 +951,7 @@ class XmlWriter {
|
|
|
949
951
|
}
|
|
950
952
|
}
|
|
951
953
|
else if (value.startsWith('|')) {
|
|
952
|
-
value = value.
|
|
954
|
+
value = value.slice(1);
|
|
953
955
|
}
|
|
954
956
|
this.ignoreTagName = tagName + value;
|
|
955
957
|
this.#patternIgnore = null;
|
|
@@ -972,7 +974,7 @@ class XmlWriter {
|
|
|
972
974
|
({ tagName, tagVoid } = options);
|
|
973
975
|
}
|
|
974
976
|
const source = this.source;
|
|
975
|
-
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);
|
|
976
978
|
if (match) {
|
|
977
979
|
tagName ||= match[1];
|
|
978
980
|
const startIndex = match.index;
|
|
@@ -984,7 +986,7 @@ class XmlWriter {
|
|
|
984
986
|
endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
985
987
|
}
|
|
986
988
|
if (endIndex !== -1) {
|
|
987
|
-
return { tagName, id, outerXml: source.
|
|
989
|
+
return { tagName, id, outerXml: source.slice(startIndex, endIndex + 1), startIndex, endIndex, ignoreCase };
|
|
988
990
|
}
|
|
989
991
|
}
|
|
990
992
|
}
|
|
@@ -1007,7 +1009,7 @@ class XmlWriter {
|
|
|
1007
1009
|
if (!tagVoid) {
|
|
1008
1010
|
const [index, closeTag] = findCloseIndex(source, tagName, endIndex + 1, ignoreCase);
|
|
1009
1011
|
if (index !== -1) {
|
|
1010
|
-
outerXml = source.
|
|
1012
|
+
outerXml = source.slice(startIndex, index + 1);
|
|
1011
1013
|
endIndex = index;
|
|
1012
1014
|
}
|
|
1013
1015
|
else if (closeTag > 0) {
|
|
@@ -1024,7 +1026,7 @@ class XmlWriter {
|
|
|
1024
1026
|
return startIndex !== -1 ? this.spliceRawString({ startIndex, endIndex: startIndex + targetXml.length - 1, outerXml }) : '';
|
|
1025
1027
|
}
|
|
1026
1028
|
getRawString(index) {
|
|
1027
|
-
return this.source.
|
|
1029
|
+
return this.source.slice(index.startIndex, index.endIndex + 1);
|
|
1028
1030
|
}
|
|
1029
1031
|
spliceRawString(content, reset = true) {
|
|
1030
1032
|
const { startIndex, endIndex, outerXml } = content;
|
|
@@ -1032,7 +1034,7 @@ class XmlWriter {
|
|
|
1032
1034
|
this.resetPosition(startIndex);
|
|
1033
1035
|
}
|
|
1034
1036
|
++this.modifyCount;
|
|
1035
|
-
return this.source = this.source.
|
|
1037
|
+
return this.source = this.source.slice(0, startIndex) + outerXml + this.source.slice(endIndex + 1);
|
|
1036
1038
|
}
|
|
1037
1039
|
getComments() {
|
|
1038
1040
|
return this._invalidContent ? this._invalidContent.filter(item => item.type === 'comment') : null;
|
|
@@ -1047,7 +1049,7 @@ class XmlWriter {
|
|
|
1047
1049
|
this.resetPosition();
|
|
1048
1050
|
}
|
|
1049
1051
|
get newId() {
|
|
1050
|
-
return
|
|
1052
|
+
return randomUUID();
|
|
1051
1053
|
}
|
|
1052
1054
|
get nameOfId() {
|
|
1053
1055
|
return XmlWriter.getNameOfId(this.documentName);
|
|
@@ -1068,7 +1070,6 @@ class XmlWriter {
|
|
|
1068
1070
|
return this.modifyCount > 0;
|
|
1069
1071
|
}
|
|
1070
1072
|
}
|
|
1071
|
-
exports.XmlWriter = XmlWriter;
|
|
1072
1073
|
class XmlElement {
|
|
1073
1074
|
documentName;
|
|
1074
1075
|
node;
|
|
@@ -1082,7 +1083,7 @@ class XmlElement {
|
|
|
1082
1083
|
if (value === null) {
|
|
1083
1084
|
continue;
|
|
1084
1085
|
}
|
|
1085
|
-
result += '="' + (typeof value === 'string' ? escapeEntities ? XmlWriter.escapeXmlString(value) : value.
|
|
1086
|
+
result += '="' + (typeof value === 'string' ? escapeEntities ? XmlWriter.escapeXmlString(value) : value.replace(/"/g, '"') : Module.asString(value)) + '"';
|
|
1086
1087
|
}
|
|
1087
1088
|
return result;
|
|
1088
1089
|
}
|
|
@@ -1122,7 +1123,7 @@ class XmlElement {
|
|
|
1122
1123
|
if (!attrs.has(key)) {
|
|
1123
1124
|
attrs.set(key, match[2] || match[3] || match[4] || '');
|
|
1124
1125
|
}
|
|
1125
|
-
source =
|
|
1126
|
+
source = spliceMatch(source, match, '', REGEXP_ATTRVALUE);
|
|
1126
1127
|
}
|
|
1127
1128
|
for (const attr of source.matchAll(REGEXP_ATTRNAME)) {
|
|
1128
1129
|
const key = ignoreCase ? attr[1].toLowerCase() : attr[1];
|
|
@@ -1135,7 +1136,6 @@ class XmlElement {
|
|
|
1135
1136
|
}
|
|
1136
1137
|
this._tagVoid = isVoid;
|
|
1137
1138
|
REGEXP_ATTRVALUE.lastIndex = 0;
|
|
1138
|
-
REGEXP_ATTRNAME.lastIndex = 0;
|
|
1139
1139
|
}
|
|
1140
1140
|
else if (tagVoid) {
|
|
1141
1141
|
this._tagVoid = true;
|
|
@@ -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;
|