@e-mc/document 0.3.3 → 0.4.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 +10 -10
- package/asset.d.ts +7 -7
- package/asset.js +11 -11
- package/index.d.ts +4 -4
- package/index.js +1291 -1291
- package/package.json +4 -4
- package/parse/dom.d.ts +8 -8
- package/parse/dom.js +256 -256
- package/parse/index.d.ts +8 -8
- package/parse/index.js +1452 -1452
- package/transform/index.d.ts +7 -7
- package/transform/index.js +321 -321
- package/util.js +203 -203
package/parse/index.js
CHANGED
|
@@ -1,1452 +1,1452 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.XmlElement = exports.XmlWriter = exports.IGNORE_FLAG = void 0;
|
|
4
|
-
const htmlparser2 = require("htmlparser2");
|
|
5
|
-
const domhandler = require("domhandler");
|
|
6
|
-
const domutils = require("domutils");
|
|
7
|
-
const types_1 = require("../../types");
|
|
8
|
-
const module_1 = require("../../module");
|
|
9
|
-
var IGNORE_FLAG;
|
|
10
|
-
(function (IGNORE_FLAG) {
|
|
11
|
-
IGNORE_FLAG[IGNORE_FLAG["NONE"] = 0] = "NONE";
|
|
12
|
-
IGNORE_FLAG[IGNORE_FLAG["INTERIOR"] = 1] = "INTERIOR";
|
|
13
|
-
IGNORE_FLAG[IGNORE_FLAG["LOCATOR"] = 2] = "LOCATOR";
|
|
14
|
-
})(IGNORE_FLAG = exports.IGNORE_FLAG || (exports.IGNORE_FLAG = {}));
|
|
15
|
-
const Parser = htmlparser2.Parser;
|
|
16
|
-
const DomHandler = domhandler.DomHandler;
|
|
17
|
-
const CACHE_TAGNAME = {};
|
|
18
|
-
const CACHE_NAMEOFID = {};
|
|
19
|
-
const CACHE_TAGOFFSET = {};
|
|
20
|
-
const PATTERN_ATTRNAME = '([^\\s=>]+)';
|
|
21
|
-
const PATTERN_ATTRVALUE = `=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]*))`;
|
|
22
|
-
const PATTERN_TAGNAME = '[A-Za-z][\\w-]*';
|
|
23
|
-
const PATTERN_TAGOPEN = `(?:[^=>]|${PATTERN_ATTRVALUE})`;
|
|
24
|
-
const PATTERN_QUOTEVALUE = `(?:"[^"]+"|'[^']+')`;
|
|
25
|
-
const PATTERN_COMMENT = '/\\*[\\S\\s]*?\\*/';
|
|
26
|
-
const PATTERN_TRAILINGSPACE = '[ \\t]*((?:\\r?\\n)*)';
|
|
27
|
-
const REGEXP_ATTRNAME = new RegExp('\\s+' + PATTERN_ATTRNAME, 'g');
|
|
28
|
-
const REGEXP_ATTRVALUE = new RegExp(PATTERN_ATTRNAME + '\\s*' + PATTERN_ATTRVALUE, 'g');
|
|
29
|
-
const REGEXP_TAGATTR = new RegExp(`<${PATTERN_TAGNAME}\\s+(${PATTERN_TAGOPEN}*)>`, 'g');
|
|
30
|
-
const REGEXP_ESCAPECHAR = /[-|\\{}()[\]^$+*?.]/g;
|
|
31
|
-
function applyAttributes(attrs, data, ignoreCase) {
|
|
32
|
-
for (const key in data) {
|
|
33
|
-
attrs.set(ignoreCase && typeof key === 'string' ? key.toLowerCase() : key.toString(), data[key]);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function deletePosition(item, rootName, startIndex) {
|
|
37
|
-
if (isIndex(item.startIndex) && (!isIndex(startIndex) || item.startIndex >= startIndex) && item.tagName !== rootName) {
|
|
38
|
-
item.startIndex = undefined;
|
|
39
|
-
item.endIndex = undefined;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function updateTagName(item, tagName) {
|
|
43
|
-
item.tagName = tagName;
|
|
44
|
-
item.tagIndex = Infinity;
|
|
45
|
-
item.tagCount = 0;
|
|
46
|
-
}
|
|
47
|
-
function resetTagPosition(item) {
|
|
48
|
-
item.tagIndex = -1;
|
|
49
|
-
item.tagCount = 0;
|
|
50
|
-
}
|
|
51
|
-
function findCloseIndex(source, tagName, lastIndex, ignoreCase) {
|
|
52
|
-
var _a;
|
|
53
|
-
const flags = ignoreCase ? 'gi' : 'g';
|
|
54
|
-
const pattern = CACHE_TAGNAME[_a = tagName + flags + '0'] || (CACHE_TAGNAME[_a] = new RegExp(`<(?:${escapeTagName(tagName)}\\s*|/${escapeTagName(tagName)}\\s*>)`, flags));
|
|
55
|
-
pattern.lastIndex = lastIndex;
|
|
56
|
-
let openTag = 1, closeTag = 0, match;
|
|
57
|
-
while (match = pattern.exec(source)) {
|
|
58
|
-
if (match[0][1] !== '/') {
|
|
59
|
-
++openTag;
|
|
60
|
-
}
|
|
61
|
-
else if (openTag === ++closeTag) {
|
|
62
|
-
return [match.index + match[0].length - 1, closeTag];
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return [-1, closeTag];
|
|
66
|
-
}
|
|
67
|
-
function isValidIndex(items, startIndex, endIndex) {
|
|
68
|
-
for (let i = 0, length = items.length; i < length; ++i) {
|
|
69
|
-
const item = items[i];
|
|
70
|
-
if (startIndex > item.startIndex && endIndex < item.endIndex) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
function getNewlineCount(value) {
|
|
77
|
-
let result = 0;
|
|
78
|
-
for (let i = 0, length = value.length; i < length; ++i) {
|
|
79
|
-
if (value[i] === '\n') {
|
|
80
|
-
++result;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
function getParserDOM(source, parser) {
|
|
86
|
-
const result = {};
|
|
87
|
-
new Parser(new DomHandler((err, dom) => {
|
|
88
|
-
if (!err) {
|
|
89
|
-
result.outDom = dom;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
result.error = err;
|
|
93
|
-
}
|
|
94
|
-
}, { withStartIndices: true, withEndIndices: true }), { decodeEntities: false, ...parser }).end(source);
|
|
95
|
-
return result;
|
|
96
|
-
}
|
|
97
|
-
const isIndex = (value) => typeof value === 'number' && value >= 0 && value !== Infinity;
|
|
98
|
-
const isCount = (value) => typeof value === 'number' && value > 0 && value !== Infinity;
|
|
99
|
-
const getPatternId = (name) => CACHE_NAMEOFID[name] || (CACHE_NAMEOFID[name] = new RegExp(`\\s${(0, types_1.escapePattern)(name)}="([^"]+)"`));
|
|
100
|
-
const escapeTagName = (value) => value.replace(REGEXP_ESCAPECHAR, capture => capture === '-' ? '\\x2d' : '\\' + capture);
|
|
101
|
-
class XmlWriter {
|
|
102
|
-
static get PATTERN_ATTRNAME() { return PATTERN_ATTRNAME; }
|
|
103
|
-
static get PATTERN_ATTRVALUE() { return PATTERN_ATTRVALUE; }
|
|
104
|
-
static get PATTERN_TAGNAME() { return PATTERN_TAGNAME; }
|
|
105
|
-
static get PATTERN_TAGOPEN() { return PATTERN_TAGOPEN; }
|
|
106
|
-
static get PATTERN_QUOTEVALUE() { return PATTERN_QUOTEVALUE; }
|
|
107
|
-
static get PATTERN_COMMENT() { return PATTERN_COMMENT; }
|
|
108
|
-
static get PATTERN_TRAILINGSPACE() { return PATTERN_TRAILINGSPACE; }
|
|
109
|
-
static replaceMatch(match, source, content = '', options) {
|
|
110
|
-
if (typeof content === 'number') {
|
|
111
|
-
content = match[content] || '';
|
|
112
|
-
}
|
|
113
|
-
let index = match.index, leading = index > 0 ? source.substring(0, index) : '', trailing = source.substring(index + match[0].length);
|
|
114
|
-
if (options) {
|
|
115
|
-
let pattern;
|
|
116
|
-
if ((0, types_1.isPlainObject)(options)) {
|
|
117
|
-
let trimLeading, trimTrailing;
|
|
118
|
-
({ pattern, trimLeading, trimTrailing } = options);
|
|
119
|
-
if (trimLeading) {
|
|
120
|
-
const length = leading.length;
|
|
121
|
-
leading = leading.trimEnd();
|
|
122
|
-
index -= length - leading.length;
|
|
123
|
-
}
|
|
124
|
-
if (trimTrailing) {
|
|
125
|
-
trailing = trailing.trimStart();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
pattern = options;
|
|
130
|
-
}
|
|
131
|
-
if (pattern) {
|
|
132
|
-
pattern.lastIndex = index + content.length;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return leading + content + trailing;
|
|
136
|
-
}
|
|
137
|
-
static escapeXmlString(value, ampersand) {
|
|
138
|
-
return value.replace(ampersand ? /[<>"'&]/g : /[<>"']|&([^#A-Za-z]|$)/g, capture => {
|
|
139
|
-
switch (capture) {
|
|
140
|
-
case '<':
|
|
141
|
-
return '<';
|
|
142
|
-
case '>':
|
|
143
|
-
return '>';
|
|
144
|
-
case '"':
|
|
145
|
-
return '"';
|
|
146
|
-
case "'":
|
|
147
|
-
return ''';
|
|
148
|
-
default:
|
|
149
|
-
return '&' + (capture[1] || '');
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
static escapeAttributes(source) {
|
|
154
|
-
let match;
|
|
155
|
-
while (match = REGEXP_TAGATTR.exec(source)) {
|
|
156
|
-
let output = match[0], modified, subMatch;
|
|
157
|
-
while (subMatch = REGEXP_ATTRVALUE.exec(match[1])) {
|
|
158
|
-
const value = subMatch[2] || subMatch[3] || subMatch[4];
|
|
159
|
-
if (value) {
|
|
160
|
-
const escaped = this.escapeXmlString(value);
|
|
161
|
-
if (escaped !== value) {
|
|
162
|
-
output = output.replace(subMatch[0], subMatch[1] + `="${escaped}"`);
|
|
163
|
-
modified = true;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (modified) {
|
|
168
|
-
source = this.replaceMatch(match, source, output, REGEXP_TAGATTR);
|
|
169
|
-
}
|
|
170
|
-
REGEXP_ATTRVALUE.lastIndex = 0;
|
|
171
|
-
}
|
|
172
|
-
REGEXP_TAGATTR.lastIndex = 0;
|
|
173
|
-
return source;
|
|
174
|
-
}
|
|
175
|
-
static getNewlineString(leading, trailing, newline) {
|
|
176
|
-
const value = leading + trailing;
|
|
177
|
-
return getNewlineCount(value) > 1 ? newline || (value.indexOf('\r') !== -1 ? '\r\n' : '\n') : '';
|
|
178
|
-
}
|
|
179
|
-
static findCloseTag(source, startIndex = 0) {
|
|
180
|
-
const length = source.length;
|
|
181
|
-
const start = [];
|
|
182
|
-
for (let i = startIndex, quote = ''; i < length; ++i) {
|
|
183
|
-
let ch = source[i];
|
|
184
|
-
if (ch === '=') {
|
|
185
|
-
if (!quote) {
|
|
186
|
-
while (this.isSpace(ch = source[++i])) { }
|
|
187
|
-
switch (ch) {
|
|
188
|
-
case '"':
|
|
189
|
-
quote = '"';
|
|
190
|
-
start.push(i);
|
|
191
|
-
break;
|
|
192
|
-
case "'":
|
|
193
|
-
quote = "'";
|
|
194
|
-
start.push(i);
|
|
195
|
-
break;
|
|
196
|
-
case '>':
|
|
197
|
-
return i;
|
|
198
|
-
default:
|
|
199
|
-
while (!this.isSpace(ch = source[++i])) {
|
|
200
|
-
if (ch === '>') {
|
|
201
|
-
return i;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
else if (ch === quote) {
|
|
209
|
-
quote = '';
|
|
210
|
-
}
|
|
211
|
-
else if (ch === '>' && !quote) {
|
|
212
|
-
return i;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
if (start.length) {
|
|
216
|
-
for (const index of start.reverse()) {
|
|
217
|
-
for (let j = index + 1; j < length; ++j) {
|
|
218
|
-
if (source[j] === '>') {
|
|
219
|
-
return j;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return -1;
|
|
225
|
-
}
|
|
226
|
-
static findElement(source, node, options = {}) {
|
|
227
|
-
const { document, id, tagCount = node.tagCount, locatorAttr, parser } = options;
|
|
228
|
-
let outDom = options.outDom, error;
|
|
229
|
-
if (!(0, types_1.isArray)(outDom)) {
|
|
230
|
-
({ outDom, error } = getParserDOM(source, parser));
|
|
231
|
-
}
|
|
232
|
-
const result = { element: null, error: null };
|
|
233
|
-
if (error) {
|
|
234
|
-
result.error = error;
|
|
235
|
-
return result;
|
|
236
|
-
}
|
|
237
|
-
const nodes = domutils.getElementsByTagName(node.tagName, outDom, true);
|
|
238
|
-
if (!parser?.xmlMode) {
|
|
239
|
-
nodes.filter(item => item.next && item.next.startIndex <= item.endIndex).forEach(item => {
|
|
240
|
-
for (let i = 0, length = nodes.length; i < length; ++i) {
|
|
241
|
-
const element = nodes[i];
|
|
242
|
-
let current = element.prev;
|
|
243
|
-
while (current) {
|
|
244
|
-
if (current === item.next) {
|
|
245
|
-
item.endIndex = element.endIndex;
|
|
246
|
-
nodes.splice(i, 1);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
current = current.prev;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
let index = -1;
|
|
255
|
-
if (document && id) {
|
|
256
|
-
const documentId = this.getNameOfId(document);
|
|
257
|
-
if ((index = nodes.findIndex(elem => elem.attribs[documentId] === id)) !== -1) {
|
|
258
|
-
result.element = nodes[index];
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
if (!result.element) {
|
|
262
|
-
const locator = node.locator;
|
|
263
|
-
if (locator && locatorAttr) {
|
|
264
|
-
const { element } = this.locateElement(source, locator, locatorAttr, { parser, outDom });
|
|
265
|
-
if (element?.tagName === node.tagName) {
|
|
266
|
-
result.element = element;
|
|
267
|
-
index = nodes.findIndex(item => item === element);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
if ((!result.element || index === -1) && nodes.length === tagCount) {
|
|
271
|
-
const tagIndex = node.tagIndex;
|
|
272
|
-
if (tagIndex !== undefined && nodes[tagIndex]) {
|
|
273
|
-
result.element = nodes[tagIndex];
|
|
274
|
-
index = tagIndex;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if (result.element) {
|
|
279
|
-
result.tagName = node.tagName;
|
|
280
|
-
result.tagIndex = index;
|
|
281
|
-
result.tagCount = index !== -1 ? nodes.length : Infinity;
|
|
282
|
-
}
|
|
283
|
-
result.parser = parser;
|
|
284
|
-
result.outDom = outDom;
|
|
285
|
-
return result;
|
|
286
|
-
}
|
|
287
|
-
static locateElement(source, locator, attr, options = {}) {
|
|
288
|
-
let { parser, outDom } = options, error;
|
|
289
|
-
if (!(0, types_1.isArray)(outDom)) {
|
|
290
|
-
({ outDom, error } = getParserDOM(source, parser));
|
|
291
|
-
}
|
|
292
|
-
if (error) {
|
|
293
|
-
return { element: null, error };
|
|
294
|
-
}
|
|
295
|
-
const { id, count = 1, index = 0 } = locator;
|
|
296
|
-
const nodes = domutils.findAll(elem => elem.attribs[attr] === id, outDom);
|
|
297
|
-
const element = nodes.length === count && nodes[index] || null;
|
|
298
|
-
return { element, parser, outDom, error: null };
|
|
299
|
-
}
|
|
300
|
-
static getTagOffset(source, replacement, options) {
|
|
301
|
-
var _a, _b;
|
|
302
|
-
if ((0, types_1.isObject)(replacement)) {
|
|
303
|
-
options = replacement;
|
|
304
|
-
replacement = undefined;
|
|
305
|
-
}
|
|
306
|
-
let parser;
|
|
307
|
-
if (options) {
|
|
308
|
-
const { ignoreCase, ignoreTagName, ignoreTagGroup } = options;
|
|
309
|
-
if (ignoreTagName) {
|
|
310
|
-
const flags = ignoreCase ? 'gi' : 'g';
|
|
311
|
-
source = source.replace(CACHE_TAGOFFSET[_a = ignoreTagName + flags] || (CACHE_TAGOFFSET[_a] = new RegExp(`<(?:${ignoreTagName.split('|').map(value => escapeTagName(value)).join('|')})${XmlWriter.PATTERN_TAGOPEN}*>[\\S\\s]*?<\\/\\1\\s*>`, flags)), '');
|
|
312
|
-
}
|
|
313
|
-
if (ignoreTagGroup) {
|
|
314
|
-
for (let i = 0, length = ignoreTagGroup.length; i < length; i += 2) {
|
|
315
|
-
const start = ignoreTagGroup[i];
|
|
316
|
-
const end = ignoreTagGroup[i + 1];
|
|
317
|
-
if (end) {
|
|
318
|
-
source = source.replace(CACHE_TAGOFFSET[_b = start + end] || (CACHE_TAGOFFSET[_b] = new RegExp(escapeTagName(start) + '[\\S\\s]*?' + escapeTagName(end), 'g')), '');
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
parser = options.parser;
|
|
323
|
-
}
|
|
324
|
-
const result = {};
|
|
325
|
-
new Parser({
|
|
326
|
-
onopentag(name) {
|
|
327
|
-
result[name] = (result[name] || 0) + 1;
|
|
328
|
-
}
|
|
329
|
-
}, { xmlMode: true, decodeEntities: false, lowerCaseAttributeNames: false, ...parser }).end(source);
|
|
330
|
-
if ((0, types_1.isString)(replacement)) {
|
|
331
|
-
const next = this.getTagOffset(replacement, options);
|
|
332
|
-
let modified;
|
|
333
|
-
for (const tagName of new Set([...Object.keys(result), ...Object.keys(next)])) {
|
|
334
|
-
if (result[tagName] !== next[tagName]) {
|
|
335
|
-
result[tagName] = (next[tagName] || 0) - (result[tagName] || 0);
|
|
336
|
-
modified = true;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
if (!modified) {
|
|
340
|
-
return {};
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return result;
|
|
344
|
-
}
|
|
345
|
-
static getNodeId(node, document) {
|
|
346
|
-
return node.id?.[document] || '';
|
|
347
|
-
}
|
|
348
|
-
static getNameOfId(document) {
|
|
349
|
-
return `data-${document}-id`;
|
|
350
|
-
}
|
|
351
|
-
static getCommentsAndCDATA(source, tagPattern = '', ignoreCase, stripXml) {
|
|
352
|
-
var _a, _b;
|
|
353
|
-
let tagGroup;
|
|
354
|
-
if (stripXml) {
|
|
355
|
-
if (typeof tagPattern !== 'string') {
|
|
356
|
-
tagPattern = '';
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
else if (Array.isArray(tagPattern)) {
|
|
360
|
-
if (tagPattern.every(item => typeof item === 'string')) {
|
|
361
|
-
tagGroup = tagPattern;
|
|
362
|
-
tagPattern = '';
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
[tagPattern = '', tagGroup] = tagPattern;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
const result = [];
|
|
369
|
-
const flags = ignoreCase ? 'gi' : 'g';
|
|
370
|
-
let pattern = CACHE_TAGNAME[_a = tagPattern + flags] || (CACHE_TAGNAME[_a] = new RegExp(`<(?:(!--[\\S\\s]*?--)|(!\\[CDATA\\[[\\S\\s]*?\\]\\])` + (tagPattern ? '|' + `(${tagPattern})${PATTERN_TAGOPEN}*` : '') + ')>', flags)), match;
|
|
371
|
-
pattern.lastIndex = 0;
|
|
372
|
-
while (match = pattern.exec(source)) {
|
|
373
|
-
if (stripXml) {
|
|
374
|
-
source = this.replaceMatch(match, source, '', { pattern, trimLeading: true });
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
const type = match[1] && 'comment' || match[2] && 'cdata' || 'node';
|
|
378
|
-
const startIndex = match.index;
|
|
379
|
-
let endIndex = startIndex + match[0].length;
|
|
380
|
-
if (type !== 'node') {
|
|
381
|
-
result.push({ type, outerXml: match[0], startIndex, endIndex: endIndex - 1 });
|
|
382
|
-
}
|
|
383
|
-
else if ((endIndex = findCloseIndex(source, match[3], endIndex, ignoreCase)[0]) !== -1) {
|
|
384
|
-
result.push({ type, outerXml: source.substring(startIndex, endIndex + 1), startIndex, endIndex });
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
if (stripXml) {
|
|
388
|
-
return source;
|
|
389
|
-
}
|
|
390
|
-
if (tagGroup) {
|
|
391
|
-
for (let i = 0, length = tagGroup.length; i < length; i += 2) {
|
|
392
|
-
const start = tagGroup[i];
|
|
393
|
-
const end = tagGroup[i + 1];
|
|
394
|
-
if (end) {
|
|
395
|
-
pattern = CACHE_TAGNAME[_b = start + end] || (CACHE_TAGNAME[_b] = new RegExp(escapeTagName(start) + '[\\S\\s]*?' + escapeTagName(end), 'g'));
|
|
396
|
-
pattern.lastIndex = 0;
|
|
397
|
-
while (match = pattern.exec(source)) {
|
|
398
|
-
const startIndex = match.index;
|
|
399
|
-
result.push({ type: 'block', outerXml: match[0], startIndex, endIndex: startIndex + match[0].length - 1 });
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
return result;
|
|
405
|
-
}
|
|
406
|
-
static isEqual(node, other, document, ignoreCase) {
|
|
407
|
-
if (typeof document === 'boolean') {
|
|
408
|
-
ignoreCase = document;
|
|
409
|
-
document = undefined;
|
|
410
|
-
}
|
|
411
|
-
if (node === other) {
|
|
412
|
-
return true;
|
|
413
|
-
}
|
|
414
|
-
const { index, tagName, tagIndex, tagCount, id } = node;
|
|
415
|
-
if ((ignoreCase ? tagName.toLowerCase() === other.tagName.toLowerCase() : tagName === other.tagName) && (index === other.index && isIndex(index) || tagIndex === other.tagIndex && tagCount === other.tagCount && isIndex(tagIndex) && isCount(tagCount))) {
|
|
416
|
-
return true;
|
|
417
|
-
}
|
|
418
|
-
return document && other.id && id?.[document] ? id[document] === other.id[document] : false;
|
|
419
|
-
}
|
|
420
|
-
static isIndex(value) {
|
|
421
|
-
return isIndex(value);
|
|
422
|
-
}
|
|
423
|
-
static isCount(value) {
|
|
424
|
-
return isCount(value);
|
|
425
|
-
}
|
|
426
|
-
static isSpace(ch) {
|
|
427
|
-
return ch === ' ' || ch === '\n' || ch === '\t' || ch === '\f' || ch === '\r' || ch === '\v';
|
|
428
|
-
}
|
|
429
|
-
constructor(documentName, source, elements, options) {
|
|
430
|
-
this.documentName = documentName;
|
|
431
|
-
this.elements = elements;
|
|
432
|
-
this.modifyCount = 0;
|
|
433
|
-
this.failCount = 0;
|
|
434
|
-
this.errors = [];
|
|
435
|
-
this.newline = '\n';
|
|
436
|
-
this._tagCount = Object.create(null);
|
|
437
|
-
this._hasInvalidContent = true;
|
|
438
|
-
this._ignoreFlag = 0;
|
|
439
|
-
this._appendCount = 0;
|
|
440
|
-
this._invalidContent = null;
|
|
441
|
-
this._patternId = null;
|
|
442
|
-
this._patternIgnore = null;
|
|
443
|
-
this._writeStartIndex = -1;
|
|
444
|
-
this._source = source;
|
|
445
|
-
this.parser = options?.parser;
|
|
446
|
-
}
|
|
447
|
-
init(offsetMap) {
|
|
448
|
-
const appending = [];
|
|
449
|
-
const rootName = this.rootName;
|
|
450
|
-
for (const item of this.elements) {
|
|
451
|
-
if (item.append) {
|
|
452
|
-
appending.push(item);
|
|
453
|
-
}
|
|
454
|
-
if (isCount(item.tagCount)) {
|
|
455
|
-
const tagName = item.tagName;
|
|
456
|
-
item.tagCount += offsetMap?.[tagName] || 0;
|
|
457
|
-
this._tagCount[tagName] = item.tagCount;
|
|
458
|
-
}
|
|
459
|
-
deletePosition(item, rootName);
|
|
460
|
-
}
|
|
461
|
-
if (appending.length) {
|
|
462
|
-
this.insertNodes(appending);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
ignoreFlag(...values) {
|
|
466
|
-
values.forEach(value => this._ignoreFlag |= value);
|
|
467
|
-
}
|
|
468
|
-
getInvalidArea() {
|
|
469
|
-
if ((this._ignoreFlag & IGNORE_FLAG.INTERIOR) === 0 && this._hasInvalidContent) {
|
|
470
|
-
const startIndex = this._writeStartIndex;
|
|
471
|
-
if (isIndex(startIndex) && this._invalidContent && !this._invalidContent.some(item => item.startIndex >= startIndex)) {
|
|
472
|
-
return this._invalidContent;
|
|
473
|
-
}
|
|
474
|
-
const result = XmlWriter.getCommentsAndCDATA(this.source, this.ignoreTagGroup ? [this.ignoreTagName || '', this.ignoreTagGroup] : this.ignoreTagName, this.ignoreCaseTagName);
|
|
475
|
-
this._invalidContent = result;
|
|
476
|
-
if (result.length) {
|
|
477
|
-
return result;
|
|
478
|
-
}
|
|
479
|
-
this._hasInvalidContent = false;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
insertNodes(nodes) {
|
|
483
|
-
nodes.sort((a, b) => {
|
|
484
|
-
if (!isIndex(a.index) || !isIndex(b.index)) {
|
|
485
|
-
return 0;
|
|
486
|
-
}
|
|
487
|
-
if (a.index === b.index) {
|
|
488
|
-
const itemA = a.append;
|
|
489
|
-
const itemB = b.append;
|
|
490
|
-
if (itemA && itemB) {
|
|
491
|
-
const prependA = itemA.prepend;
|
|
492
|
-
const prependB = itemB.prepend;
|
|
493
|
-
if (prependA && prependB) {
|
|
494
|
-
return itemA.order - itemB.order;
|
|
495
|
-
}
|
|
496
|
-
if (!prependA && !prependB) {
|
|
497
|
-
return itemB.order - itemA.order;
|
|
498
|
-
}
|
|
499
|
-
if (prependA || prependB === false) {
|
|
500
|
-
return 1;
|
|
501
|
-
}
|
|
502
|
-
if (prependA === false) {
|
|
503
|
-
return -1;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return b.index - a.index;
|
|
508
|
-
})
|
|
509
|
-
.forEach(item => this.append(item));
|
|
510
|
-
}
|
|
511
|
-
fromNode(node, append) {
|
|
512
|
-
const element = this.newElement(node);
|
|
513
|
-
if (append) {
|
|
514
|
-
const tagName = append.tagName;
|
|
515
|
-
if (!(tagName in this._tagCount) && isCount(append.tagCount)) {
|
|
516
|
-
this._tagCount[tagName] = append.tagCount;
|
|
517
|
-
}
|
|
518
|
-
append.id || (append.id = this.newId);
|
|
519
|
-
element.setAppend(append);
|
|
520
|
-
}
|
|
521
|
-
return element;
|
|
522
|
-
}
|
|
523
|
-
append(node) {
|
|
524
|
-
const append = node.append;
|
|
525
|
-
if (append) {
|
|
526
|
-
if (node.ignoreCase) {
|
|
527
|
-
append.tagName = append.tagName.toLowerCase();
|
|
528
|
-
}
|
|
529
|
-
const element = this.fromNode(node, append);
|
|
530
|
-
if (this.write(element)) {
|
|
531
|
-
delete node.append;
|
|
532
|
-
++this._appendCount;
|
|
533
|
-
return element;
|
|
534
|
-
}
|
|
535
|
-
const index = this.elements.findIndex(item => item === node);
|
|
536
|
-
if (index !== -1) {
|
|
537
|
-
this.elements.splice(index, 1);
|
|
538
|
-
}
|
|
539
|
-
++this.failCount;
|
|
540
|
-
this.errors.push((0, types_1.errorValue)(`Unable to ${append.prepend ? 'prepend' : 'append'} element`, append.tagName.toUpperCase() + (isIndex(node.index) ? ' @ ' + node.index : '')));
|
|
541
|
-
}
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
write(element) {
|
|
545
|
-
if (!element.modified) {
|
|
546
|
-
return true;
|
|
547
|
-
}
|
|
548
|
-
const { node, append } = element;
|
|
549
|
-
element.parser || (element.parser = this.parser);
|
|
550
|
-
element.newline = this.newline;
|
|
551
|
-
let output, outerXml = '', error;
|
|
552
|
-
if (element.hasPosition()) {
|
|
553
|
-
[output, outerXml] = element.replace(this.source, { startIndex: node.startIndex, endIndex: node.endIndex, append, remove: element.remove });
|
|
554
|
-
}
|
|
555
|
-
else if (element.tagName !== this.rootName) {
|
|
556
|
-
[output, outerXml, error] = element.write(this.source, this.getInvalidArea());
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
error = new Error('Root source position not found');
|
|
560
|
-
}
|
|
561
|
-
if (output) {
|
|
562
|
-
this.source = output;
|
|
563
|
-
if (!this.elements.includes(node)) {
|
|
564
|
-
const index = this.elements.findIndex(item => XmlWriter.isEqual(node, item));
|
|
565
|
-
if (index !== -1) {
|
|
566
|
-
this.elements.splice(index, 1, node);
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
this.elements.push(node);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
if (append) {
|
|
573
|
-
const { tagName, id, textContent = '', prepend, nextSibling } = append;
|
|
574
|
-
if (!prepend) {
|
|
575
|
-
node.index = nextSibling ?? -1;
|
|
576
|
-
}
|
|
577
|
-
(node.id || (node.id = {}))[this.documentName] = id;
|
|
578
|
-
element.id = id;
|
|
579
|
-
element.innerXml = textContent;
|
|
580
|
-
const offset = element.getInnerOffset(tagName);
|
|
581
|
-
if (tagName !== node.tagName) {
|
|
582
|
-
updateTagName(node, tagName);
|
|
583
|
-
this.indexTag(tagName, append, offset);
|
|
584
|
-
}
|
|
585
|
-
else if (!prepend && isIndex(node.tagIndex) && isCount(node.tagCount)) {
|
|
586
|
-
++node.tagIndex;
|
|
587
|
-
++node.tagCount;
|
|
588
|
-
}
|
|
589
|
-
this.increment([node], offset);
|
|
590
|
-
}
|
|
591
|
-
else if (element.remove) {
|
|
592
|
-
this.decrement(node, element.getInnerOffset(element.tagName), true);
|
|
593
|
-
}
|
|
594
|
-
else if (element.tagName !== node.tagName) {
|
|
595
|
-
this.renameTag(node, element.tagName);
|
|
596
|
-
}
|
|
597
|
-
this.update(node, outerXml, append, element.tagOffset);
|
|
598
|
-
if (element.innerXml && !element.remove && (element.hasModifiedContent() || this.patternIgnore?.test(element.tagName))) {
|
|
599
|
-
this._hasInvalidContent = true;
|
|
600
|
-
this._writeStartIndex = -1;
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
this._writeStartIndex = node.startIndex;
|
|
604
|
-
}
|
|
605
|
-
element.reset();
|
|
606
|
-
return true;
|
|
607
|
-
}
|
|
608
|
-
if (node.locator && (this._ignoreFlag & IGNORE_FLAG.LOCATOR)) {
|
|
609
|
-
return true;
|
|
610
|
-
}
|
|
611
|
-
if (error) {
|
|
612
|
-
this.errors.push(error);
|
|
613
|
-
}
|
|
614
|
-
++this.failCount;
|
|
615
|
-
return false;
|
|
616
|
-
}
|
|
617
|
-
save() {
|
|
618
|
-
this.reset();
|
|
619
|
-
return this.source;
|
|
620
|
-
}
|
|
621
|
-
update(node, outerXml, append, offsetMap) {
|
|
622
|
-
const { elements, documentName, rootName } = this;
|
|
623
|
-
const { tagName, startIndex, endIndex } = node;
|
|
624
|
-
const items = [];
|
|
625
|
-
const updateMap = offsetMap && Object.keys(offsetMap).length > 0;
|
|
626
|
-
const index = isIndex(node.index) ? node.index : -1;
|
|
627
|
-
const hasIndex = isIndex(startIndex) && isIndex(endIndex);
|
|
628
|
-
for (let i = 0; i < elements.length; ++i) {
|
|
629
|
-
const item = elements[i];
|
|
630
|
-
if (XmlWriter.isEqual(node, item, documentName, this.ignoreCaseTagName)) {
|
|
631
|
-
if (!outerXml) {
|
|
632
|
-
item.removed = true;
|
|
633
|
-
elements.splice(i--, 1);
|
|
634
|
-
continue;
|
|
635
|
-
}
|
|
636
|
-
item.outerXml = outerXml;
|
|
637
|
-
if (hasIndex) {
|
|
638
|
-
item.startIndex = startIndex;
|
|
639
|
-
item.endIndex = endIndex;
|
|
640
|
-
}
|
|
641
|
-
else {
|
|
642
|
-
deletePosition(item, rootName);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
deletePosition(item, rootName, startIndex);
|
|
647
|
-
}
|
|
648
|
-
if (updateMap && item.append) {
|
|
649
|
-
items.push([true, item.index, item.append]);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
if (updateMap) {
|
|
653
|
-
items.push(...elements.map(item => [false, item.index, item]));
|
|
654
|
-
for (const name in offsetMap) {
|
|
655
|
-
const offset = offsetMap[name];
|
|
656
|
-
invalid: {
|
|
657
|
-
if (offset) {
|
|
658
|
-
const updated = !!append && tagName === name;
|
|
659
|
-
let offsetCount = -1;
|
|
660
|
-
for (const [appended, itemIndex, item] of items) {
|
|
661
|
-
if (item.tagName === name) {
|
|
662
|
-
if (index !== -1 && isIndex(itemIndex) && isCount(item.tagCount)) {
|
|
663
|
-
if (appended) {
|
|
664
|
-
if (updated) {
|
|
665
|
-
item.tagCount = this._tagCount[name];
|
|
666
|
-
}
|
|
667
|
-
else {
|
|
668
|
-
item.tagCount += offset;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
else if (isIndex(item.tagIndex)) {
|
|
672
|
-
if (!updated) {
|
|
673
|
-
if (itemIndex > index) {
|
|
674
|
-
item.tagIndex += offset;
|
|
675
|
-
}
|
|
676
|
-
item.tagCount += offset;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
offsetCount = Infinity;
|
|
681
|
-
}
|
|
682
|
-
if (offsetCount === -1) {
|
|
683
|
-
offsetCount = item.tagCount;
|
|
684
|
-
continue;
|
|
685
|
-
}
|
|
686
|
-
if (offsetCount === item.tagCount) {
|
|
687
|
-
continue;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
this.resetTag(name);
|
|
691
|
-
break invalid;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
if (offsetCount !== -1) {
|
|
695
|
-
this._tagCount[name] = offsetCount;
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
increment(nodes, offset = 0) {
|
|
703
|
-
let { index, tagName, tagIndex } = nodes[0];
|
|
704
|
-
if (!isIndex(index)) {
|
|
705
|
-
index = -1;
|
|
706
|
-
}
|
|
707
|
-
let invalid = index === -1;
|
|
708
|
-
++offset;
|
|
709
|
-
for (const item of this.elements) {
|
|
710
|
-
if (!nodes.includes(item)) {
|
|
711
|
-
if (item.tagName === tagName) {
|
|
712
|
-
if (!invalid && isIndex(tagIndex) && isIndex(item.tagIndex) && isCount(item.tagCount)) {
|
|
713
|
-
if (item.tagIndex >= tagIndex) {
|
|
714
|
-
item.tagIndex += offset;
|
|
715
|
-
}
|
|
716
|
-
item.tagCount += offset;
|
|
717
|
-
}
|
|
718
|
-
else {
|
|
719
|
-
invalid = true;
|
|
720
|
-
continue;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
if (isIndex(item.index) && index !== -1) {
|
|
724
|
-
const append = item.append;
|
|
725
|
-
if (item.index >= index) {
|
|
726
|
-
++item.index;
|
|
727
|
-
}
|
|
728
|
-
if (append) {
|
|
729
|
-
const nextSibling = append.nextSibling;
|
|
730
|
-
if (isIndex(nextSibling) && nextSibling >= index) {
|
|
731
|
-
append.nextSibling = nextSibling + 1;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
if (invalid) {
|
|
738
|
-
this.resetTag(tagName);
|
|
739
|
-
}
|
|
740
|
-
else if (tagName in this._tagCount) {
|
|
741
|
-
this._tagCount[tagName] += offset;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
decrement(node, offset = 0, remove) {
|
|
745
|
-
const { elements, documentName } = this;
|
|
746
|
-
const { tagName, tagIndex, tagCount } = node;
|
|
747
|
-
const hasIndex = isIndex(tagIndex) && isCount(tagCount);
|
|
748
|
-
const result = [];
|
|
749
|
-
++offset;
|
|
750
|
-
for (let i = 0; i < elements.length; ++i) {
|
|
751
|
-
const item = elements[i];
|
|
752
|
-
if (item.tagName === tagName) {
|
|
753
|
-
if (XmlWriter.isEqual(node, item, documentName, this.ignoreCaseTagName)) {
|
|
754
|
-
if (remove) {
|
|
755
|
-
item.removed = true;
|
|
756
|
-
elements.splice(i--, 1);
|
|
757
|
-
}
|
|
758
|
-
else {
|
|
759
|
-
result.push(item);
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
else if (hasIndex && isIndex(item.tagIndex) && isCount(item.tagCount)) {
|
|
763
|
-
if (item.tagIndex > tagIndex) {
|
|
764
|
-
item.tagIndex -= offset;
|
|
765
|
-
}
|
|
766
|
-
item.tagCount -= offset;
|
|
767
|
-
}
|
|
768
|
-
else {
|
|
769
|
-
this.resetTag(tagName);
|
|
770
|
-
return [];
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
if (tagName in this._tagCount) {
|
|
775
|
-
this._tagCount[tagName] -= offset;
|
|
776
|
-
}
|
|
777
|
-
return result;
|
|
778
|
-
}
|
|
779
|
-
renameTag(node, tagName) {
|
|
780
|
-
const revised = this.decrement(node);
|
|
781
|
-
if (revised.includes(node)) {
|
|
782
|
-
if (tagName in this._tagCount) {
|
|
783
|
-
revised.forEach(item => updateTagName(item, tagName));
|
|
784
|
-
this.indexTag(tagName);
|
|
785
|
-
this.increment(revised);
|
|
786
|
-
}
|
|
787
|
-
else {
|
|
788
|
-
this.resetTag(tagName);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
else {
|
|
792
|
-
node.tagName = tagName;
|
|
793
|
-
resetTagPosition(node);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
indexTag(tagName, append, offset = 0) {
|
|
797
|
-
if (tagName in this._tagCount) {
|
|
798
|
-
const elements = [];
|
|
799
|
-
const revised = [];
|
|
800
|
-
const indexMap = new Set();
|
|
801
|
-
let documentIndex = -1, minIndex = Infinity, maxIndex = -1;
|
|
802
|
-
for (const item of this.elements) {
|
|
803
|
-
if (item.tagName === tagName) {
|
|
804
|
-
const index = item.index;
|
|
805
|
-
if (isIndex(index)) {
|
|
806
|
-
const tagIndex = item.tagIndex;
|
|
807
|
-
if (tagIndex === Infinity) {
|
|
808
|
-
documentIndex = index;
|
|
809
|
-
revised.push(item);
|
|
810
|
-
continue;
|
|
811
|
-
}
|
|
812
|
-
if (isIndex(tagIndex)) {
|
|
813
|
-
elements.push(item);
|
|
814
|
-
indexMap.add(tagIndex);
|
|
815
|
-
minIndex = Math.min(minIndex, index);
|
|
816
|
-
maxIndex = Math.max(maxIndex, index);
|
|
817
|
-
continue;
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
this.resetTag(tagName);
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
if (revised.length) {
|
|
825
|
-
const tagCount = this._tagCount[tagName];
|
|
826
|
-
const nextCount = tagCount + offset + 1;
|
|
827
|
-
if (elements.length) {
|
|
828
|
-
if (documentIndex < minIndex) {
|
|
829
|
-
for (const item of revised) {
|
|
830
|
-
item.tagIndex = 0;
|
|
831
|
-
item.tagCount = nextCount;
|
|
832
|
-
}
|
|
833
|
-
return;
|
|
834
|
-
}
|
|
835
|
-
if (documentIndex > maxIndex) {
|
|
836
|
-
for (const item of revised) {
|
|
837
|
-
item.tagIndex = tagCount;
|
|
838
|
-
item.tagCount = nextCount;
|
|
839
|
-
}
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
if (indexMap.size === tagCount) {
|
|
843
|
-
let i = tagCount, last = true;
|
|
844
|
-
indexMap.clear();
|
|
845
|
-
for (const item of elements) {
|
|
846
|
-
let tagIndex = item.tagIndex;
|
|
847
|
-
if (item.index > documentIndex) {
|
|
848
|
-
tagIndex += offset + 1;
|
|
849
|
-
last = false;
|
|
850
|
-
}
|
|
851
|
-
indexMap.add(tagIndex);
|
|
852
|
-
}
|
|
853
|
-
if (!last) {
|
|
854
|
-
while (indexMap.has(i)) {
|
|
855
|
-
--i;
|
|
856
|
-
}
|
|
857
|
-
i -= offset;
|
|
858
|
-
}
|
|
859
|
-
for (const target of revised) {
|
|
860
|
-
target.tagIndex = i;
|
|
861
|
-
target.tagCount = tagCount + offset + 1;
|
|
862
|
-
}
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
const id = append ? append.id : revised[0].id?.[this.documentName];
|
|
867
|
-
if (id) {
|
|
868
|
-
const element = XmlWriter.findElement(this.source, (append || revised[0]), { document: this.documentName, id, tagCount: nextCount, parser: this.parser });
|
|
869
|
-
if (element) {
|
|
870
|
-
for (const target of revised) {
|
|
871
|
-
target.tagIndex = element.tagIndex;
|
|
872
|
-
target.tagCount = element.tagCount;
|
|
873
|
-
}
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
this.resetTag(tagName);
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
resetTag(tagName) {
|
|
882
|
-
for (const item of this.elements) {
|
|
883
|
-
if (item.tagName === tagName) {
|
|
884
|
-
resetTagPosition(item);
|
|
885
|
-
item.index = -1;
|
|
886
|
-
}
|
|
887
|
-
const append = item.append;
|
|
888
|
-
if (append?.tagName === tagName) {
|
|
889
|
-
delete append.tagCount;
|
|
890
|
-
const nextSibling = append.nextSibling;
|
|
891
|
-
if (isIndex(nextSibling)) {
|
|
892
|
-
delete append.nextSibling;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
delete this._tagCount[tagName];
|
|
897
|
-
}
|
|
898
|
-
ignoreTag(value) {
|
|
899
|
-
if (Array.isArray(value)) {
|
|
900
|
-
this.ignoreTagGroup = value;
|
|
901
|
-
return;
|
|
902
|
-
}
|
|
903
|
-
let tagName = this.ignoreTagName || '';
|
|
904
|
-
if (tagName) {
|
|
905
|
-
if (value[0] !== '|' && tagName[tagName.length - 1] !== '|') {
|
|
906
|
-
tagName += '|';
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
else if (value[0] === '|') {
|
|
910
|
-
value = value.substring(1);
|
|
911
|
-
}
|
|
912
|
-
this.ignoreTagName = tagName + value;
|
|
913
|
-
this._patternIgnore = null;
|
|
914
|
-
}
|
|
915
|
-
resetPosition(startIndex) {
|
|
916
|
-
const rootName = this.rootName;
|
|
917
|
-
this.elements.forEach(item => deletePosition(item, rootName, startIndex));
|
|
918
|
-
}
|
|
919
|
-
close() {
|
|
920
|
-
const source = this.source;
|
|
921
|
-
this.source = '';
|
|
922
|
-
this.elements.length = 0;
|
|
923
|
-
return source;
|
|
924
|
-
}
|
|
925
|
-
getElementById(id, ignoreCase = false, options) {
|
|
926
|
-
let tagName, tagVoid;
|
|
927
|
-
if (options) {
|
|
928
|
-
({ tagName, tagVoid } = options);
|
|
929
|
-
}
|
|
930
|
-
const source = this.source;
|
|
931
|
-
const match = new RegExp(`<(${tagName && escapeTagName(tagName) || '[^\\s>]+'})${PATTERN_TAGOPEN}+?${(0, types_1.escapePattern)(this.nameOfId)}="${(0, types_1.escapePattern)(id)}"`, ignoreCase ? 'i' : '').exec(source);
|
|
932
|
-
if (match) {
|
|
933
|
-
tagName || (tagName = match[1]);
|
|
934
|
-
const startIndex = match.index;
|
|
935
|
-
let endIndex = -1, closeTag = 0;
|
|
936
|
-
if (!tagVoid) {
|
|
937
|
-
[endIndex, closeTag] = findCloseIndex(source, tagName, startIndex + match[0].length, ignoreCase);
|
|
938
|
-
}
|
|
939
|
-
if (closeTag === 0) {
|
|
940
|
-
endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
941
|
-
}
|
|
942
|
-
if (endIndex !== -1) {
|
|
943
|
-
return { tagName, id, outerXml: source.substring(startIndex, endIndex + 1), startIndex, endIndex, ignoreCase };
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
getElementsByTagName(tagName, ignoreCase = false, options) {
|
|
948
|
-
var _a;
|
|
949
|
-
let tagVoid;
|
|
950
|
-
if (options) {
|
|
951
|
-
({ tagVoid } = options);
|
|
952
|
-
}
|
|
953
|
-
const source = this.source;
|
|
954
|
-
const invalid = this.getInvalidArea();
|
|
955
|
-
const result = [];
|
|
956
|
-
const patternId = this.patternId;
|
|
957
|
-
const flags = ignoreCase ? 'gi' : 'g';
|
|
958
|
-
const pattern = CACHE_TAGNAME[_a = tagName + flags + '3'] || (CACHE_TAGNAME[_a] = new RegExp(`<${escapeTagName(tagName) + PATTERN_TAGOPEN}*>`, flags));
|
|
959
|
-
pattern.lastIndex = 0;
|
|
960
|
-
let match;
|
|
961
|
-
while (match = pattern.exec(source)) {
|
|
962
|
-
const startIndex = match.index;
|
|
963
|
-
let outerXml = match[0], endIndex = startIndex + outerXml.length - 1;
|
|
964
|
-
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
965
|
-
const id = patternId.exec(outerXml)?.[1];
|
|
966
|
-
if (!tagVoid) {
|
|
967
|
-
const [index, closeTag] = findCloseIndex(source, tagName, endIndex + 1, ignoreCase);
|
|
968
|
-
if (index !== -1) {
|
|
969
|
-
outerXml = source.substring(startIndex, index + 1);
|
|
970
|
-
endIndex = index;
|
|
971
|
-
}
|
|
972
|
-
else if (closeTag > 0) {
|
|
973
|
-
continue;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
result.push({ tagName, id, outerXml, startIndex, endIndex, ignoreCase });
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
return result;
|
|
980
|
-
}
|
|
981
|
-
setRawString(targetXml, outerXml) {
|
|
982
|
-
const startIndex = this.source.indexOf(targetXml);
|
|
983
|
-
return startIndex !== -1 ? this.spliceRawString({ startIndex, endIndex: startIndex + targetXml.length - 1, outerXml }) : '';
|
|
984
|
-
}
|
|
985
|
-
getRawString(index) {
|
|
986
|
-
return this.source.substring(index.startIndex, index.endIndex + 1);
|
|
987
|
-
}
|
|
988
|
-
spliceRawString(content, reset = true) {
|
|
989
|
-
const { startIndex, endIndex, outerXml } = content;
|
|
990
|
-
if (reset) {
|
|
991
|
-
this.resetPosition(startIndex);
|
|
992
|
-
}
|
|
993
|
-
++this.modifyCount;
|
|
994
|
-
return this.source = this.source.substring(0, startIndex) + outerXml + this.source.substring(endIndex + 1);
|
|
995
|
-
}
|
|
996
|
-
getComments() {
|
|
997
|
-
return this._invalidContent ? this._invalidContent.filter(item => item.type === 'comment') : null;
|
|
998
|
-
}
|
|
999
|
-
hasErrors() {
|
|
1000
|
-
return this.errors.length > 0;
|
|
1001
|
-
}
|
|
1002
|
-
reset() {
|
|
1003
|
-
this.modifyCount = 0;
|
|
1004
|
-
this.failCount = 0;
|
|
1005
|
-
this.errors.length = 0;
|
|
1006
|
-
this.resetPosition();
|
|
1007
|
-
}
|
|
1008
|
-
get newId() {
|
|
1009
|
-
return (0, types_1.generateUUID)();
|
|
1010
|
-
}
|
|
1011
|
-
get patternId() {
|
|
1012
|
-
return this._patternId || (this._patternId = getPatternId(this.nameOfId));
|
|
1013
|
-
}
|
|
1014
|
-
get patternIgnore() {
|
|
1015
|
-
return this.ignoreTagName ? this._patternIgnore || (this._patternIgnore = new RegExp(`^(?:${this.ignoreTagName})$`, this.ignoreCaseTagName ? 'i' : '')) : null;
|
|
1016
|
-
}
|
|
1017
|
-
set source(value) {
|
|
1018
|
-
if (value !== this._source) {
|
|
1019
|
-
this._source = value;
|
|
1020
|
-
++this.modifyCount;
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
get source() {
|
|
1024
|
-
return this._source;
|
|
1025
|
-
}
|
|
1026
|
-
get modified() {
|
|
1027
|
-
return this.modifyCount > 0;
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
exports.XmlWriter = XmlWriter;
|
|
1031
|
-
class XmlElement {
|
|
1032
|
-
static writeAttributes(attrs, escapeEntities) {
|
|
1033
|
-
let result = '';
|
|
1034
|
-
for (const [key, value] of attrs) {
|
|
1035
|
-
if (value === undefined) {
|
|
1036
|
-
continue;
|
|
1037
|
-
}
|
|
1038
|
-
result += ' ' + key;
|
|
1039
|
-
if (value === null) {
|
|
1040
|
-
continue;
|
|
1041
|
-
}
|
|
1042
|
-
result += '="' + (typeof value === 'string' ? escapeEntities ? XmlWriter.escapeXmlString(value) : value.replace(/"/g, '"') : module_1.default.asString(value)) + '"';
|
|
1043
|
-
}
|
|
1044
|
-
return result;
|
|
1045
|
-
}
|
|
1046
|
-
constructor(documentName, node, attributes, tagVoid = false, parser) {
|
|
1047
|
-
this.documentName = documentName;
|
|
1048
|
-
this.node = node;
|
|
1049
|
-
this.newline = '\n';
|
|
1050
|
-
this.TAG_VOID = [];
|
|
1051
|
-
this._modified = true;
|
|
1052
|
-
this._tagName = '';
|
|
1053
|
-
this._innerXml = '';
|
|
1054
|
-
this._remove = false;
|
|
1055
|
-
this._tagVoid = false;
|
|
1056
|
-
this._prevTagName = null;
|
|
1057
|
-
this._prevInnerXml = null;
|
|
1058
|
-
this._append = undefined;
|
|
1059
|
-
this._tagOffset = undefined;
|
|
1060
|
-
this._attributes = new Map();
|
|
1061
|
-
if ((0, types_1.isObject)(tagVoid)) {
|
|
1062
|
-
({ tagVoid = false, parser } = tagVoid);
|
|
1063
|
-
}
|
|
1064
|
-
if (parser) {
|
|
1065
|
-
this.parser = parser;
|
|
1066
|
-
}
|
|
1067
|
-
const { dynamic, ignoreCase = false } = node;
|
|
1068
|
-
const attrs = this._attributes;
|
|
1069
|
-
applyAttributes(attrs, node.attributes, ignoreCase);
|
|
1070
|
-
applyAttributes(attrs, attributes, ignoreCase);
|
|
1071
|
-
this._ignoreCase = ignoreCase;
|
|
1072
|
-
if (!node.append) {
|
|
1073
|
-
this._modified = attrs.size > 0;
|
|
1074
|
-
if (node.outerXml) {
|
|
1075
|
-
const [tagStart, innerXml, isVoid] = this.parseOuterXml(node.outerXml, tagVoid);
|
|
1076
|
-
let source = tagStart, match;
|
|
1077
|
-
while (match = REGEXP_ATTRVALUE.exec(tagStart)) {
|
|
1078
|
-
const attr = ignoreCase ? match[1].toLowerCase() : match[1];
|
|
1079
|
-
if (!attrs.has(attr)) {
|
|
1080
|
-
attrs.set(attr, match[2] || match[3] || match[4] || '');
|
|
1081
|
-
}
|
|
1082
|
-
source = source.replace(match[0], '');
|
|
1083
|
-
}
|
|
1084
|
-
while (match = REGEXP_ATTRNAME.exec(source)) {
|
|
1085
|
-
const attr = ignoreCase ? match[1].toLowerCase() : match[1];
|
|
1086
|
-
if (!attrs.has(attr)) {
|
|
1087
|
-
attrs.set(attr, null);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
if (!dynamic) {
|
|
1091
|
-
this._innerXml = innerXml;
|
|
1092
|
-
}
|
|
1093
|
-
this._tagVoid = isVoid;
|
|
1094
|
-
REGEXP_ATTRVALUE.lastIndex = 0;
|
|
1095
|
-
REGEXP_ATTRNAME.lastIndex = 0;
|
|
1096
|
-
}
|
|
1097
|
-
else if (tagVoid) {
|
|
1098
|
-
this._tagVoid = true;
|
|
1099
|
-
}
|
|
1100
|
-
else if (!dynamic && node.innerXml) {
|
|
1101
|
-
this._innerXml = node.innerXml;
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
setAppend(value) {
|
|
1106
|
-
if (this._append = value) {
|
|
1107
|
-
this._modified = true;
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
parseOuterXml(value = this.node.outerXml, tagVoid) {
|
|
1111
|
-
let tagStart, innerXml;
|
|
1112
|
-
if (value) {
|
|
1113
|
-
const endIndex = XmlWriter.findCloseTag(value) + 1;
|
|
1114
|
-
if (endIndex !== 0) {
|
|
1115
|
-
if (endIndex === value.length) {
|
|
1116
|
-
return [value, '', true];
|
|
1117
|
-
}
|
|
1118
|
-
let lastIndex = -1;
|
|
1119
|
-
if (tagVoid === true || (lastIndex = value.lastIndexOf('<')) && lastIndex < endIndex) {
|
|
1120
|
-
return [value.substring(0, endIndex), '', true];
|
|
1121
|
-
}
|
|
1122
|
-
tagStart = value.substring(0, endIndex);
|
|
1123
|
-
innerXml = value.substring(endIndex, lastIndex);
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
return [tagStart || `<${this.tagName}>`, innerXml || '', false];
|
|
1127
|
-
}
|
|
1128
|
-
getTagOffset(replacement, options = {}) {
|
|
1129
|
-
if (!this.tagVoid || this._prevTagName && !this.TAG_VOID.includes(this._prevTagName)) {
|
|
1130
|
-
options.parser || (options.parser = this.parser);
|
|
1131
|
-
if (!this.node.append) {
|
|
1132
|
-
return XmlWriter.getTagOffset(this.innerXml, replacement, options);
|
|
1133
|
-
}
|
|
1134
|
-
if (replacement) {
|
|
1135
|
-
return XmlWriter.getTagOffset(replacement, options);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
setAttribute(name, value) {
|
|
1140
|
-
if (this._attributes.get(this._ignoreCase ? name = name.toLowerCase() : name) !== value) {
|
|
1141
|
-
this._attributes.set(name, value);
|
|
1142
|
-
this._modified = true;
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
getAttribute(name) {
|
|
1146
|
-
let result = this._attributes.get(this._ignoreCase ? name = name.toLowerCase() : name);
|
|
1147
|
-
if (result) {
|
|
1148
|
-
return result;
|
|
1149
|
-
}
|
|
1150
|
-
if (this.node.append && name === this.nameOfId) {
|
|
1151
|
-
if (result = XmlWriter.getNodeId(this.node, this.documentName)) {
|
|
1152
|
-
return result;
|
|
1153
|
-
}
|
|
1154
|
-
const outerXml = this.node.outerXml;
|
|
1155
|
-
if (outerXml) {
|
|
1156
|
-
const index = XmlWriter.findCloseTag(outerXml);
|
|
1157
|
-
if (index !== -1) {
|
|
1158
|
-
return this.patternId.exec(outerXml.substring(0, index))?.[1] || '';
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
return '';
|
|
1163
|
-
}
|
|
1164
|
-
removeAttribute(...names) {
|
|
1165
|
-
const attrs = this._attributes;
|
|
1166
|
-
for (let name of names) {
|
|
1167
|
-
if (attrs.has(this._ignoreCase ? name = name.toLowerCase() : name)) {
|
|
1168
|
-
attrs.delete(name);
|
|
1169
|
-
this._modified = true;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
hasAttribute(name) {
|
|
1174
|
-
return this._attributes.has(this._ignoreCase ? name.toLowerCase() : name);
|
|
1175
|
-
}
|
|
1176
|
-
replace(source, options) {
|
|
1177
|
-
let { startIndex, endIndex } = options, leading = '', outerXml = '', trailing = '';
|
|
1178
|
-
if (options.remove) {
|
|
1179
|
-
let i = endIndex, ch;
|
|
1180
|
-
while (XmlWriter.isSpace(ch = source[i++])) {
|
|
1181
|
-
trailing += ch;
|
|
1182
|
-
if (ch === '\n') {
|
|
1183
|
-
break;
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
i = startIndex - 1;
|
|
1187
|
-
while (XmlWriter.isSpace(ch = source[i--])) {
|
|
1188
|
-
leading = ch + leading;
|
|
1189
|
-
}
|
|
1190
|
-
startIndex -= leading.length;
|
|
1191
|
-
endIndex += trailing.length + 1;
|
|
1192
|
-
leading = '';
|
|
1193
|
-
}
|
|
1194
|
-
else {
|
|
1195
|
-
if (options.append) {
|
|
1196
|
-
let i = startIndex - 1, ch, newline;
|
|
1197
|
-
while (XmlWriter.isSpace(ch = source[i--])) {
|
|
1198
|
-
if (ch === '\n') {
|
|
1199
|
-
newline = true;
|
|
1200
|
-
break;
|
|
1201
|
-
}
|
|
1202
|
-
leading = ch + leading;
|
|
1203
|
-
}
|
|
1204
|
-
if (!options.append.prepend) {
|
|
1205
|
-
endIndex += 2;
|
|
1206
|
-
startIndex = endIndex;
|
|
1207
|
-
if (!newline) {
|
|
1208
|
-
leading = this.newline + leading;
|
|
1209
|
-
trailing = this.newline;
|
|
1210
|
-
}
|
|
1211
|
-
else {
|
|
1212
|
-
switch (source[endIndex]) {
|
|
1213
|
-
case '\n':
|
|
1214
|
-
break;
|
|
1215
|
-
case '\r':
|
|
1216
|
-
if (source[endIndex + 1] === '\n') {
|
|
1217
|
-
break;
|
|
1218
|
-
}
|
|
1219
|
-
default:
|
|
1220
|
-
trailing = this.newline;
|
|
1221
|
-
break;
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
else {
|
|
1226
|
-
trailing = this.newline + leading;
|
|
1227
|
-
endIndex = startIndex;
|
|
1228
|
-
leading = '';
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
else {
|
|
1232
|
-
++endIndex;
|
|
1233
|
-
}
|
|
1234
|
-
outerXml = this.outerXml;
|
|
1235
|
-
const node = this.node;
|
|
1236
|
-
node.startIndex = startIndex + leading.length;
|
|
1237
|
-
node.endIndex = node.startIndex + outerXml.length - 1;
|
|
1238
|
-
}
|
|
1239
|
-
return [source.substring(0, startIndex) + leading + outerXml + trailing + source.substring(endIndex), outerXml];
|
|
1240
|
-
}
|
|
1241
|
-
write(source, invalid) {
|
|
1242
|
-
var _a, _b;
|
|
1243
|
-
if (!this._modified) {
|
|
1244
|
-
return ['', ''];
|
|
1245
|
-
}
|
|
1246
|
-
const { node, remove, append } = this;
|
|
1247
|
-
const getResult = (startIndex, endIndex) => this.replace(source, { remove, append, startIndex, endIndex });
|
|
1248
|
-
if (this.hasPosition()) {
|
|
1249
|
-
return getResult(node.startIndex, node.endIndex);
|
|
1250
|
-
}
|
|
1251
|
-
const { tagName, tagIndex = -1, tagCount = Infinity, ignoreCase } = node;
|
|
1252
|
-
const id = this.id;
|
|
1253
|
-
const flags = ignoreCase ? 'gi' : 'g';
|
|
1254
|
-
const hasId = (startIndex, endIndex) => source.substring(startIndex, endIndex).indexOf(id) !== -1;
|
|
1255
|
-
const errorResult = () => ['', '', (0, types_1.errorValue)('Element was not found', tagName.toUpperCase() + (isIndex(tagIndex) ? ' @ ' + tagIndex : ''))];
|
|
1256
|
-
let position;
|
|
1257
|
-
if (this.TAG_VOID.includes(tagName)) {
|
|
1258
|
-
const openTag = [];
|
|
1259
|
-
const pattern = CACHE_TAGNAME[_a = tagName + flags + '1'] || (CACHE_TAGNAME[_a] = new RegExp(`<${escapeTagName(tagName)}[\\s|>]`, flags));
|
|
1260
|
-
let openCount = 0, match;
|
|
1261
|
-
pattern.lastIndex = 0;
|
|
1262
|
-
while (match = pattern.exec(source)) {
|
|
1263
|
-
const startIndex = match.index;
|
|
1264
|
-
const endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
1265
|
-
if (endIndex === -1) {
|
|
1266
|
-
break;
|
|
1267
|
-
}
|
|
1268
|
-
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
1269
|
-
if (id && hasId(startIndex, endIndex)) {
|
|
1270
|
-
return getResult(startIndex, endIndex);
|
|
1271
|
-
}
|
|
1272
|
-
openCount = openTag.push([startIndex, endIndex]);
|
|
1273
|
-
}
|
|
1274
|
-
pattern.lastIndex = endIndex;
|
|
1275
|
-
}
|
|
1276
|
-
if (openCount === tagCount && isIndex(tagIndex)) {
|
|
1277
|
-
return getResult(...openTag[tagIndex]);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
else if (id || isIndex(tagIndex) && isCount(tagCount)) {
|
|
1281
|
-
complete: {
|
|
1282
|
-
const pattern = CACHE_TAGNAME[_b = tagName + flags + '2'] || (CACHE_TAGNAME[_b] = new RegExp(`<(?:${escapeTagName(tagName)}[\\s|>]|/${escapeTagName(tagName)}\\s*>)`, flags));
|
|
1283
|
-
const openTag = [];
|
|
1284
|
-
let openCount = 0, found, match;
|
|
1285
|
-
pattern.lastIndex = 0;
|
|
1286
|
-
while (match = pattern.exec(source)) {
|
|
1287
|
-
const startIndex = match.index;
|
|
1288
|
-
if (match[0][1] === '/') {
|
|
1289
|
-
const endIndex = startIndex + match[0].length - 1;
|
|
1290
|
-
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
1291
|
-
for (let i = 0; i < openCount; ++i) {
|
|
1292
|
-
const tag = openTag[i];
|
|
1293
|
-
if (tag[1] === -1 && --tag[2] === 0) {
|
|
1294
|
-
if (tag[3]) {
|
|
1295
|
-
position = { startIndex: tag[0], endIndex };
|
|
1296
|
-
break complete;
|
|
1297
|
-
}
|
|
1298
|
-
tag[1] = endIndex;
|
|
1299
|
-
break;
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
else {
|
|
1305
|
-
const endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
1306
|
-
if (endIndex === -1) {
|
|
1307
|
-
break;
|
|
1308
|
-
}
|
|
1309
|
-
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
1310
|
-
for (let i = 0; i < openCount; ++i) {
|
|
1311
|
-
const tag = openTag[i];
|
|
1312
|
-
if (tag[1] === -1) {
|
|
1313
|
-
++tag[2];
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
openCount = openTag.push([startIndex, -1, 1, id && !found && hasId(startIndex, endIndex) ? (found = true) && 1 : 0]);
|
|
1317
|
-
}
|
|
1318
|
-
pattern.lastIndex = endIndex;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
if (openTag.length === tagCount && isIndex(tagIndex)) {
|
|
1322
|
-
const tag = openTag[tagIndex];
|
|
1323
|
-
position = { startIndex: tag[0], endIndex: tag[1] };
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
if (position || (position = this.findIndexOf(source))) {
|
|
1328
|
-
if (remove) {
|
|
1329
|
-
position.remove = true;
|
|
1330
|
-
}
|
|
1331
|
-
else if (append) {
|
|
1332
|
-
position.append = append;
|
|
1333
|
-
}
|
|
1334
|
-
return this.replace(source, position);
|
|
1335
|
-
}
|
|
1336
|
-
return errorResult();
|
|
1337
|
-
}
|
|
1338
|
-
save(source, invalid) {
|
|
1339
|
-
const [output, outerXml, error] = this.write(source, invalid || XmlWriter.getCommentsAndCDATA(source));
|
|
1340
|
-
if (output) {
|
|
1341
|
-
this.node.outerXml = outerXml;
|
|
1342
|
-
this.reset();
|
|
1343
|
-
}
|
|
1344
|
-
return [output, error];
|
|
1345
|
-
}
|
|
1346
|
-
reset() {
|
|
1347
|
-
this._append = undefined;
|
|
1348
|
-
this._tagOffset = undefined;
|
|
1349
|
-
this._prevTagName = null;
|
|
1350
|
-
this._prevInnerXml = null;
|
|
1351
|
-
this._modified = false;
|
|
1352
|
-
}
|
|
1353
|
-
hasModifiedContent() {
|
|
1354
|
-
return typeof this._prevInnerXml === 'string';
|
|
1355
|
-
}
|
|
1356
|
-
getOuterContent() {
|
|
1357
|
-
const attributes = Array.from(this._attributes);
|
|
1358
|
-
const append = this.node.append;
|
|
1359
|
-
if (append) {
|
|
1360
|
-
const idKey = this.nameOfId;
|
|
1361
|
-
const items = attributes.filter(item => item[0] !== idKey);
|
|
1362
|
-
if (append.id) {
|
|
1363
|
-
items.push([idKey, append.id]);
|
|
1364
|
-
}
|
|
1365
|
-
return [append.tagName, items, append.textContent || ''];
|
|
1366
|
-
}
|
|
1367
|
-
return [this.tagName, attributes, this.innerXml];
|
|
1368
|
-
}
|
|
1369
|
-
getInnerOffset(tagName) {
|
|
1370
|
-
return this._tagOffset?.[tagName] || 0;
|
|
1371
|
-
}
|
|
1372
|
-
hasPosition() {
|
|
1373
|
-
return isIndex(this.node.startIndex) && isIndex(this.node.endIndex);
|
|
1374
|
-
}
|
|
1375
|
-
set id(value) {
|
|
1376
|
-
this.setAttribute(this.nameOfId, value);
|
|
1377
|
-
}
|
|
1378
|
-
get id() {
|
|
1379
|
-
return this.getAttribute(this.nameOfId) || '';
|
|
1380
|
-
}
|
|
1381
|
-
set tagName(value) {
|
|
1382
|
-
if (this.node.ignoreCase) {
|
|
1383
|
-
value = value.toLowerCase();
|
|
1384
|
-
}
|
|
1385
|
-
const tagName = this.tagName;
|
|
1386
|
-
if (value !== tagName) {
|
|
1387
|
-
this._prevTagName || (this._prevTagName = tagName);
|
|
1388
|
-
this._tagName = value;
|
|
1389
|
-
if (this.TAG_VOID.includes(value)) {
|
|
1390
|
-
this.innerXml = '';
|
|
1391
|
-
}
|
|
1392
|
-
this._modified = true;
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
get tagName() {
|
|
1396
|
-
const tagName = this._tagName || this.node.tagName;
|
|
1397
|
-
return this.node.ignoreCase ? tagName.toLowerCase() : tagName;
|
|
1398
|
-
}
|
|
1399
|
-
get tagVoid() {
|
|
1400
|
-
return this._tagVoid || this.TAG_VOID.includes(this.tagName);
|
|
1401
|
-
}
|
|
1402
|
-
set innerXml(value) {
|
|
1403
|
-
if (!this.tagVoid && value !== this._innerXml) {
|
|
1404
|
-
this._prevInnerXml = this._innerXml;
|
|
1405
|
-
this._tagOffset = this.getTagOffset(value, { ignoreCase: this.ignoreCase });
|
|
1406
|
-
this._innerXml = value;
|
|
1407
|
-
this._modified = true;
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
get innerXml() {
|
|
1411
|
-
return this._innerXml;
|
|
1412
|
-
}
|
|
1413
|
-
set tagOffset(value) {
|
|
1414
|
-
this._tagOffset = value && Object.keys(value).length ? value : undefined;
|
|
1415
|
-
}
|
|
1416
|
-
get tagOffset() {
|
|
1417
|
-
return this._tagOffset;
|
|
1418
|
-
}
|
|
1419
|
-
get ignoreCase() {
|
|
1420
|
-
return this._ignoreCase;
|
|
1421
|
-
}
|
|
1422
|
-
set remove(value) {
|
|
1423
|
-
if (value && !this._append) {
|
|
1424
|
-
const tagOffset = this.getTagOffset('', { ignoreCase: this.ignoreCase });
|
|
1425
|
-
if (tagOffset) {
|
|
1426
|
-
for (const tagName in tagOffset) {
|
|
1427
|
-
tagOffset[tagName] *= -1;
|
|
1428
|
-
}
|
|
1429
|
-
this._tagOffset = tagOffset;
|
|
1430
|
-
}
|
|
1431
|
-
this._remove = true;
|
|
1432
|
-
this._modified = true;
|
|
1433
|
-
}
|
|
1434
|
-
else {
|
|
1435
|
-
this._tagOffset = undefined;
|
|
1436
|
-
this._remove = false;
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
get remove() {
|
|
1440
|
-
return this._remove;
|
|
1441
|
-
}
|
|
1442
|
-
get append() {
|
|
1443
|
-
return this._append;
|
|
1444
|
-
}
|
|
1445
|
-
get patternId() {
|
|
1446
|
-
return this._patternId || (this._patternId = getPatternId(this.nameOfId));
|
|
1447
|
-
}
|
|
1448
|
-
get modified() {
|
|
1449
|
-
return this._modified;
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
exports.XmlElement = XmlElement;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.XmlElement = exports.XmlWriter = exports.IGNORE_FLAG = void 0;
|
|
4
|
+
const htmlparser2 = require("htmlparser2");
|
|
5
|
+
const domhandler = require("domhandler");
|
|
6
|
+
const domutils = require("domutils");
|
|
7
|
+
const types_1 = require("../../types");
|
|
8
|
+
const module_1 = require("../../module");
|
|
9
|
+
var IGNORE_FLAG;
|
|
10
|
+
(function (IGNORE_FLAG) {
|
|
11
|
+
IGNORE_FLAG[IGNORE_FLAG["NONE"] = 0] = "NONE";
|
|
12
|
+
IGNORE_FLAG[IGNORE_FLAG["INTERIOR"] = 1] = "INTERIOR";
|
|
13
|
+
IGNORE_FLAG[IGNORE_FLAG["LOCATOR"] = 2] = "LOCATOR";
|
|
14
|
+
})(IGNORE_FLAG = exports.IGNORE_FLAG || (exports.IGNORE_FLAG = {}));
|
|
15
|
+
const Parser = htmlparser2.Parser;
|
|
16
|
+
const DomHandler = domhandler.DomHandler;
|
|
17
|
+
const CACHE_TAGNAME = {};
|
|
18
|
+
const CACHE_NAMEOFID = {};
|
|
19
|
+
const CACHE_TAGOFFSET = {};
|
|
20
|
+
const PATTERN_ATTRNAME = '([^\\s=>]+)';
|
|
21
|
+
const PATTERN_ATTRVALUE = `=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]*))`;
|
|
22
|
+
const PATTERN_TAGNAME = '[A-Za-z][\\w-]*';
|
|
23
|
+
const PATTERN_TAGOPEN = `(?:[^=>]|${PATTERN_ATTRVALUE})`;
|
|
24
|
+
const PATTERN_QUOTEVALUE = `(?:"[^"]+"|'[^']+')`;
|
|
25
|
+
const PATTERN_COMMENT = '/\\*[\\S\\s]*?\\*/';
|
|
26
|
+
const PATTERN_TRAILINGSPACE = '[ \\t]*((?:\\r?\\n)*)';
|
|
27
|
+
const REGEXP_ATTRNAME = new RegExp('\\s+' + PATTERN_ATTRNAME, 'g');
|
|
28
|
+
const REGEXP_ATTRVALUE = new RegExp(PATTERN_ATTRNAME + '\\s*' + PATTERN_ATTRVALUE, 'g');
|
|
29
|
+
const REGEXP_TAGATTR = new RegExp(`<${PATTERN_TAGNAME}\\s+(${PATTERN_TAGOPEN}*)>`, 'g');
|
|
30
|
+
const REGEXP_ESCAPECHAR = /[-|\\{}()[\]^$+*?.]/g;
|
|
31
|
+
function applyAttributes(attrs, data, ignoreCase) {
|
|
32
|
+
for (const key in data) {
|
|
33
|
+
attrs.set(ignoreCase && typeof key === 'string' ? key.toLowerCase() : key.toString(), data[key]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function deletePosition(item, rootName, startIndex) {
|
|
37
|
+
if (isIndex(item.startIndex) && (!isIndex(startIndex) || item.startIndex >= startIndex) && item.tagName !== rootName) {
|
|
38
|
+
item.startIndex = undefined;
|
|
39
|
+
item.endIndex = undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function updateTagName(item, tagName) {
|
|
43
|
+
item.tagName = tagName;
|
|
44
|
+
item.tagIndex = Infinity;
|
|
45
|
+
item.tagCount = 0;
|
|
46
|
+
}
|
|
47
|
+
function resetTagPosition(item) {
|
|
48
|
+
item.tagIndex = -1;
|
|
49
|
+
item.tagCount = 0;
|
|
50
|
+
}
|
|
51
|
+
function findCloseIndex(source, tagName, lastIndex, ignoreCase) {
|
|
52
|
+
var _a;
|
|
53
|
+
const flags = ignoreCase ? 'gi' : 'g';
|
|
54
|
+
const pattern = CACHE_TAGNAME[_a = tagName + flags + '0'] || (CACHE_TAGNAME[_a] = new RegExp(`<(?:${escapeTagName(tagName)}\\s*|/${escapeTagName(tagName)}\\s*>)`, flags));
|
|
55
|
+
pattern.lastIndex = lastIndex;
|
|
56
|
+
let openTag = 1, closeTag = 0, match;
|
|
57
|
+
while (match = pattern.exec(source)) {
|
|
58
|
+
if (match[0][1] !== '/') {
|
|
59
|
+
++openTag;
|
|
60
|
+
}
|
|
61
|
+
else if (openTag === ++closeTag) {
|
|
62
|
+
return [match.index + match[0].length - 1, closeTag];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return [-1, closeTag];
|
|
66
|
+
}
|
|
67
|
+
function isValidIndex(items, startIndex, endIndex) {
|
|
68
|
+
for (let i = 0, length = items.length; i < length; ++i) {
|
|
69
|
+
const item = items[i];
|
|
70
|
+
if (startIndex > item.startIndex && endIndex < item.endIndex) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function getNewlineCount(value) {
|
|
77
|
+
let result = 0;
|
|
78
|
+
for (let i = 0, length = value.length; i < length; ++i) {
|
|
79
|
+
if (value[i] === '\n') {
|
|
80
|
+
++result;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function getParserDOM(source, parser) {
|
|
86
|
+
const result = {};
|
|
87
|
+
new Parser(new DomHandler((err, dom) => {
|
|
88
|
+
if (!err) {
|
|
89
|
+
result.outDom = dom;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
result.error = err;
|
|
93
|
+
}
|
|
94
|
+
}, { withStartIndices: true, withEndIndices: true }), { decodeEntities: false, ...parser }).end(source);
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
const isIndex = (value) => typeof value === 'number' && value >= 0 && value !== Infinity;
|
|
98
|
+
const isCount = (value) => typeof value === 'number' && value > 0 && value !== Infinity;
|
|
99
|
+
const getPatternId = (name) => CACHE_NAMEOFID[name] || (CACHE_NAMEOFID[name] = new RegExp(`\\s${(0, types_1.escapePattern)(name)}="([^"]+)"`));
|
|
100
|
+
const escapeTagName = (value) => value.replace(REGEXP_ESCAPECHAR, capture => capture === '-' ? '\\x2d' : '\\' + capture);
|
|
101
|
+
class XmlWriter {
|
|
102
|
+
static get PATTERN_ATTRNAME() { return PATTERN_ATTRNAME; }
|
|
103
|
+
static get PATTERN_ATTRVALUE() { return PATTERN_ATTRVALUE; }
|
|
104
|
+
static get PATTERN_TAGNAME() { return PATTERN_TAGNAME; }
|
|
105
|
+
static get PATTERN_TAGOPEN() { return PATTERN_TAGOPEN; }
|
|
106
|
+
static get PATTERN_QUOTEVALUE() { return PATTERN_QUOTEVALUE; }
|
|
107
|
+
static get PATTERN_COMMENT() { return PATTERN_COMMENT; }
|
|
108
|
+
static get PATTERN_TRAILINGSPACE() { return PATTERN_TRAILINGSPACE; }
|
|
109
|
+
static replaceMatch(match, source, content = '', options) {
|
|
110
|
+
if (typeof content === 'number') {
|
|
111
|
+
content = match[content] || '';
|
|
112
|
+
}
|
|
113
|
+
let index = match.index, leading = index > 0 ? source.substring(0, index) : '', trailing = source.substring(index + match[0].length);
|
|
114
|
+
if (options) {
|
|
115
|
+
let pattern;
|
|
116
|
+
if ((0, types_1.isPlainObject)(options)) {
|
|
117
|
+
let trimLeading, trimTrailing;
|
|
118
|
+
({ pattern, trimLeading, trimTrailing } = options);
|
|
119
|
+
if (trimLeading) {
|
|
120
|
+
const length = leading.length;
|
|
121
|
+
leading = leading.trimEnd();
|
|
122
|
+
index -= length - leading.length;
|
|
123
|
+
}
|
|
124
|
+
if (trimTrailing) {
|
|
125
|
+
trailing = trailing.trimStart();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
pattern = options;
|
|
130
|
+
}
|
|
131
|
+
if (pattern) {
|
|
132
|
+
pattern.lastIndex = index + content.length;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return leading + content + trailing;
|
|
136
|
+
}
|
|
137
|
+
static escapeXmlString(value, ampersand) {
|
|
138
|
+
return value.replace(ampersand ? /[<>"'&]/g : /[<>"']|&([^#A-Za-z]|$)/g, capture => {
|
|
139
|
+
switch (capture) {
|
|
140
|
+
case '<':
|
|
141
|
+
return '<';
|
|
142
|
+
case '>':
|
|
143
|
+
return '>';
|
|
144
|
+
case '"':
|
|
145
|
+
return '"';
|
|
146
|
+
case "'":
|
|
147
|
+
return ''';
|
|
148
|
+
default:
|
|
149
|
+
return '&' + (capture[1] || '');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
static escapeAttributes(source) {
|
|
154
|
+
let match;
|
|
155
|
+
while (match = REGEXP_TAGATTR.exec(source)) {
|
|
156
|
+
let output = match[0], modified, subMatch;
|
|
157
|
+
while (subMatch = REGEXP_ATTRVALUE.exec(match[1])) {
|
|
158
|
+
const value = subMatch[2] || subMatch[3] || subMatch[4];
|
|
159
|
+
if (value) {
|
|
160
|
+
const escaped = this.escapeXmlString(value);
|
|
161
|
+
if (escaped !== value) {
|
|
162
|
+
output = output.replace(subMatch[0], subMatch[1] + `="${escaped}"`);
|
|
163
|
+
modified = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (modified) {
|
|
168
|
+
source = this.replaceMatch(match, source, output, REGEXP_TAGATTR);
|
|
169
|
+
}
|
|
170
|
+
REGEXP_ATTRVALUE.lastIndex = 0;
|
|
171
|
+
}
|
|
172
|
+
REGEXP_TAGATTR.lastIndex = 0;
|
|
173
|
+
return source;
|
|
174
|
+
}
|
|
175
|
+
static getNewlineString(leading, trailing, newline) {
|
|
176
|
+
const value = leading + trailing;
|
|
177
|
+
return getNewlineCount(value) > 1 ? newline || (value.indexOf('\r') !== -1 ? '\r\n' : '\n') : '';
|
|
178
|
+
}
|
|
179
|
+
static findCloseTag(source, startIndex = 0) {
|
|
180
|
+
const length = source.length;
|
|
181
|
+
const start = [];
|
|
182
|
+
for (let i = startIndex, quote = ''; i < length; ++i) {
|
|
183
|
+
let ch = source[i];
|
|
184
|
+
if (ch === '=') {
|
|
185
|
+
if (!quote) {
|
|
186
|
+
while (this.isSpace(ch = source[++i])) { }
|
|
187
|
+
switch (ch) {
|
|
188
|
+
case '"':
|
|
189
|
+
quote = '"';
|
|
190
|
+
start.push(i);
|
|
191
|
+
break;
|
|
192
|
+
case "'":
|
|
193
|
+
quote = "'";
|
|
194
|
+
start.push(i);
|
|
195
|
+
break;
|
|
196
|
+
case '>':
|
|
197
|
+
return i;
|
|
198
|
+
default:
|
|
199
|
+
while (!this.isSpace(ch = source[++i])) {
|
|
200
|
+
if (ch === '>') {
|
|
201
|
+
return i;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (ch === quote) {
|
|
209
|
+
quote = '';
|
|
210
|
+
}
|
|
211
|
+
else if (ch === '>' && !quote) {
|
|
212
|
+
return i;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (start.length) {
|
|
216
|
+
for (const index of start.reverse()) {
|
|
217
|
+
for (let j = index + 1; j < length; ++j) {
|
|
218
|
+
if (source[j] === '>') {
|
|
219
|
+
return j;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return -1;
|
|
225
|
+
}
|
|
226
|
+
static findElement(source, node, options = {}) {
|
|
227
|
+
const { document, id, tagCount = node.tagCount, locatorAttr, parser } = options;
|
|
228
|
+
let outDom = options.outDom, error;
|
|
229
|
+
if (!(0, types_1.isArray)(outDom)) {
|
|
230
|
+
({ outDom, error } = getParserDOM(source, parser));
|
|
231
|
+
}
|
|
232
|
+
const result = { element: null, error: null };
|
|
233
|
+
if (error) {
|
|
234
|
+
result.error = error;
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
const nodes = domutils.getElementsByTagName(node.tagName, outDom, true);
|
|
238
|
+
if (!parser?.xmlMode) {
|
|
239
|
+
nodes.filter(item => item.next && item.next.startIndex <= item.endIndex).forEach(item => {
|
|
240
|
+
for (let i = 0, length = nodes.length; i < length; ++i) {
|
|
241
|
+
const element = nodes[i];
|
|
242
|
+
let current = element.prev;
|
|
243
|
+
while (current) {
|
|
244
|
+
if (current === item.next) {
|
|
245
|
+
item.endIndex = element.endIndex;
|
|
246
|
+
nodes.splice(i, 1);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
current = current.prev;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
let index = -1;
|
|
255
|
+
if (document && id) {
|
|
256
|
+
const documentId = this.getNameOfId(document);
|
|
257
|
+
if ((index = nodes.findIndex(elem => elem.attribs[documentId] === id)) !== -1) {
|
|
258
|
+
result.element = nodes[index];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!result.element) {
|
|
262
|
+
const locator = node.locator;
|
|
263
|
+
if (locator && locatorAttr) {
|
|
264
|
+
const { element } = this.locateElement(source, locator, locatorAttr, { parser, outDom });
|
|
265
|
+
if (element?.tagName === node.tagName) {
|
|
266
|
+
result.element = element;
|
|
267
|
+
index = nodes.findIndex(item => item === element);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if ((!result.element || index === -1) && nodes.length === tagCount) {
|
|
271
|
+
const tagIndex = node.tagIndex;
|
|
272
|
+
if (tagIndex !== undefined && nodes[tagIndex]) {
|
|
273
|
+
result.element = nodes[tagIndex];
|
|
274
|
+
index = tagIndex;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (result.element) {
|
|
279
|
+
result.tagName = node.tagName;
|
|
280
|
+
result.tagIndex = index;
|
|
281
|
+
result.tagCount = index !== -1 ? nodes.length : Infinity;
|
|
282
|
+
}
|
|
283
|
+
result.parser = parser;
|
|
284
|
+
result.outDom = outDom;
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
static locateElement(source, locator, attr, options = {}) {
|
|
288
|
+
let { parser, outDom } = options, error;
|
|
289
|
+
if (!(0, types_1.isArray)(outDom)) {
|
|
290
|
+
({ outDom, error } = getParserDOM(source, parser));
|
|
291
|
+
}
|
|
292
|
+
if (error) {
|
|
293
|
+
return { element: null, error };
|
|
294
|
+
}
|
|
295
|
+
const { id, count = 1, index = 0 } = locator;
|
|
296
|
+
const nodes = domutils.findAll(elem => elem.attribs[attr] === id, outDom);
|
|
297
|
+
const element = nodes.length === count && nodes[index] || null;
|
|
298
|
+
return { element, parser, outDom, error: null };
|
|
299
|
+
}
|
|
300
|
+
static getTagOffset(source, replacement, options) {
|
|
301
|
+
var _a, _b;
|
|
302
|
+
if ((0, types_1.isObject)(replacement)) {
|
|
303
|
+
options = replacement;
|
|
304
|
+
replacement = undefined;
|
|
305
|
+
}
|
|
306
|
+
let parser;
|
|
307
|
+
if (options) {
|
|
308
|
+
const { ignoreCase, ignoreTagName, ignoreTagGroup } = options;
|
|
309
|
+
if (ignoreTagName) {
|
|
310
|
+
const flags = ignoreCase ? 'gi' : 'g';
|
|
311
|
+
source = source.replace(CACHE_TAGOFFSET[_a = ignoreTagName + flags] || (CACHE_TAGOFFSET[_a] = new RegExp(`<(?:${ignoreTagName.split('|').map(value => escapeTagName(value)).join('|')})${XmlWriter.PATTERN_TAGOPEN}*>[\\S\\s]*?<\\/\\1\\s*>`, flags)), '');
|
|
312
|
+
}
|
|
313
|
+
if (ignoreTagGroup) {
|
|
314
|
+
for (let i = 0, length = ignoreTagGroup.length; i < length; i += 2) {
|
|
315
|
+
const start = ignoreTagGroup[i];
|
|
316
|
+
const end = ignoreTagGroup[i + 1];
|
|
317
|
+
if (end) {
|
|
318
|
+
source = source.replace(CACHE_TAGOFFSET[_b = start + end] || (CACHE_TAGOFFSET[_b] = new RegExp(escapeTagName(start) + '[\\S\\s]*?' + escapeTagName(end), 'g')), '');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
parser = options.parser;
|
|
323
|
+
}
|
|
324
|
+
const result = {};
|
|
325
|
+
new Parser({
|
|
326
|
+
onopentag(name) {
|
|
327
|
+
result[name] = (result[name] || 0) + 1;
|
|
328
|
+
}
|
|
329
|
+
}, { xmlMode: true, decodeEntities: false, lowerCaseAttributeNames: false, ...parser }).end(source);
|
|
330
|
+
if ((0, types_1.isString)(replacement)) {
|
|
331
|
+
const next = this.getTagOffset(replacement, options);
|
|
332
|
+
let modified;
|
|
333
|
+
for (const tagName of new Set([...Object.keys(result), ...Object.keys(next)])) {
|
|
334
|
+
if (result[tagName] !== next[tagName]) {
|
|
335
|
+
result[tagName] = (next[tagName] || 0) - (result[tagName] || 0);
|
|
336
|
+
modified = true;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (!modified) {
|
|
340
|
+
return {};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
static getNodeId(node, document) {
|
|
346
|
+
return node.id?.[document] || '';
|
|
347
|
+
}
|
|
348
|
+
static getNameOfId(document) {
|
|
349
|
+
return `data-${document}-id`;
|
|
350
|
+
}
|
|
351
|
+
static getCommentsAndCDATA(source, tagPattern = '', ignoreCase, stripXml) {
|
|
352
|
+
var _a, _b;
|
|
353
|
+
let tagGroup;
|
|
354
|
+
if (stripXml) {
|
|
355
|
+
if (typeof tagPattern !== 'string') {
|
|
356
|
+
tagPattern = '';
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
else if (Array.isArray(tagPattern)) {
|
|
360
|
+
if (tagPattern.every(item => typeof item === 'string')) {
|
|
361
|
+
tagGroup = tagPattern;
|
|
362
|
+
tagPattern = '';
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
[tagPattern = '', tagGroup] = tagPattern;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const result = [];
|
|
369
|
+
const flags = ignoreCase ? 'gi' : 'g';
|
|
370
|
+
let pattern = CACHE_TAGNAME[_a = tagPattern + flags] || (CACHE_TAGNAME[_a] = new RegExp(`<(?:(!--[\\S\\s]*?--)|(!\\[CDATA\\[[\\S\\s]*?\\]\\])` + (tagPattern ? '|' + `(${tagPattern})${PATTERN_TAGOPEN}*` : '') + ')>', flags)), match;
|
|
371
|
+
pattern.lastIndex = 0;
|
|
372
|
+
while (match = pattern.exec(source)) {
|
|
373
|
+
if (stripXml) {
|
|
374
|
+
source = this.replaceMatch(match, source, '', { pattern, trimLeading: true });
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const type = match[1] && 'comment' || match[2] && 'cdata' || 'node';
|
|
378
|
+
const startIndex = match.index;
|
|
379
|
+
let endIndex = startIndex + match[0].length;
|
|
380
|
+
if (type !== 'node') {
|
|
381
|
+
result.push({ type, outerXml: match[0], startIndex, endIndex: endIndex - 1 });
|
|
382
|
+
}
|
|
383
|
+
else if ((endIndex = findCloseIndex(source, match[3], endIndex, ignoreCase)[0]) !== -1) {
|
|
384
|
+
result.push({ type, outerXml: source.substring(startIndex, endIndex + 1), startIndex, endIndex });
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (stripXml) {
|
|
388
|
+
return source;
|
|
389
|
+
}
|
|
390
|
+
if (tagGroup) {
|
|
391
|
+
for (let i = 0, length = tagGroup.length; i < length; i += 2) {
|
|
392
|
+
const start = tagGroup[i];
|
|
393
|
+
const end = tagGroup[i + 1];
|
|
394
|
+
if (end) {
|
|
395
|
+
pattern = CACHE_TAGNAME[_b = start + end] || (CACHE_TAGNAME[_b] = new RegExp(escapeTagName(start) + '[\\S\\s]*?' + escapeTagName(end), 'g'));
|
|
396
|
+
pattern.lastIndex = 0;
|
|
397
|
+
while (match = pattern.exec(source)) {
|
|
398
|
+
const startIndex = match.index;
|
|
399
|
+
result.push({ type: 'block', outerXml: match[0], startIndex, endIndex: startIndex + match[0].length - 1 });
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
static isEqual(node, other, document, ignoreCase) {
|
|
407
|
+
if (typeof document === 'boolean') {
|
|
408
|
+
ignoreCase = document;
|
|
409
|
+
document = undefined;
|
|
410
|
+
}
|
|
411
|
+
if (node === other) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
const { index, tagName, tagIndex, tagCount, id } = node;
|
|
415
|
+
if ((ignoreCase ? tagName.toLowerCase() === other.tagName.toLowerCase() : tagName === other.tagName) && (index === other.index && isIndex(index) || tagIndex === other.tagIndex && tagCount === other.tagCount && isIndex(tagIndex) && isCount(tagCount))) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
return document && other.id && id?.[document] ? id[document] === other.id[document] : false;
|
|
419
|
+
}
|
|
420
|
+
static isIndex(value) {
|
|
421
|
+
return isIndex(value);
|
|
422
|
+
}
|
|
423
|
+
static isCount(value) {
|
|
424
|
+
return isCount(value);
|
|
425
|
+
}
|
|
426
|
+
static isSpace(ch) {
|
|
427
|
+
return ch === ' ' || ch === '\n' || ch === '\t' || ch === '\f' || ch === '\r' || ch === '\v';
|
|
428
|
+
}
|
|
429
|
+
constructor(documentName, source, elements, options) {
|
|
430
|
+
this.documentName = documentName;
|
|
431
|
+
this.elements = elements;
|
|
432
|
+
this.modifyCount = 0;
|
|
433
|
+
this.failCount = 0;
|
|
434
|
+
this.errors = [];
|
|
435
|
+
this.newline = '\n';
|
|
436
|
+
this._tagCount = Object.create(null);
|
|
437
|
+
this._hasInvalidContent = true;
|
|
438
|
+
this._ignoreFlag = 0;
|
|
439
|
+
this._appendCount = 0;
|
|
440
|
+
this._invalidContent = null;
|
|
441
|
+
this._patternId = null;
|
|
442
|
+
this._patternIgnore = null;
|
|
443
|
+
this._writeStartIndex = -1;
|
|
444
|
+
this._source = source;
|
|
445
|
+
this.parser = options?.parser;
|
|
446
|
+
}
|
|
447
|
+
init(offsetMap) {
|
|
448
|
+
const appending = [];
|
|
449
|
+
const rootName = this.rootName;
|
|
450
|
+
for (const item of this.elements) {
|
|
451
|
+
if (item.append) {
|
|
452
|
+
appending.push(item);
|
|
453
|
+
}
|
|
454
|
+
if (isCount(item.tagCount)) {
|
|
455
|
+
const tagName = item.tagName;
|
|
456
|
+
item.tagCount += offsetMap?.[tagName] || 0;
|
|
457
|
+
this._tagCount[tagName] = item.tagCount;
|
|
458
|
+
}
|
|
459
|
+
deletePosition(item, rootName);
|
|
460
|
+
}
|
|
461
|
+
if (appending.length) {
|
|
462
|
+
this.insertNodes(appending);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
ignoreFlag(...values) {
|
|
466
|
+
values.forEach(value => this._ignoreFlag |= value);
|
|
467
|
+
}
|
|
468
|
+
getInvalidArea() {
|
|
469
|
+
if ((this._ignoreFlag & IGNORE_FLAG.INTERIOR) === 0 && this._hasInvalidContent) {
|
|
470
|
+
const startIndex = this._writeStartIndex;
|
|
471
|
+
if (isIndex(startIndex) && this._invalidContent && !this._invalidContent.some(item => item.startIndex >= startIndex)) {
|
|
472
|
+
return this._invalidContent;
|
|
473
|
+
}
|
|
474
|
+
const result = XmlWriter.getCommentsAndCDATA(this.source, this.ignoreTagGroup ? [this.ignoreTagName || '', this.ignoreTagGroup] : this.ignoreTagName, this.ignoreCaseTagName);
|
|
475
|
+
this._invalidContent = result;
|
|
476
|
+
if (result.length) {
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
this._hasInvalidContent = false;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
insertNodes(nodes) {
|
|
483
|
+
nodes.sort((a, b) => {
|
|
484
|
+
if (!isIndex(a.index) || !isIndex(b.index)) {
|
|
485
|
+
return 0;
|
|
486
|
+
}
|
|
487
|
+
if (a.index === b.index) {
|
|
488
|
+
const itemA = a.append;
|
|
489
|
+
const itemB = b.append;
|
|
490
|
+
if (itemA && itemB) {
|
|
491
|
+
const prependA = itemA.prepend;
|
|
492
|
+
const prependB = itemB.prepend;
|
|
493
|
+
if (prependA && prependB) {
|
|
494
|
+
return itemA.order - itemB.order;
|
|
495
|
+
}
|
|
496
|
+
if (!prependA && !prependB) {
|
|
497
|
+
return itemB.order - itemA.order;
|
|
498
|
+
}
|
|
499
|
+
if (prependA || prependB === false) {
|
|
500
|
+
return 1;
|
|
501
|
+
}
|
|
502
|
+
if (prependA === false) {
|
|
503
|
+
return -1;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return b.index - a.index;
|
|
508
|
+
})
|
|
509
|
+
.forEach(item => this.append(item));
|
|
510
|
+
}
|
|
511
|
+
fromNode(node, append) {
|
|
512
|
+
const element = this.newElement(node);
|
|
513
|
+
if (append) {
|
|
514
|
+
const tagName = append.tagName;
|
|
515
|
+
if (!(tagName in this._tagCount) && isCount(append.tagCount)) {
|
|
516
|
+
this._tagCount[tagName] = append.tagCount;
|
|
517
|
+
}
|
|
518
|
+
append.id || (append.id = this.newId);
|
|
519
|
+
element.setAppend(append);
|
|
520
|
+
}
|
|
521
|
+
return element;
|
|
522
|
+
}
|
|
523
|
+
append(node) {
|
|
524
|
+
const append = node.append;
|
|
525
|
+
if (append) {
|
|
526
|
+
if (node.ignoreCase) {
|
|
527
|
+
append.tagName = append.tagName.toLowerCase();
|
|
528
|
+
}
|
|
529
|
+
const element = this.fromNode(node, append);
|
|
530
|
+
if (this.write(element)) {
|
|
531
|
+
delete node.append;
|
|
532
|
+
++this._appendCount;
|
|
533
|
+
return element;
|
|
534
|
+
}
|
|
535
|
+
const index = this.elements.findIndex(item => item === node);
|
|
536
|
+
if (index !== -1) {
|
|
537
|
+
this.elements.splice(index, 1);
|
|
538
|
+
}
|
|
539
|
+
++this.failCount;
|
|
540
|
+
this.errors.push((0, types_1.errorValue)(`Unable to ${append.prepend ? 'prepend' : 'append'} element`, append.tagName.toUpperCase() + (isIndex(node.index) ? ' @ ' + node.index : '')));
|
|
541
|
+
}
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
write(element) {
|
|
545
|
+
if (!element.modified) {
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
const { node, append } = element;
|
|
549
|
+
element.parser || (element.parser = this.parser);
|
|
550
|
+
element.newline = this.newline;
|
|
551
|
+
let output, outerXml = '', error;
|
|
552
|
+
if (element.hasPosition()) {
|
|
553
|
+
[output, outerXml] = element.replace(this.source, { startIndex: node.startIndex, endIndex: node.endIndex, append, remove: element.remove });
|
|
554
|
+
}
|
|
555
|
+
else if (element.tagName !== this.rootName) {
|
|
556
|
+
[output, outerXml, error] = element.write(this.source, this.getInvalidArea());
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
error = new Error('Root source position not found');
|
|
560
|
+
}
|
|
561
|
+
if (output) {
|
|
562
|
+
this.source = output;
|
|
563
|
+
if (!this.elements.includes(node)) {
|
|
564
|
+
const index = this.elements.findIndex(item => XmlWriter.isEqual(node, item));
|
|
565
|
+
if (index !== -1) {
|
|
566
|
+
this.elements.splice(index, 1, node);
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
this.elements.push(node);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (append) {
|
|
573
|
+
const { tagName, id, textContent = '', prepend, nextSibling } = append;
|
|
574
|
+
if (!prepend) {
|
|
575
|
+
node.index = nextSibling ?? -1;
|
|
576
|
+
}
|
|
577
|
+
(node.id || (node.id = {}))[this.documentName] = id;
|
|
578
|
+
element.id = id;
|
|
579
|
+
element.innerXml = textContent;
|
|
580
|
+
const offset = element.getInnerOffset(tagName);
|
|
581
|
+
if (tagName !== node.tagName) {
|
|
582
|
+
updateTagName(node, tagName);
|
|
583
|
+
this.indexTag(tagName, append, offset);
|
|
584
|
+
}
|
|
585
|
+
else if (!prepend && isIndex(node.tagIndex) && isCount(node.tagCount)) {
|
|
586
|
+
++node.tagIndex;
|
|
587
|
+
++node.tagCount;
|
|
588
|
+
}
|
|
589
|
+
this.increment([node], offset);
|
|
590
|
+
}
|
|
591
|
+
else if (element.remove) {
|
|
592
|
+
this.decrement(node, element.getInnerOffset(element.tagName), true);
|
|
593
|
+
}
|
|
594
|
+
else if (element.tagName !== node.tagName) {
|
|
595
|
+
this.renameTag(node, element.tagName);
|
|
596
|
+
}
|
|
597
|
+
this.update(node, outerXml, append, element.tagOffset);
|
|
598
|
+
if (element.innerXml && !element.remove && (element.hasModifiedContent() || this.patternIgnore?.test(element.tagName))) {
|
|
599
|
+
this._hasInvalidContent = true;
|
|
600
|
+
this._writeStartIndex = -1;
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
this._writeStartIndex = node.startIndex;
|
|
604
|
+
}
|
|
605
|
+
element.reset();
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
if (node.locator && (this._ignoreFlag & IGNORE_FLAG.LOCATOR)) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
if (error) {
|
|
612
|
+
this.errors.push(error);
|
|
613
|
+
}
|
|
614
|
+
++this.failCount;
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
save() {
|
|
618
|
+
this.reset();
|
|
619
|
+
return this.source;
|
|
620
|
+
}
|
|
621
|
+
update(node, outerXml, append, offsetMap) {
|
|
622
|
+
const { elements, documentName, rootName } = this;
|
|
623
|
+
const { tagName, startIndex, endIndex } = node;
|
|
624
|
+
const items = [];
|
|
625
|
+
const updateMap = offsetMap && Object.keys(offsetMap).length > 0;
|
|
626
|
+
const index = isIndex(node.index) ? node.index : -1;
|
|
627
|
+
const hasIndex = isIndex(startIndex) && isIndex(endIndex);
|
|
628
|
+
for (let i = 0; i < elements.length; ++i) {
|
|
629
|
+
const item = elements[i];
|
|
630
|
+
if (XmlWriter.isEqual(node, item, documentName, this.ignoreCaseTagName)) {
|
|
631
|
+
if (!outerXml) {
|
|
632
|
+
item.removed = true;
|
|
633
|
+
elements.splice(i--, 1);
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
item.outerXml = outerXml;
|
|
637
|
+
if (hasIndex) {
|
|
638
|
+
item.startIndex = startIndex;
|
|
639
|
+
item.endIndex = endIndex;
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
deletePosition(item, rootName);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
deletePosition(item, rootName, startIndex);
|
|
647
|
+
}
|
|
648
|
+
if (updateMap && item.append) {
|
|
649
|
+
items.push([true, item.index, item.append]);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (updateMap) {
|
|
653
|
+
items.push(...elements.map(item => [false, item.index, item]));
|
|
654
|
+
for (const name in offsetMap) {
|
|
655
|
+
const offset = offsetMap[name];
|
|
656
|
+
invalid: {
|
|
657
|
+
if (offset) {
|
|
658
|
+
const updated = !!append && tagName === name;
|
|
659
|
+
let offsetCount = -1;
|
|
660
|
+
for (const [appended, itemIndex, item] of items) {
|
|
661
|
+
if (item.tagName === name) {
|
|
662
|
+
if (index !== -1 && isIndex(itemIndex) && isCount(item.tagCount)) {
|
|
663
|
+
if (appended) {
|
|
664
|
+
if (updated) {
|
|
665
|
+
item.tagCount = this._tagCount[name];
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
item.tagCount += offset;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
else if (isIndex(item.tagIndex)) {
|
|
672
|
+
if (!updated) {
|
|
673
|
+
if (itemIndex > index) {
|
|
674
|
+
item.tagIndex += offset;
|
|
675
|
+
}
|
|
676
|
+
item.tagCount += offset;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
offsetCount = Infinity;
|
|
681
|
+
}
|
|
682
|
+
if (offsetCount === -1) {
|
|
683
|
+
offsetCount = item.tagCount;
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
if (offsetCount === item.tagCount) {
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
this.resetTag(name);
|
|
691
|
+
break invalid;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
if (offsetCount !== -1) {
|
|
695
|
+
this._tagCount[name] = offsetCount;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
increment(nodes, offset = 0) {
|
|
703
|
+
let { index, tagName, tagIndex } = nodes[0];
|
|
704
|
+
if (!isIndex(index)) {
|
|
705
|
+
index = -1;
|
|
706
|
+
}
|
|
707
|
+
let invalid = index === -1;
|
|
708
|
+
++offset;
|
|
709
|
+
for (const item of this.elements) {
|
|
710
|
+
if (!nodes.includes(item)) {
|
|
711
|
+
if (item.tagName === tagName) {
|
|
712
|
+
if (!invalid && isIndex(tagIndex) && isIndex(item.tagIndex) && isCount(item.tagCount)) {
|
|
713
|
+
if (item.tagIndex >= tagIndex) {
|
|
714
|
+
item.tagIndex += offset;
|
|
715
|
+
}
|
|
716
|
+
item.tagCount += offset;
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
invalid = true;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (isIndex(item.index) && index !== -1) {
|
|
724
|
+
const append = item.append;
|
|
725
|
+
if (item.index >= index) {
|
|
726
|
+
++item.index;
|
|
727
|
+
}
|
|
728
|
+
if (append) {
|
|
729
|
+
const nextSibling = append.nextSibling;
|
|
730
|
+
if (isIndex(nextSibling) && nextSibling >= index) {
|
|
731
|
+
append.nextSibling = nextSibling + 1;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (invalid) {
|
|
738
|
+
this.resetTag(tagName);
|
|
739
|
+
}
|
|
740
|
+
else if (tagName in this._tagCount) {
|
|
741
|
+
this._tagCount[tagName] += offset;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
decrement(node, offset = 0, remove) {
|
|
745
|
+
const { elements, documentName } = this;
|
|
746
|
+
const { tagName, tagIndex, tagCount } = node;
|
|
747
|
+
const hasIndex = isIndex(tagIndex) && isCount(tagCount);
|
|
748
|
+
const result = [];
|
|
749
|
+
++offset;
|
|
750
|
+
for (let i = 0; i < elements.length; ++i) {
|
|
751
|
+
const item = elements[i];
|
|
752
|
+
if (item.tagName === tagName) {
|
|
753
|
+
if (XmlWriter.isEqual(node, item, documentName, this.ignoreCaseTagName)) {
|
|
754
|
+
if (remove) {
|
|
755
|
+
item.removed = true;
|
|
756
|
+
elements.splice(i--, 1);
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
result.push(item);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
else if (hasIndex && isIndex(item.tagIndex) && isCount(item.tagCount)) {
|
|
763
|
+
if (item.tagIndex > tagIndex) {
|
|
764
|
+
item.tagIndex -= offset;
|
|
765
|
+
}
|
|
766
|
+
item.tagCount -= offset;
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
this.resetTag(tagName);
|
|
770
|
+
return [];
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (tagName in this._tagCount) {
|
|
775
|
+
this._tagCount[tagName] -= offset;
|
|
776
|
+
}
|
|
777
|
+
return result;
|
|
778
|
+
}
|
|
779
|
+
renameTag(node, tagName) {
|
|
780
|
+
const revised = this.decrement(node);
|
|
781
|
+
if (revised.includes(node)) {
|
|
782
|
+
if (tagName in this._tagCount) {
|
|
783
|
+
revised.forEach(item => updateTagName(item, tagName));
|
|
784
|
+
this.indexTag(tagName);
|
|
785
|
+
this.increment(revised);
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
this.resetTag(tagName);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
node.tagName = tagName;
|
|
793
|
+
resetTagPosition(node);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
indexTag(tagName, append, offset = 0) {
|
|
797
|
+
if (tagName in this._tagCount) {
|
|
798
|
+
const elements = [];
|
|
799
|
+
const revised = [];
|
|
800
|
+
const indexMap = new Set();
|
|
801
|
+
let documentIndex = -1, minIndex = Infinity, maxIndex = -1;
|
|
802
|
+
for (const item of this.elements) {
|
|
803
|
+
if (item.tagName === tagName) {
|
|
804
|
+
const index = item.index;
|
|
805
|
+
if (isIndex(index)) {
|
|
806
|
+
const tagIndex = item.tagIndex;
|
|
807
|
+
if (tagIndex === Infinity) {
|
|
808
|
+
documentIndex = index;
|
|
809
|
+
revised.push(item);
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
if (isIndex(tagIndex)) {
|
|
813
|
+
elements.push(item);
|
|
814
|
+
indexMap.add(tagIndex);
|
|
815
|
+
minIndex = Math.min(minIndex, index);
|
|
816
|
+
maxIndex = Math.max(maxIndex, index);
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
this.resetTag(tagName);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
if (revised.length) {
|
|
825
|
+
const tagCount = this._tagCount[tagName];
|
|
826
|
+
const nextCount = tagCount + offset + 1;
|
|
827
|
+
if (elements.length) {
|
|
828
|
+
if (documentIndex < minIndex) {
|
|
829
|
+
for (const item of revised) {
|
|
830
|
+
item.tagIndex = 0;
|
|
831
|
+
item.tagCount = nextCount;
|
|
832
|
+
}
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
if (documentIndex > maxIndex) {
|
|
836
|
+
for (const item of revised) {
|
|
837
|
+
item.tagIndex = tagCount;
|
|
838
|
+
item.tagCount = nextCount;
|
|
839
|
+
}
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (indexMap.size === tagCount) {
|
|
843
|
+
let i = tagCount, last = true;
|
|
844
|
+
indexMap.clear();
|
|
845
|
+
for (const item of elements) {
|
|
846
|
+
let tagIndex = item.tagIndex;
|
|
847
|
+
if (item.index > documentIndex) {
|
|
848
|
+
tagIndex += offset + 1;
|
|
849
|
+
last = false;
|
|
850
|
+
}
|
|
851
|
+
indexMap.add(tagIndex);
|
|
852
|
+
}
|
|
853
|
+
if (!last) {
|
|
854
|
+
while (indexMap.has(i)) {
|
|
855
|
+
--i;
|
|
856
|
+
}
|
|
857
|
+
i -= offset;
|
|
858
|
+
}
|
|
859
|
+
for (const target of revised) {
|
|
860
|
+
target.tagIndex = i;
|
|
861
|
+
target.tagCount = tagCount + offset + 1;
|
|
862
|
+
}
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
const id = append ? append.id : revised[0].id?.[this.documentName];
|
|
867
|
+
if (id) {
|
|
868
|
+
const element = XmlWriter.findElement(this.source, (append || revised[0]), { document: this.documentName, id, tagCount: nextCount, parser: this.parser });
|
|
869
|
+
if (element) {
|
|
870
|
+
for (const target of revised) {
|
|
871
|
+
target.tagIndex = element.tagIndex;
|
|
872
|
+
target.tagCount = element.tagCount;
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
this.resetTag(tagName);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
resetTag(tagName) {
|
|
882
|
+
for (const item of this.elements) {
|
|
883
|
+
if (item.tagName === tagName) {
|
|
884
|
+
resetTagPosition(item);
|
|
885
|
+
item.index = -1;
|
|
886
|
+
}
|
|
887
|
+
const append = item.append;
|
|
888
|
+
if (append?.tagName === tagName) {
|
|
889
|
+
delete append.tagCount;
|
|
890
|
+
const nextSibling = append.nextSibling;
|
|
891
|
+
if (isIndex(nextSibling)) {
|
|
892
|
+
delete append.nextSibling;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
delete this._tagCount[tagName];
|
|
897
|
+
}
|
|
898
|
+
ignoreTag(value) {
|
|
899
|
+
if (Array.isArray(value)) {
|
|
900
|
+
this.ignoreTagGroup = value;
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
let tagName = this.ignoreTagName || '';
|
|
904
|
+
if (tagName) {
|
|
905
|
+
if (value[0] !== '|' && tagName[tagName.length - 1] !== '|') {
|
|
906
|
+
tagName += '|';
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
else if (value[0] === '|') {
|
|
910
|
+
value = value.substring(1);
|
|
911
|
+
}
|
|
912
|
+
this.ignoreTagName = tagName + value;
|
|
913
|
+
this._patternIgnore = null;
|
|
914
|
+
}
|
|
915
|
+
resetPosition(startIndex) {
|
|
916
|
+
const rootName = this.rootName;
|
|
917
|
+
this.elements.forEach(item => deletePosition(item, rootName, startIndex));
|
|
918
|
+
}
|
|
919
|
+
close() {
|
|
920
|
+
const source = this.source;
|
|
921
|
+
this.source = '';
|
|
922
|
+
this.elements.length = 0;
|
|
923
|
+
return source;
|
|
924
|
+
}
|
|
925
|
+
getElementById(id, ignoreCase = false, options) {
|
|
926
|
+
let tagName, tagVoid;
|
|
927
|
+
if (options) {
|
|
928
|
+
({ tagName, tagVoid } = options);
|
|
929
|
+
}
|
|
930
|
+
const source = this.source;
|
|
931
|
+
const match = new RegExp(`<(${tagName && escapeTagName(tagName) || '[^\\s>]+'})${PATTERN_TAGOPEN}+?${(0, types_1.escapePattern)(this.nameOfId)}="${(0, types_1.escapePattern)(id)}"`, ignoreCase ? 'i' : '').exec(source);
|
|
932
|
+
if (match) {
|
|
933
|
+
tagName || (tagName = match[1]);
|
|
934
|
+
const startIndex = match.index;
|
|
935
|
+
let endIndex = -1, closeTag = 0;
|
|
936
|
+
if (!tagVoid) {
|
|
937
|
+
[endIndex, closeTag] = findCloseIndex(source, tagName, startIndex + match[0].length, ignoreCase);
|
|
938
|
+
}
|
|
939
|
+
if (closeTag === 0) {
|
|
940
|
+
endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
941
|
+
}
|
|
942
|
+
if (endIndex !== -1) {
|
|
943
|
+
return { tagName, id, outerXml: source.substring(startIndex, endIndex + 1), startIndex, endIndex, ignoreCase };
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
getElementsByTagName(tagName, ignoreCase = false, options) {
|
|
948
|
+
var _a;
|
|
949
|
+
let tagVoid;
|
|
950
|
+
if (options) {
|
|
951
|
+
({ tagVoid } = options);
|
|
952
|
+
}
|
|
953
|
+
const source = this.source;
|
|
954
|
+
const invalid = this.getInvalidArea();
|
|
955
|
+
const result = [];
|
|
956
|
+
const patternId = this.patternId;
|
|
957
|
+
const flags = ignoreCase ? 'gi' : 'g';
|
|
958
|
+
const pattern = CACHE_TAGNAME[_a = tagName + flags + '3'] || (CACHE_TAGNAME[_a] = new RegExp(`<${escapeTagName(tagName) + PATTERN_TAGOPEN}*>`, flags));
|
|
959
|
+
pattern.lastIndex = 0;
|
|
960
|
+
let match;
|
|
961
|
+
while (match = pattern.exec(source)) {
|
|
962
|
+
const startIndex = match.index;
|
|
963
|
+
let outerXml = match[0], endIndex = startIndex + outerXml.length - 1;
|
|
964
|
+
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
965
|
+
const id = patternId.exec(outerXml)?.[1];
|
|
966
|
+
if (!tagVoid) {
|
|
967
|
+
const [index, closeTag] = findCloseIndex(source, tagName, endIndex + 1, ignoreCase);
|
|
968
|
+
if (index !== -1) {
|
|
969
|
+
outerXml = source.substring(startIndex, index + 1);
|
|
970
|
+
endIndex = index;
|
|
971
|
+
}
|
|
972
|
+
else if (closeTag > 0) {
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
result.push({ tagName, id, outerXml, startIndex, endIndex, ignoreCase });
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return result;
|
|
980
|
+
}
|
|
981
|
+
setRawString(targetXml, outerXml) {
|
|
982
|
+
const startIndex = this.source.indexOf(targetXml);
|
|
983
|
+
return startIndex !== -1 ? this.spliceRawString({ startIndex, endIndex: startIndex + targetXml.length - 1, outerXml }) : '';
|
|
984
|
+
}
|
|
985
|
+
getRawString(index) {
|
|
986
|
+
return this.source.substring(index.startIndex, index.endIndex + 1);
|
|
987
|
+
}
|
|
988
|
+
spliceRawString(content, reset = true) {
|
|
989
|
+
const { startIndex, endIndex, outerXml } = content;
|
|
990
|
+
if (reset) {
|
|
991
|
+
this.resetPosition(startIndex);
|
|
992
|
+
}
|
|
993
|
+
++this.modifyCount;
|
|
994
|
+
return this.source = this.source.substring(0, startIndex) + outerXml + this.source.substring(endIndex + 1);
|
|
995
|
+
}
|
|
996
|
+
getComments() {
|
|
997
|
+
return this._invalidContent ? this._invalidContent.filter(item => item.type === 'comment') : null;
|
|
998
|
+
}
|
|
999
|
+
hasErrors() {
|
|
1000
|
+
return this.errors.length > 0;
|
|
1001
|
+
}
|
|
1002
|
+
reset() {
|
|
1003
|
+
this.modifyCount = 0;
|
|
1004
|
+
this.failCount = 0;
|
|
1005
|
+
this.errors.length = 0;
|
|
1006
|
+
this.resetPosition();
|
|
1007
|
+
}
|
|
1008
|
+
get newId() {
|
|
1009
|
+
return (0, types_1.generateUUID)();
|
|
1010
|
+
}
|
|
1011
|
+
get patternId() {
|
|
1012
|
+
return this._patternId || (this._patternId = getPatternId(this.nameOfId));
|
|
1013
|
+
}
|
|
1014
|
+
get patternIgnore() {
|
|
1015
|
+
return this.ignoreTagName ? this._patternIgnore || (this._patternIgnore = new RegExp(`^(?:${this.ignoreTagName})$`, this.ignoreCaseTagName ? 'i' : '')) : null;
|
|
1016
|
+
}
|
|
1017
|
+
set source(value) {
|
|
1018
|
+
if (value !== this._source) {
|
|
1019
|
+
this._source = value;
|
|
1020
|
+
++this.modifyCount;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
get source() {
|
|
1024
|
+
return this._source;
|
|
1025
|
+
}
|
|
1026
|
+
get modified() {
|
|
1027
|
+
return this.modifyCount > 0;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
exports.XmlWriter = XmlWriter;
|
|
1031
|
+
class XmlElement {
|
|
1032
|
+
static writeAttributes(attrs, escapeEntities) {
|
|
1033
|
+
let result = '';
|
|
1034
|
+
for (const [key, value] of attrs) {
|
|
1035
|
+
if (value === undefined) {
|
|
1036
|
+
continue;
|
|
1037
|
+
}
|
|
1038
|
+
result += ' ' + key;
|
|
1039
|
+
if (value === null) {
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
result += '="' + (typeof value === 'string' ? escapeEntities ? XmlWriter.escapeXmlString(value) : value.replace(/"/g, '"') : module_1.default.asString(value)) + '"';
|
|
1043
|
+
}
|
|
1044
|
+
return result;
|
|
1045
|
+
}
|
|
1046
|
+
constructor(documentName, node, attributes, tagVoid = false, parser) {
|
|
1047
|
+
this.documentName = documentName;
|
|
1048
|
+
this.node = node;
|
|
1049
|
+
this.newline = '\n';
|
|
1050
|
+
this.TAG_VOID = [];
|
|
1051
|
+
this._modified = true;
|
|
1052
|
+
this._tagName = '';
|
|
1053
|
+
this._innerXml = '';
|
|
1054
|
+
this._remove = false;
|
|
1055
|
+
this._tagVoid = false;
|
|
1056
|
+
this._prevTagName = null;
|
|
1057
|
+
this._prevInnerXml = null;
|
|
1058
|
+
this._append = undefined;
|
|
1059
|
+
this._tagOffset = undefined;
|
|
1060
|
+
this._attributes = new Map();
|
|
1061
|
+
if ((0, types_1.isObject)(tagVoid)) {
|
|
1062
|
+
({ tagVoid = false, parser } = tagVoid);
|
|
1063
|
+
}
|
|
1064
|
+
if (parser) {
|
|
1065
|
+
this.parser = parser;
|
|
1066
|
+
}
|
|
1067
|
+
const { dynamic, ignoreCase = false } = node;
|
|
1068
|
+
const attrs = this._attributes;
|
|
1069
|
+
applyAttributes(attrs, node.attributes, ignoreCase);
|
|
1070
|
+
applyAttributes(attrs, attributes, ignoreCase);
|
|
1071
|
+
this._ignoreCase = ignoreCase;
|
|
1072
|
+
if (!node.append) {
|
|
1073
|
+
this._modified = attrs.size > 0;
|
|
1074
|
+
if (node.outerXml) {
|
|
1075
|
+
const [tagStart, innerXml, isVoid] = this.parseOuterXml(node.outerXml, tagVoid);
|
|
1076
|
+
let source = tagStart, match;
|
|
1077
|
+
while (match = REGEXP_ATTRVALUE.exec(tagStart)) {
|
|
1078
|
+
const attr = ignoreCase ? match[1].toLowerCase() : match[1];
|
|
1079
|
+
if (!attrs.has(attr)) {
|
|
1080
|
+
attrs.set(attr, match[2] || match[3] || match[4] || '');
|
|
1081
|
+
}
|
|
1082
|
+
source = source.replace(match[0], '');
|
|
1083
|
+
}
|
|
1084
|
+
while (match = REGEXP_ATTRNAME.exec(source)) {
|
|
1085
|
+
const attr = ignoreCase ? match[1].toLowerCase() : match[1];
|
|
1086
|
+
if (!attrs.has(attr)) {
|
|
1087
|
+
attrs.set(attr, null);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
if (!dynamic) {
|
|
1091
|
+
this._innerXml = innerXml;
|
|
1092
|
+
}
|
|
1093
|
+
this._tagVoid = isVoid;
|
|
1094
|
+
REGEXP_ATTRVALUE.lastIndex = 0;
|
|
1095
|
+
REGEXP_ATTRNAME.lastIndex = 0;
|
|
1096
|
+
}
|
|
1097
|
+
else if (tagVoid) {
|
|
1098
|
+
this._tagVoid = true;
|
|
1099
|
+
}
|
|
1100
|
+
else if (!dynamic && node.innerXml) {
|
|
1101
|
+
this._innerXml = node.innerXml;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
setAppend(value) {
|
|
1106
|
+
if (this._append = value) {
|
|
1107
|
+
this._modified = true;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
parseOuterXml(value = this.node.outerXml, tagVoid) {
|
|
1111
|
+
let tagStart, innerXml;
|
|
1112
|
+
if (value) {
|
|
1113
|
+
const endIndex = XmlWriter.findCloseTag(value) + 1;
|
|
1114
|
+
if (endIndex !== 0) {
|
|
1115
|
+
if (endIndex === value.length) {
|
|
1116
|
+
return [value, '', true];
|
|
1117
|
+
}
|
|
1118
|
+
let lastIndex = -1;
|
|
1119
|
+
if (tagVoid === true || (lastIndex = value.lastIndexOf('<')) && lastIndex < endIndex) {
|
|
1120
|
+
return [value.substring(0, endIndex), '', true];
|
|
1121
|
+
}
|
|
1122
|
+
tagStart = value.substring(0, endIndex);
|
|
1123
|
+
innerXml = value.substring(endIndex, lastIndex);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return [tagStart || `<${this.tagName}>`, innerXml || '', false];
|
|
1127
|
+
}
|
|
1128
|
+
getTagOffset(replacement, options = {}) {
|
|
1129
|
+
if (!this.tagVoid || this._prevTagName && !this.TAG_VOID.includes(this._prevTagName)) {
|
|
1130
|
+
options.parser || (options.parser = this.parser);
|
|
1131
|
+
if (!this.node.append) {
|
|
1132
|
+
return XmlWriter.getTagOffset(this.innerXml, replacement, options);
|
|
1133
|
+
}
|
|
1134
|
+
if (replacement) {
|
|
1135
|
+
return XmlWriter.getTagOffset(replacement, options);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
setAttribute(name, value) {
|
|
1140
|
+
if (this._attributes.get(this._ignoreCase ? name = name.toLowerCase() : name) !== value) {
|
|
1141
|
+
this._attributes.set(name, value);
|
|
1142
|
+
this._modified = true;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
getAttribute(name) {
|
|
1146
|
+
let result = this._attributes.get(this._ignoreCase ? name = name.toLowerCase() : name);
|
|
1147
|
+
if (result) {
|
|
1148
|
+
return result;
|
|
1149
|
+
}
|
|
1150
|
+
if (this.node.append && name === this.nameOfId) {
|
|
1151
|
+
if (result = XmlWriter.getNodeId(this.node, this.documentName)) {
|
|
1152
|
+
return result;
|
|
1153
|
+
}
|
|
1154
|
+
const outerXml = this.node.outerXml;
|
|
1155
|
+
if (outerXml) {
|
|
1156
|
+
const index = XmlWriter.findCloseTag(outerXml);
|
|
1157
|
+
if (index !== -1) {
|
|
1158
|
+
return this.patternId.exec(outerXml.substring(0, index))?.[1] || '';
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
return '';
|
|
1163
|
+
}
|
|
1164
|
+
removeAttribute(...names) {
|
|
1165
|
+
const attrs = this._attributes;
|
|
1166
|
+
for (let name of names) {
|
|
1167
|
+
if (attrs.has(this._ignoreCase ? name = name.toLowerCase() : name)) {
|
|
1168
|
+
attrs.delete(name);
|
|
1169
|
+
this._modified = true;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
hasAttribute(name) {
|
|
1174
|
+
return this._attributes.has(this._ignoreCase ? name.toLowerCase() : name);
|
|
1175
|
+
}
|
|
1176
|
+
replace(source, options) {
|
|
1177
|
+
let { startIndex, endIndex } = options, leading = '', outerXml = '', trailing = '';
|
|
1178
|
+
if (options.remove) {
|
|
1179
|
+
let i = endIndex, ch;
|
|
1180
|
+
while (XmlWriter.isSpace(ch = source[i++])) {
|
|
1181
|
+
trailing += ch;
|
|
1182
|
+
if (ch === '\n') {
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
i = startIndex - 1;
|
|
1187
|
+
while (XmlWriter.isSpace(ch = source[i--])) {
|
|
1188
|
+
leading = ch + leading;
|
|
1189
|
+
}
|
|
1190
|
+
startIndex -= leading.length;
|
|
1191
|
+
endIndex += trailing.length + 1;
|
|
1192
|
+
leading = '';
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
if (options.append) {
|
|
1196
|
+
let i = startIndex - 1, ch, newline;
|
|
1197
|
+
while (XmlWriter.isSpace(ch = source[i--])) {
|
|
1198
|
+
if (ch === '\n') {
|
|
1199
|
+
newline = true;
|
|
1200
|
+
break;
|
|
1201
|
+
}
|
|
1202
|
+
leading = ch + leading;
|
|
1203
|
+
}
|
|
1204
|
+
if (!options.append.prepend) {
|
|
1205
|
+
endIndex += 2;
|
|
1206
|
+
startIndex = endIndex;
|
|
1207
|
+
if (!newline) {
|
|
1208
|
+
leading = this.newline + leading;
|
|
1209
|
+
trailing = this.newline;
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
switch (source[endIndex]) {
|
|
1213
|
+
case '\n':
|
|
1214
|
+
break;
|
|
1215
|
+
case '\r':
|
|
1216
|
+
if (source[endIndex + 1] === '\n') {
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
default:
|
|
1220
|
+
trailing = this.newline;
|
|
1221
|
+
break;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
else {
|
|
1226
|
+
trailing = this.newline + leading;
|
|
1227
|
+
endIndex = startIndex;
|
|
1228
|
+
leading = '';
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
else {
|
|
1232
|
+
++endIndex;
|
|
1233
|
+
}
|
|
1234
|
+
outerXml = this.outerXml;
|
|
1235
|
+
const node = this.node;
|
|
1236
|
+
node.startIndex = startIndex + leading.length;
|
|
1237
|
+
node.endIndex = node.startIndex + outerXml.length - 1;
|
|
1238
|
+
}
|
|
1239
|
+
return [source.substring(0, startIndex) + leading + outerXml + trailing + source.substring(endIndex), outerXml];
|
|
1240
|
+
}
|
|
1241
|
+
write(source, invalid) {
|
|
1242
|
+
var _a, _b;
|
|
1243
|
+
if (!this._modified) {
|
|
1244
|
+
return ['', ''];
|
|
1245
|
+
}
|
|
1246
|
+
const { node, remove, append } = this;
|
|
1247
|
+
const getResult = (startIndex, endIndex) => this.replace(source, { remove, append, startIndex, endIndex });
|
|
1248
|
+
if (this.hasPosition()) {
|
|
1249
|
+
return getResult(node.startIndex, node.endIndex);
|
|
1250
|
+
}
|
|
1251
|
+
const { tagName, tagIndex = -1, tagCount = Infinity, ignoreCase } = node;
|
|
1252
|
+
const id = this.id;
|
|
1253
|
+
const flags = ignoreCase ? 'gi' : 'g';
|
|
1254
|
+
const hasId = (startIndex, endIndex) => source.substring(startIndex, endIndex).indexOf(id) !== -1;
|
|
1255
|
+
const errorResult = () => ['', '', (0, types_1.errorValue)('Element was not found', tagName.toUpperCase() + (isIndex(tagIndex) ? ' @ ' + tagIndex : ''))];
|
|
1256
|
+
let position;
|
|
1257
|
+
if (this.TAG_VOID.includes(tagName)) {
|
|
1258
|
+
const openTag = [];
|
|
1259
|
+
const pattern = CACHE_TAGNAME[_a = tagName + flags + '1'] || (CACHE_TAGNAME[_a] = new RegExp(`<${escapeTagName(tagName)}[\\s|>]`, flags));
|
|
1260
|
+
let openCount = 0, match;
|
|
1261
|
+
pattern.lastIndex = 0;
|
|
1262
|
+
while (match = pattern.exec(source)) {
|
|
1263
|
+
const startIndex = match.index;
|
|
1264
|
+
const endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
1265
|
+
if (endIndex === -1) {
|
|
1266
|
+
break;
|
|
1267
|
+
}
|
|
1268
|
+
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
1269
|
+
if (id && hasId(startIndex, endIndex)) {
|
|
1270
|
+
return getResult(startIndex, endIndex);
|
|
1271
|
+
}
|
|
1272
|
+
openCount = openTag.push([startIndex, endIndex]);
|
|
1273
|
+
}
|
|
1274
|
+
pattern.lastIndex = endIndex;
|
|
1275
|
+
}
|
|
1276
|
+
if (openCount === tagCount && isIndex(tagIndex)) {
|
|
1277
|
+
return getResult(...openTag[tagIndex]);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
else if (id || isIndex(tagIndex) && isCount(tagCount)) {
|
|
1281
|
+
complete: {
|
|
1282
|
+
const pattern = CACHE_TAGNAME[_b = tagName + flags + '2'] || (CACHE_TAGNAME[_b] = new RegExp(`<(?:${escapeTagName(tagName)}[\\s|>]|/${escapeTagName(tagName)}\\s*>)`, flags));
|
|
1283
|
+
const openTag = [];
|
|
1284
|
+
let openCount = 0, found, match;
|
|
1285
|
+
pattern.lastIndex = 0;
|
|
1286
|
+
while (match = pattern.exec(source)) {
|
|
1287
|
+
const startIndex = match.index;
|
|
1288
|
+
if (match[0][1] === '/') {
|
|
1289
|
+
const endIndex = startIndex + match[0].length - 1;
|
|
1290
|
+
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
1291
|
+
for (let i = 0; i < openCount; ++i) {
|
|
1292
|
+
const tag = openTag[i];
|
|
1293
|
+
if (tag[1] === -1 && --tag[2] === 0) {
|
|
1294
|
+
if (tag[3]) {
|
|
1295
|
+
position = { startIndex: tag[0], endIndex };
|
|
1296
|
+
break complete;
|
|
1297
|
+
}
|
|
1298
|
+
tag[1] = endIndex;
|
|
1299
|
+
break;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
else {
|
|
1305
|
+
const endIndex = XmlWriter.findCloseTag(source, startIndex);
|
|
1306
|
+
if (endIndex === -1) {
|
|
1307
|
+
break;
|
|
1308
|
+
}
|
|
1309
|
+
if (!invalid || isValidIndex(invalid, startIndex, endIndex)) {
|
|
1310
|
+
for (let i = 0; i < openCount; ++i) {
|
|
1311
|
+
const tag = openTag[i];
|
|
1312
|
+
if (tag[1] === -1) {
|
|
1313
|
+
++tag[2];
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
openCount = openTag.push([startIndex, -1, 1, id && !found && hasId(startIndex, endIndex) ? (found = true) && 1 : 0]);
|
|
1317
|
+
}
|
|
1318
|
+
pattern.lastIndex = endIndex;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
if (openTag.length === tagCount && isIndex(tagIndex)) {
|
|
1322
|
+
const tag = openTag[tagIndex];
|
|
1323
|
+
position = { startIndex: tag[0], endIndex: tag[1] };
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
if (position || (position = this.findIndexOf(source))) {
|
|
1328
|
+
if (remove) {
|
|
1329
|
+
position.remove = true;
|
|
1330
|
+
}
|
|
1331
|
+
else if (append) {
|
|
1332
|
+
position.append = append;
|
|
1333
|
+
}
|
|
1334
|
+
return this.replace(source, position);
|
|
1335
|
+
}
|
|
1336
|
+
return errorResult();
|
|
1337
|
+
}
|
|
1338
|
+
save(source, invalid) {
|
|
1339
|
+
const [output, outerXml, error] = this.write(source, invalid || XmlWriter.getCommentsAndCDATA(source));
|
|
1340
|
+
if (output) {
|
|
1341
|
+
this.node.outerXml = outerXml;
|
|
1342
|
+
this.reset();
|
|
1343
|
+
}
|
|
1344
|
+
return [output, error];
|
|
1345
|
+
}
|
|
1346
|
+
reset() {
|
|
1347
|
+
this._append = undefined;
|
|
1348
|
+
this._tagOffset = undefined;
|
|
1349
|
+
this._prevTagName = null;
|
|
1350
|
+
this._prevInnerXml = null;
|
|
1351
|
+
this._modified = false;
|
|
1352
|
+
}
|
|
1353
|
+
hasModifiedContent() {
|
|
1354
|
+
return typeof this._prevInnerXml === 'string';
|
|
1355
|
+
}
|
|
1356
|
+
getOuterContent() {
|
|
1357
|
+
const attributes = Array.from(this._attributes);
|
|
1358
|
+
const append = this.node.append;
|
|
1359
|
+
if (append) {
|
|
1360
|
+
const idKey = this.nameOfId;
|
|
1361
|
+
const items = attributes.filter(item => item[0] !== idKey);
|
|
1362
|
+
if (append.id) {
|
|
1363
|
+
items.push([idKey, append.id]);
|
|
1364
|
+
}
|
|
1365
|
+
return [append.tagName, items, append.textContent || ''];
|
|
1366
|
+
}
|
|
1367
|
+
return [this.tagName, attributes, this.innerXml];
|
|
1368
|
+
}
|
|
1369
|
+
getInnerOffset(tagName) {
|
|
1370
|
+
return this._tagOffset?.[tagName] || 0;
|
|
1371
|
+
}
|
|
1372
|
+
hasPosition() {
|
|
1373
|
+
return isIndex(this.node.startIndex) && isIndex(this.node.endIndex);
|
|
1374
|
+
}
|
|
1375
|
+
set id(value) {
|
|
1376
|
+
this.setAttribute(this.nameOfId, value);
|
|
1377
|
+
}
|
|
1378
|
+
get id() {
|
|
1379
|
+
return this.getAttribute(this.nameOfId) || '';
|
|
1380
|
+
}
|
|
1381
|
+
set tagName(value) {
|
|
1382
|
+
if (this.node.ignoreCase) {
|
|
1383
|
+
value = value.toLowerCase();
|
|
1384
|
+
}
|
|
1385
|
+
const tagName = this.tagName;
|
|
1386
|
+
if (value !== tagName) {
|
|
1387
|
+
this._prevTagName || (this._prevTagName = tagName);
|
|
1388
|
+
this._tagName = value;
|
|
1389
|
+
if (this.TAG_VOID.includes(value)) {
|
|
1390
|
+
this.innerXml = '';
|
|
1391
|
+
}
|
|
1392
|
+
this._modified = true;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
get tagName() {
|
|
1396
|
+
const tagName = this._tagName || this.node.tagName;
|
|
1397
|
+
return this.node.ignoreCase ? tagName.toLowerCase() : tagName;
|
|
1398
|
+
}
|
|
1399
|
+
get tagVoid() {
|
|
1400
|
+
return this._tagVoid || this.TAG_VOID.includes(this.tagName);
|
|
1401
|
+
}
|
|
1402
|
+
set innerXml(value) {
|
|
1403
|
+
if (!this.tagVoid && value !== this._innerXml) {
|
|
1404
|
+
this._prevInnerXml = this._innerXml;
|
|
1405
|
+
this._tagOffset = this.getTagOffset(value, { ignoreCase: this.ignoreCase });
|
|
1406
|
+
this._innerXml = value;
|
|
1407
|
+
this._modified = true;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
get innerXml() {
|
|
1411
|
+
return this._innerXml;
|
|
1412
|
+
}
|
|
1413
|
+
set tagOffset(value) {
|
|
1414
|
+
this._tagOffset = value && Object.keys(value).length ? value : undefined;
|
|
1415
|
+
}
|
|
1416
|
+
get tagOffset() {
|
|
1417
|
+
return this._tagOffset;
|
|
1418
|
+
}
|
|
1419
|
+
get ignoreCase() {
|
|
1420
|
+
return this._ignoreCase;
|
|
1421
|
+
}
|
|
1422
|
+
set remove(value) {
|
|
1423
|
+
if (value && !this._append) {
|
|
1424
|
+
const tagOffset = this.getTagOffset('', { ignoreCase: this.ignoreCase });
|
|
1425
|
+
if (tagOffset) {
|
|
1426
|
+
for (const tagName in tagOffset) {
|
|
1427
|
+
tagOffset[tagName] *= -1;
|
|
1428
|
+
}
|
|
1429
|
+
this._tagOffset = tagOffset;
|
|
1430
|
+
}
|
|
1431
|
+
this._remove = true;
|
|
1432
|
+
this._modified = true;
|
|
1433
|
+
}
|
|
1434
|
+
else {
|
|
1435
|
+
this._tagOffset = undefined;
|
|
1436
|
+
this._remove = false;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
get remove() {
|
|
1440
|
+
return this._remove;
|
|
1441
|
+
}
|
|
1442
|
+
get append() {
|
|
1443
|
+
return this._append;
|
|
1444
|
+
}
|
|
1445
|
+
get patternId() {
|
|
1446
|
+
return this._patternId || (this._patternId = getPatternId(this.nameOfId));
|
|
1447
|
+
}
|
|
1448
|
+
get modified() {
|
|
1449
|
+
return this._modified;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
exports.XmlElement = XmlElement;
|