wikiparser-node 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.eslintrc.json +229 -0
  2. package/LICENSE +674 -0
  3. package/README.md +1896 -0
  4. package/config/default.json +766 -0
  5. package/config/llwiki.json +686 -0
  6. package/config/moegirl.json +721 -0
  7. package/index.js +159 -0
  8. package/jsconfig.json +7 -0
  9. package/lib/element.js +690 -0
  10. package/lib/node.js +357 -0
  11. package/lib/ranges.js +122 -0
  12. package/lib/title.js +57 -0
  13. package/mixin/attributeParent.js +67 -0
  14. package/mixin/fixedToken.js +32 -0
  15. package/mixin/hidden.js +22 -0
  16. package/package.json +30 -0
  17. package/parser/brackets.js +107 -0
  18. package/parser/commentAndExt.js +61 -0
  19. package/parser/externalLinks.js +30 -0
  20. package/parser/hrAndDoubleUnderscore.js +26 -0
  21. package/parser/html.js +41 -0
  22. package/parser/links.js +92 -0
  23. package/parser/magicLinks.js +40 -0
  24. package/parser/quotes.js +63 -0
  25. package/parser/table.js +97 -0
  26. package/src/arg.js +150 -0
  27. package/src/atom/hidden.js +10 -0
  28. package/src/atom/index.js +33 -0
  29. package/src/attribute.js +342 -0
  30. package/src/extLink.js +116 -0
  31. package/src/heading.js +91 -0
  32. package/src/html.js +144 -0
  33. package/src/imageParameter.js +172 -0
  34. package/src/index.js +602 -0
  35. package/src/link/category.js +88 -0
  36. package/src/link/file.js +201 -0
  37. package/src/link/index.js +214 -0
  38. package/src/listToken.js +47 -0
  39. package/src/magicLink.js +66 -0
  40. package/src/nowiki/comment.js +45 -0
  41. package/src/nowiki/doubleUnderscore.js +42 -0
  42. package/src/nowiki/hr.js +41 -0
  43. package/src/nowiki/index.js +37 -0
  44. package/src/nowiki/noinclude.js +24 -0
  45. package/src/nowiki/quote.js +37 -0
  46. package/src/onlyinclude.js +42 -0
  47. package/src/parameter.js +165 -0
  48. package/src/syntax.js +80 -0
  49. package/src/table/index.js +867 -0
  50. package/src/table/td.js +259 -0
  51. package/src/table/tr.js +244 -0
  52. package/src/tagPair/ext.js +85 -0
  53. package/src/tagPair/include.js +45 -0
  54. package/src/tagPair/index.js +91 -0
  55. package/src/transclude.js +627 -0
  56. package/tool/index.js +898 -0
  57. package/typings/element.d.ts +28 -0
  58. package/typings/index.d.ts +49 -0
  59. package/typings/node.d.ts +23 -0
  60. package/typings/parser.d.ts +9 -0
  61. package/typings/table.d.ts +14 -0
  62. package/typings/token.d.ts +21 -0
  63. package/typings/tool.d.ts +10 -0
  64. package/util/debug.js +70 -0
  65. package/util/string.js +60 -0
@@ -0,0 +1,259 @@
1
+ 'use strict';
2
+
3
+ const fixedToken = require('../../mixin/fixedToken'),
4
+ {externalUse, typeError} = require('../../util/debug'),
5
+ /** @type {Parser} */ Parser = require('../..'),
6
+ Token = require('..'),
7
+ TrToken = require('./tr');
8
+
9
+ /**
10
+ * `<td>`、`<th>`和`<caption>`
11
+ * @classdesc `{childNodes: [SyntaxToken, AttributeToken, Token]}`
12
+ */
13
+ class TdToken extends fixedToken(TrToken) {
14
+ type = 'td';
15
+ #innerSyntax = '';
16
+
17
+ /** @complexity `n` */
18
+ get subtype() {
19
+ return this.getSyntax().subtype;
20
+ }
21
+ set subtype(subtype) {
22
+ this.setSyntax(subtype);
23
+ }
24
+
25
+ get rowspan() {
26
+ return this.getAttr('rowspan');
27
+ }
28
+ set rowspan(rowspan) {
29
+ this.setAttr('rowspan', rowspan);
30
+ }
31
+ get colspan() {
32
+ return this.getAttr('colspan');
33
+ }
34
+ set colspan(colspan) {
35
+ this.setAttr('colspan', colspan);
36
+ }
37
+
38
+ isIndependent() {
39
+ return this.firstElementChild.text().startsWith('\n');
40
+ }
41
+
42
+ /**
43
+ * @returns {{subtype: 'td'|'th'|'caption', escape: boolean, correction: boolean}}
44
+ * @complexity `n`
45
+ */
46
+ getSyntax() {
47
+ const syntax = this.firstElementChild.text(),
48
+ escape = syntax.includes('{{');
49
+ let subtype = 'td';
50
+ if (syntax.endsWith('!')) {
51
+ subtype = 'th';
52
+ } else if (syntax.endsWith('+')) {
53
+ subtype = 'caption';
54
+ }
55
+ if (this.isIndependent()) {
56
+ return {subtype, escape, correction: false};
57
+ }
58
+ const {previousElementSibling} = this;
59
+ if (previousElementSibling?.type !== 'td') {
60
+ return {subtype, escape, correction: true};
61
+ }
62
+ const result = previousElementSibling.getSyntax();
63
+ result.escape ||= escape;
64
+ result.correction = previousElementSibling.lastElementChild.offsetHeight > 1;
65
+ if (subtype === 'th' && result.subtype !== 'th') {
66
+ result.subtype = 'th';
67
+ result.correction = true;
68
+ }
69
+ return result;
70
+ }
71
+
72
+ static openingPattern = /^(?:\n[\S\n]*(?:[|!]|\|\+|{{\s*!\s*}}\+?)|(?:\||{{\s*!\s*}}){2}|!!|{{\s*!!\s*}})$/;
73
+
74
+ getRowCount = undefined;
75
+ getNthCol = undefined;
76
+ insertTableCell = undefined;
77
+
78
+ /**
79
+ * @param {string} syntax
80
+ * @param {string} inner
81
+ * @param {accum} accum
82
+ */
83
+ constructor(syntax, inner, config = Parser.getConfig(), accum = []) {
84
+ let innerSyntax = inner?.match(/\||\x00\d+!\x7f/),
85
+ attr = innerSyntax ? inner.slice(0, innerSyntax.index) : '';
86
+ if (/\[\[|-{/.test(attr)) {
87
+ innerSyntax = null;
88
+ attr = '';
89
+ }
90
+ super(syntax, attr, config, accum, TdToken.openingPattern);
91
+ if (innerSyntax) {
92
+ [this.#innerSyntax] = innerSyntax;
93
+ }
94
+ const innerToken = new Token(inner?.slice(innerSyntax?.index + this.#innerSyntax.length), config, true, accum);
95
+ innerToken.type = 'td-inner';
96
+ this.setAttribute('acceptable', {SyntaxToken: 0, AttributeToken: 1, Token: 2})
97
+ .seal(['getRowCount', 'getNthCol', 'insertTableCell']).appendChild(innerToken.setAttribute('stage', 4));
98
+ }
99
+
100
+ cloneNode() {
101
+ const token = super.cloneNode();
102
+ token.setAttribute('innerSyntax', this.#innerSyntax);
103
+ return token;
104
+ }
105
+
106
+ /**
107
+ * @param {string|Token} inner
108
+ * @param {'td'|'th'|'caption'} subtype
109
+ * @param {Record<string, string>} attr
110
+ */
111
+ static create(inner, subtype = 'td', attr = {}, include = false, config = Parser.getConfig()) {
112
+ if (typeof inner !== 'string' && (!(inner instanceof Token) || !inner.isPlain()) || typeof attr !== 'object') {
113
+ throw new TypeError('TdToken.create 方法仅接受 String、Token、Object 作为输入参数!');
114
+ } else if (!['td', 'th', 'caption'].includes(subtype)) {
115
+ throw new RangeError('单元格的子类型只能为 "td"、"th" 或 "caption"!');
116
+ } else if (typeof inner === 'string') {
117
+ inner = Parser.parse(inner, include, undefined, config);
118
+ }
119
+ const token = Parser.run(() => new TdToken('\n|', undefined, config));
120
+ token.setSyntax(subtype);
121
+ token.lastElementChild.safeReplaceWith(inner);
122
+ for (const [k, v] of Object.entries(attr)) {
123
+ token.setAttr(k, v);
124
+ }
125
+ return token;
126
+ }
127
+
128
+ /**
129
+ * @template {string} T
130
+ * @param {T} key
131
+ * @returns {TokenAttribute<T>}
132
+ */
133
+ getAttribute(key) {
134
+ if (key === 'innerSyntax') {
135
+ return this.#innerSyntax;
136
+ }
137
+ return super.getAttribute(key);
138
+ }
139
+
140
+ /**
141
+ * @template {string} T
142
+ * @param {T} key
143
+ * @param {TokenAttribute<T>} value
144
+ */
145
+ setAttribute(key, value) {
146
+ if (key !== 'innerSyntax') {
147
+ return super.setAttribute(key, value);
148
+ } else if (!Parser.debugging && externalUse('setAttribute')) {
149
+ throw new RangeError(`使用 ${this.constructor.name}.setAttribute 方法设置私有属性 #${key} 仅用于代码调试!`);
150
+ }
151
+ this.#innerSyntax = String(value);
152
+ return this;
153
+ }
154
+
155
+ build() {
156
+ if (this.#innerSyntax.includes('\x00')) {
157
+ this.#innerSyntax = this.buildFromStr(this.#innerSyntax).map(String).join('');
158
+ }
159
+ return this;
160
+ }
161
+
162
+ static #aliases = {td: '\n|', th: '\n!', caption: '\n|+'};
163
+
164
+ /** @param {string} syntax */
165
+ setSyntax(syntax, escape = false) {
166
+ super.setSyntax(TdToken.#aliases[syntax] ?? syntax, escape);
167
+ }
168
+
169
+ /** @complexity `n` */
170
+ #correct() {
171
+ if (this.children[1].toString()) {
172
+ this.#innerSyntax ||= '|';
173
+ }
174
+ const {subtype, escape, correction} = this.getSyntax();
175
+ if (correction) {
176
+ this.setSyntax(subtype, escape);
177
+ }
178
+ }
179
+
180
+ /** @complexity `n` */
181
+ independence() {
182
+ if (!this.isIndependent()) {
183
+ const {subtype, escape} = this.getSyntax();
184
+ this.setSyntax(subtype, escape);
185
+ }
186
+ }
187
+
188
+ /**
189
+ * @returns {string}
190
+ * @complexity `n`
191
+ */
192
+ toString() {
193
+ this.#correct();
194
+ const [syntax, attr, inner] = this.children;
195
+ return `${syntax.toString()}${attr.toString()}${this.#innerSyntax}${inner.toString()}`;
196
+ }
197
+
198
+ getGaps(i = 0) {
199
+ if (i !== 1) {
200
+ return 0;
201
+ }
202
+ this.#correct();
203
+ return this.#innerSyntax.length;
204
+ }
205
+
206
+ /**
207
+ * @returns {string}
208
+ * @complexity `n`
209
+ */
210
+ text() {
211
+ this.#correct();
212
+ const [syntax, attr, inner] = this.children;
213
+ return `${syntax.text()}${attr.text()}${this.#innerSyntax}${inner.text()}`;
214
+ }
215
+
216
+ /**
217
+ * @template {string} T
218
+ * @param {T} key
219
+ * @returns {T extends 'rowspan'|'colspan' ? number : Record<string, string|true>}
220
+ */
221
+ getAttr(key) {
222
+ const /** @type {string|true} */ value = super.getAttr(key);
223
+ key = key?.toLowerCase()?.trim();
224
+ return ['rowspan', 'colspan'].includes(key) ? Number(value) || 1 : value;
225
+ }
226
+
227
+ /**
228
+ * @template {string} T
229
+ * @param {T} key
230
+ * @param {T extends 'rowspan'|'colspan' ? number : string|boolean} value
231
+ */
232
+ setAttr(key, value) {
233
+ if (typeof key !== 'string') {
234
+ typeError(this, 'setAttr', 'String');
235
+ }
236
+ key = key.toLowerCase().trim();
237
+ if (typeof value === 'number' && ['rowspan', 'colspan'].includes(key)) {
238
+ value = value === 1 ? false : String(value);
239
+ }
240
+ const /** @type {boolean} */ result = super.setAttr(key, value);
241
+ if (!this.children[1].toString()) {
242
+ this.#innerSyntax = '';
243
+ }
244
+ return result;
245
+ }
246
+
247
+ escape() {
248
+ super.escape();
249
+ if (this.children[1].toString()) {
250
+ this.#innerSyntax ||= '{{!}}';
251
+ }
252
+ if (this.#innerSyntax === '|') {
253
+ this.#innerSyntax = '{{!}}';
254
+ }
255
+ }
256
+ }
257
+
258
+ Parser.classes.TdToken = __filename;
259
+ module.exports = TdToken;
@@ -0,0 +1,244 @@
1
+ 'use strict';
2
+
3
+ const attributeParent = require('../../mixin/attributeParent'),
4
+ {typeError} = require('../../util/debug'),
5
+ /** @type {Parser} */ Parser = require('../..'),
6
+ Token = require('..'),
7
+ SyntaxToken = require('../syntax'),
8
+ AttributeToken = require('../attribute');
9
+
10
+ /**
11
+ * 表格行,含开头的换行,不含结尾的换行
12
+ * @classdesc `{childNodes: [SyntaxToken, AttributeToken, ?(string|Token), ...TdToken]}`
13
+ */
14
+ class TrToken extends attributeParent(Token, 1) {
15
+ type = 'tr';
16
+
17
+ static openingPattern = /^\n[^\S\n]*(?:\|-+|{{\s*!\s*}}-+|{{\s*!-\s*}}-*)$/;
18
+
19
+ /**
20
+ * @param {string} syntax
21
+ * @param {accum} accum
22
+ */
23
+ constructor(syntax, attr = '', config = Parser.getConfig(), accum = [], pattern = TrToken.openingPattern) {
24
+ super(undefined, config, true, accum, {String: 2, Token: 2, SyntaxToken: 0, AttributeToken: 1, TdToken: '2:'});
25
+ this.append(
26
+ new SyntaxToken(syntax, pattern, 'table-syntax', config, accum, {
27
+ 'Stage-1': ':', '!ExtToken': '', TranscludeToken: ':',
28
+ }),
29
+ new AttributeToken(attr, 'table-attr', 'tr', config, accum),
30
+ );
31
+ this.protectChildren(0, 1);
32
+ }
33
+
34
+ cloneNode() {
35
+ const [syntax, attr, inner, ...cloned] = this.cloneChildren(),
36
+ /** @type {typeof TrToken} */ Constructor = this.constructor;
37
+ return Parser.run(() => {
38
+ const token = new Constructor(undefined, undefined, this.getAttribute('config'));
39
+ token.firstElementChild.safeReplaceWith(syntax);
40
+ token.children[1].safeReplaceWith(attr);
41
+ if (token.childElementCount > 2) { // TdToken
42
+ token.children[2].safeReplaceWith(inner);
43
+ } else if (inner !== undefined) {
44
+ token.appendChild(inner);
45
+ }
46
+ token.append(...cloned);
47
+ return token;
48
+ });
49
+ }
50
+
51
+ #correct() {
52
+ const [,, child] = this.childNodes;
53
+ if (typeof child === 'string' && !child.startsWith('\n')) {
54
+ this.setText(`\n${child}`, 2);
55
+ } else if (typeof child !== 'string' && child?.isPlain()) {
56
+ const {firstChild} = child;
57
+ if (typeof firstChild !== 'string') {
58
+ child.prepend('\n');
59
+ } else if (!firstChild.startsWith('\n')) {
60
+ child.setText(`\n${firstChild}`, 0);
61
+ }
62
+ }
63
+ }
64
+
65
+ toString() {
66
+ this.#correct();
67
+ return super.toString();
68
+ }
69
+
70
+ text() {
71
+ this.#correct();
72
+ const str = super.text();
73
+ return this.type === 'tr' && !str.trim().includes('\n') ? '' : str;
74
+ }
75
+
76
+ /** @param {SyntaxToken} syntax */
77
+ static escape(syntax) {
78
+ if (!(syntax instanceof SyntaxToken)) {
79
+ typeError('SyntaxToken');
80
+ }
81
+ const wikitext = syntax.childNodes.map(child => typeof child === 'string'
82
+ ? child.replaceAll('{|', '{{(!}}').replaceAll('|}', '{{!)}}').replaceAll('||', '{{!!}}')
83
+ .replaceAll('|', '{{!}}')
84
+ : child.toString(),
85
+ ).join(''),
86
+ token = Parser.parse(wikitext, syntax.getAttribute('include'), 2, syntax.getAttribute('config'));
87
+ syntax.replaceChildren(...token.childNodes);
88
+ }
89
+
90
+ /** @complexity `n` */
91
+ escape() {
92
+ for (const child of this.children) {
93
+ if (child instanceof SyntaxToken) {
94
+ TrToken.escape(child);
95
+ } else if (child instanceof TrToken) {
96
+ child.escape();
97
+ }
98
+ }
99
+ }
100
+
101
+ /** @param {string} syntax */
102
+ setSyntax(syntax, escape = false) {
103
+ const {firstElementChild} = this;
104
+ firstElementChild.replaceChildren(syntax);
105
+ if (escape) {
106
+ TrToken.escape(firstElementChild);
107
+ }
108
+ }
109
+
110
+ /**
111
+ * @param {number} i
112
+ * @complexity `n`
113
+ */
114
+ removeAt(i) {
115
+ const TdToken = require('./td'),
116
+ child = this.childNodes.at(i);
117
+ if (child instanceof TdToken && child.isIndependent()) {
118
+ const {nextElementSibling} = child;
119
+ if (nextElementSibling?.type === 'td') {
120
+ nextElementSibling.independence();
121
+ }
122
+ }
123
+ return super.removeAt(i);
124
+ }
125
+
126
+ /**
127
+ * @template {string|Token} T
128
+ * @param {T} token
129
+ * @returns {T}
130
+ * @complexity `n`
131
+ */
132
+ insertAt(token, i = this.childNodes.length) {
133
+ if (!Parser.running && !(token instanceof TrToken)) {
134
+ typeError(this, 'insertAt', 'TrToken');
135
+ }
136
+ const TdToken = require('./td'),
137
+ child = this.childNodes.at(i);
138
+ if (token instanceof TdToken && token.isIndependent() && child instanceof TdToken) {
139
+ child.independence();
140
+ }
141
+ return super.insertAt(token, i);
142
+ }
143
+
144
+ /**
145
+ * @returns {0|1}
146
+ * @complexity `n`
147
+ */
148
+ getRowCount() {
149
+ const TdToken = require('./td');
150
+ return Number(this.children.some(child =>
151
+ child instanceof TdToken && child.isIndependent() && !child.firstElementChild.text().endsWith('+'),
152
+ ));
153
+ }
154
+
155
+ /**
156
+ * @param {(children: Token[], index: number) => Token[]} subset
157
+ * @complexity `n`
158
+ */
159
+ #getSiblingRow(subset) {
160
+ const {parentElement} = this;
161
+ if (!parentElement) {
162
+ return;
163
+ }
164
+ const {children} = parentElement,
165
+ index = children.indexOf(this);
166
+ for (const child of subset(children, index)) {
167
+ if (child instanceof TrToken && child.getRowCount()) {
168
+ return child;
169
+ }
170
+ }
171
+ }
172
+
173
+ /** @complexity `n` */
174
+ getNextRow() {
175
+ return this.#getSiblingRow((children, index) => children.slice(index + 1));
176
+ }
177
+
178
+ /** @complexity `n` */
179
+ getPreviousRow() {
180
+ return this.#getSiblingRow((children, index) => children.slice(0, index).reverse());
181
+ }
182
+
183
+ /** @complexity `n` */
184
+ getColCount() {
185
+ const TdToken = require('./td');
186
+ let count = 0,
187
+ last = 0;
188
+ for (const child of this.children) {
189
+ if (child instanceof TdToken) {
190
+ last = child.isIndependent() ? Number(child.subtype !== 'caption') : last;
191
+ count += last;
192
+ }
193
+ }
194
+ return count;
195
+ }
196
+
197
+ /**
198
+ * @param {number} n
199
+ * @returns {TdToken}
200
+ * @complexity `n`
201
+ */
202
+ getNthCol(n, insert = false) {
203
+ if (typeof n !== 'number') {
204
+ typeError(this, 'getNthCol', 'Number');
205
+ }
206
+ const nCols = this.getColCount();
207
+ n = n < 0 ? n + nCols : n;
208
+ if (n < 0 || n > nCols || n === nCols && !insert) {
209
+ throw new RangeError(`不存在第 ${n} 个单元格!`);
210
+ }
211
+ const TdToken = require('./td'); // eslint-disable-line no-unused-vars
212
+ let last = 0;
213
+ for (const child of this.children.slice(2)) {
214
+ if (child instanceof TdToken) {
215
+ if (child.isIndependent()) {
216
+ last = Number(child.subtype !== 'caption');
217
+ }
218
+ n -= last;
219
+ if (n < 0) {
220
+ return child;
221
+ }
222
+ } else if (['tr', 'table-syntax'].includes(child.type)) {
223
+ return child;
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * @param {string|Token} inner
230
+ * @param {TableCoords}
231
+ * @param {'td'|'th'|'caption'} subtype
232
+ * @param {Record<string, string|boolean>} attr
233
+ * @returns {TdToken}
234
+ * @complexity `n`
235
+ */
236
+ insertTableCell(inner, {column}, subtype = 'td', attr = {}) {
237
+ const TdToken = require('./td'),
238
+ token = TdToken.create(inner, subtype, attr, this.getAttribute('include'), this.getAttribute('config'));
239
+ return this.insertBefore(token, this.getNthCol(column, true));
240
+ }
241
+ }
242
+
243
+ Parser.classes.TrToken = __filename;
244
+ module.exports = TrToken;
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ const attributeParent = require('../../mixin/attributeParent'),
4
+ /** @type {Parser} */ Parser = require('../..'),
5
+ TagPairToken = require('.');
6
+
7
+ /**
8
+ * 扩展标签
9
+ * @classdesc `{childNodes: [AttributeToken, NowikiToken|Token]}`
10
+ */
11
+ class ExtToken extends attributeParent(TagPairToken) {
12
+ type = 'ext';
13
+
14
+ /**
15
+ * @param {string} name
16
+ * @param {string|undefined} closing
17
+ * @param {accum} accum
18
+ */
19
+ constructor(name, attr = '', inner = '', closing = undefined, config = Parser.getConfig(), accum = []) {
20
+ attr = !attr || /^\s/.test(attr) ? attr : ` ${attr}`;
21
+ const lcName = name.toLowerCase(),
22
+ AttributeToken = require('../attribute'),
23
+ attrToken = new AttributeToken(attr, 'ext-attr', lcName, config, accum),
24
+ newConfig = structuredClone(config),
25
+ ext = new Set(newConfig.ext);
26
+ let /** @type {acceptable} */ acceptable, innerToken;
27
+ switch (lcName) {
28
+ case 'choose':
29
+ ext.add('option');
30
+ // fall through
31
+ case 'ref':
32
+ case 'option':
33
+ case 'poem':
34
+ case 'indicator':
35
+ case 'tab':
36
+ case 'tabs':
37
+ case 'pre': {
38
+ ext.delete(lcName);
39
+ newConfig.ext = [...ext];
40
+ const Token = require('..');
41
+ acceptable = {AttributeToken: 0, Token: 1};
42
+ innerToken = new Token(inner, newConfig, false, accum);
43
+ break;
44
+ }
45
+ /*
46
+ * 更多定制扩展的代码示例:
47
+ * ```
48
+ * case 'extensionName': {
49
+ * ext.delete(this.name);
50
+ * newConfig.ext = [...ext];
51
+ * const ExtensionToken = require('../extension');
52
+ * acceptable = {AttributeToken: 0, ExtensionToken: 1};
53
+ * innerToken = new ExtensionToken(extInner, newConfig, false, accum);
54
+ * break;
55
+ * }
56
+ * ```
57
+ */
58
+ default: {
59
+ const NowikiToken = require('../nowiki');
60
+ acceptable = {AttributeToken: 0, NowikiToken: 1};
61
+ innerToken = new NowikiToken(inner, config);
62
+ }
63
+ }
64
+ innerToken.type = 'ext-inner';
65
+ innerToken.setAttribute('name', lcName);
66
+ if (lcName === 'pre') {
67
+ innerToken.setAttribute('stage', Parser.MAX_STAGE - 1);
68
+ }
69
+ super(name, attrToken, innerToken, closing, config, accum, acceptable);
70
+ Object.defineProperty(this, 'closed', {value: true, enumerable: false, writable: false, configurable: false});
71
+ }
72
+
73
+ cloneNode() {
74
+ const inner = this.lastElementChild.cloneNode(),
75
+ tags = this.getAttribute('tags'),
76
+ config = this.getAttribute('config'),
77
+ attr = this.firstElementChild.toString(),
78
+ token = Parser.run(() => new ExtToken(tags[0], attr, '', this.selfClosing ? undefined : tags[1], config));
79
+ token.lastElementChild.safeReplaceWith(inner);
80
+ return token;
81
+ }
82
+ }
83
+
84
+ Parser.classes.ExtToken = __filename;
85
+ module.exports = ExtToken;
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ const hidden = require('../../mixin/hidden'),
4
+ /** @type {Parser} */ Parser = require('../..'),
5
+ TagPairToken = require('.');
6
+
7
+ /**
8
+ * `<includeonly>`或`<noinclude>`
9
+ * @classdesc `{childNodes: [string, string]}`
10
+ */
11
+ class IncludeToken extends hidden(TagPairToken) {
12
+ type = 'include';
13
+
14
+ /**
15
+ * @param {string} name
16
+ * @param {string|undefined} inner
17
+ * @param {string|undefined} closing
18
+ * @param {accum} accum
19
+ */
20
+ constructor(name, attr = '', inner = undefined, closing = undefined, config = Parser.getConfig(), accum = []) {
21
+ super(name, attr, inner ?? '', inner !== undefined ? closing ?? '' : closing, config, accum, {String: [0, 1]});
22
+ }
23
+
24
+ /** @this {IncludeToken & {firstChild: string, lastChild: string}} */
25
+ cloneNode() {
26
+ const tags = this.getAttribute('tags'),
27
+ config = this.getAttribute('config'),
28
+ inner = this.selfClosing ? undefined : this.lastChild,
29
+ closing = this.selfClosing || !this.closed ? undefined : tags[1],
30
+ token = Parser.run(() => new IncludeToken(tags[0], this.firstChild, inner, closing, config));
31
+ return token;
32
+ }
33
+
34
+ /** @param {string} str */
35
+ setText(str) {
36
+ return super.setText(str, 1);
37
+ }
38
+
39
+ removeAttr() {
40
+ super.setText('', 0);
41
+ }
42
+ }
43
+
44
+ Parser.classes.IncludeToken = __filename;
45
+ module.exports = IncludeToken;