wikiparser-node 0.8.0-b → 0.8.0-m

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 (78) hide show
  1. package/config/default.json +832 -0
  2. package/config/llwiki.json +630 -0
  3. package/config/minimum.json +142 -0
  4. package/config/moegirl.json +728 -0
  5. package/config/zhwiki.json +1269 -0
  6. package/index.js +79 -0
  7. package/lib/element.js +137 -0
  8. package/lib/node.js +226 -0
  9. package/lib/text.js +123 -0
  10. package/lib/title.js +60 -0
  11. package/mixin/hidden.js +18 -0
  12. package/package.json +9 -11
  13. package/parser/brackets.js +119 -0
  14. package/parser/commentAndExt.js +61 -0
  15. package/parser/converter.js +45 -0
  16. package/parser/externalLinks.js +32 -0
  17. package/parser/hrAndDoubleUnderscore.js +37 -0
  18. package/parser/html.js +41 -0
  19. package/parser/links.js +93 -0
  20. package/parser/list.js +58 -0
  21. package/parser/magicLinks.js +40 -0
  22. package/parser/quotes.js +63 -0
  23. package/parser/table.js +113 -0
  24. package/src/arg.js +89 -0
  25. package/src/atom/hidden.js +11 -0
  26. package/src/atom/index.js +26 -0
  27. package/src/attribute.js +277 -0
  28. package/src/attributes.js +150 -0
  29. package/src/converter.js +70 -0
  30. package/src/converterFlags.js +97 -0
  31. package/src/converterRule.js +75 -0
  32. package/src/extLink.js +60 -0
  33. package/src/gallery.js +101 -0
  34. package/src/hasNowiki/index.js +32 -0
  35. package/src/hasNowiki/pre.js +28 -0
  36. package/src/heading.js +83 -0
  37. package/src/html.js +133 -0
  38. package/src/imageParameter.js +106 -0
  39. package/src/imagemap.js +140 -0
  40. package/src/imagemapLink.js +29 -0
  41. package/src/index.js +407 -0
  42. package/src/link/category.js +13 -0
  43. package/src/link/file.js +125 -0
  44. package/src/link/galleryImage.js +62 -0
  45. package/src/link/index.js +125 -0
  46. package/src/magicLink.js +68 -0
  47. package/src/nested/choose.js +23 -0
  48. package/src/nested/combobox.js +22 -0
  49. package/src/nested/index.js +69 -0
  50. package/src/nested/references.js +22 -0
  51. package/src/nowiki/comment.js +47 -0
  52. package/src/nowiki/dd.js +13 -0
  53. package/src/nowiki/doubleUnderscore.js +26 -0
  54. package/src/nowiki/hr.js +22 -0
  55. package/src/nowiki/index.js +34 -0
  56. package/src/nowiki/list.js +13 -0
  57. package/src/nowiki/noinclude.js +14 -0
  58. package/src/nowiki/quote.js +55 -0
  59. package/src/onlyinclude.js +39 -0
  60. package/src/paramTag/index.js +66 -0
  61. package/src/paramTag/inputbox.js +32 -0
  62. package/src/parameter.js +97 -0
  63. package/src/syntax.js +23 -0
  64. package/src/table/index.js +46 -0
  65. package/src/table/td.js +119 -0
  66. package/src/table/tr.js +74 -0
  67. package/src/tagPair/ext.js +121 -0
  68. package/src/tagPair/include.js +26 -0
  69. package/src/tagPair/index.js +77 -0
  70. package/src/transclude.js +323 -0
  71. package/util/base.js +17 -0
  72. package/util/diff.js +76 -0
  73. package/util/lint.js +54 -0
  74. package/util/string.js +60 -0
  75. package/bundle/bundle.min.js +0 -38
  76. package/extensions/editor.css +0 -60
  77. package/extensions/editor.js +0 -317
  78. package/extensions/ui.css +0 -119
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const {generateForSelf} = require('../../util/lint'),
4
+ Parser = require('../..'),
5
+ AstText = require('../../lib/text'),
6
+ NowikiToken = require('.');
7
+
8
+ /**
9
+ * `<hr>`
10
+ * @classdesc `{childNodes: [AstText]}`
11
+ */
12
+ class QuoteToken extends NowikiToken {
13
+ type = 'quote';
14
+
15
+ /**
16
+ * @param {number} n 字符串长度
17
+ * @param {accum} accum
18
+ */
19
+ constructor(n, config = Parser.getConfig(), accum = []) {
20
+ super(`'`.repeat(n), config, accum);
21
+ }
22
+
23
+ /**
24
+ * @override
25
+ * @this {AstText}
26
+ * @param {number} start 起始位置
27
+ */
28
+ lint(start = 0) {
29
+ const {previousSibling, nextSibling} = this,
30
+ message = `孤立的"'"`,
31
+ /** @type {LintError[]} */ errors = [];
32
+ let refError, wikitext;
33
+ if (previousSibling?.type === 'text' && previousSibling.data.endsWith(`'`)) {
34
+ refError = generateForSelf(this, {start}, message);
35
+ wikitext = String(this.getRootNode());
36
+ const {startIndex: endIndex, startLine: endLine, startCol: endCol} = refError,
37
+ [, {length}] = previousSibling.data.match(/(?:^|[^'])('+)$/u),
38
+ startIndex = start - length,
39
+ excerpt = wikitext.slice(startIndex, startIndex + 50);
40
+ errors.push({...refError, startIndex, endIndex, startCol: endCol - length, endLine, endCol, excerpt});
41
+ }
42
+ if (nextSibling?.type === 'text' && nextSibling.data[0] === `'`) {
43
+ refError ||= generateForSelf(this, {start}, message);
44
+ wikitext ||= String(this.getRootNode());
45
+ const {endIndex: startIndex, endLine: startLine, endCol: startCol} = refError,
46
+ [{length}] = nextSibling.data.match(/^'+/u),
47
+ endIndex = startIndex + length,
48
+ excerpt = wikitext.slice(Math.max(0, endIndex - 50), endIndex);
49
+ errors.push({...refError, startIndex, endIndex, startLine, startCol, endCol: startCol + length, excerpt});
50
+ }
51
+ return errors;
52
+ }
53
+ }
54
+
55
+ module.exports = QuoteToken;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const Parser = require('..'),
4
+ Token = require('.');
5
+
6
+ /**
7
+ * 嵌入时的`<onlyinclude>`
8
+ * @classdesc `{childNodes: ...AstText|Token}`
9
+ */
10
+ class OnlyincludeToken extends Token {
11
+ type = 'onlyinclude';
12
+
13
+ /**
14
+ * @param {string} inner 标签内部wikitext
15
+ * @param {accum} accum
16
+ */
17
+ constructor(inner, config = Parser.getConfig(), accum = []) {
18
+ super(inner, config, true, accum);
19
+ }
20
+
21
+ /**
22
+ * @override
23
+ */
24
+ toString(selector) {
25
+ return `<onlyinclude>${super.toString()}</onlyinclude>`;
26
+ }
27
+
28
+ /** @override */
29
+ getPadding() {
30
+ return 13;
31
+ }
32
+
33
+ /** @override */
34
+ isPlain() {
35
+ return true;
36
+ }
37
+ }
38
+
39
+ module.exports = OnlyincludeToken;
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ const {generateForChild} = require('../../util/lint'),
4
+ Parser = require('../..'),
5
+ Token = require('..'),
6
+ AtomToken = require('../atom');
7
+
8
+ /**
9
+ * `<inputbox>`
10
+ * @classdesc `{childNodes: ...AtomToken}`
11
+ */
12
+ class ParamTagToken extends Token {
13
+ type = 'ext-inner';
14
+
15
+ /**
16
+ * @param {string} wikitext wikitext
17
+ * @param {accum} accum
18
+ */
19
+ constructor(wikitext, config = Parser.getConfig(), accum = []) {
20
+ super(undefined, config, true, accum, {
21
+ });
22
+ if (wikitext) {
23
+ const SingleLineAtomToken = AtomToken;
24
+ this.append(
25
+ ...wikitext.split('\n').map(line => new SingleLineAtomToken(line, 'param-line', config, accum, {
26
+ })),
27
+ );
28
+ }
29
+ }
30
+
31
+ /**
32
+ * @override
33
+ */
34
+ toString(selector) {
35
+ return super.toString(selector, '\n');
36
+ }
37
+
38
+ /** @override */
39
+ text() {
40
+ return super.text('\n');
41
+ }
42
+
43
+ /** @override */
44
+ getGaps() {
45
+ return 1;
46
+ }
47
+
48
+ /**
49
+ * @override
50
+ * @param {number} start 起始位置
51
+ */
52
+ lint(start = 0) {
53
+ let /** @type {{top: number, left: number}} */ rect;
54
+ return this.childNodes.filter(child => {
55
+ const {childNodes} = child,
56
+ i = childNodes.findIndex(({type}) => type !== 'text'),
57
+ str = (i >= 0 ? childNodes.slice(0, i).map(String).join('') : String(child)).trim();
58
+ return str && !(i >= 0 ? /^[a-z]+\s*(?:=|$)/iu : /^[a-z]+\s*=/iu).test(str);
59
+ }).map(child => {
60
+ rect ||= {start, ...this.getRootNode().posFromIndex(start)};
61
+ return generateForChild(child, rect, `${this.name}的无效参数`);
62
+ });
63
+ }
64
+ }
65
+
66
+ module.exports = ParamTagToken;
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ const parseBrackets = require('../../parser/brackets'),
4
+ Parser = require('../..'),
5
+ ParamTagToken = require('.'),
6
+ AtomToken = require('../atom');
7
+
8
+ /**
9
+ * `<inputbox>`
10
+ * @classdesc `{childNodes: ...SingleLineAtomToken}`
11
+ */
12
+ class InputboxToken extends ParamTagToken {
13
+ name = 'inputbox';
14
+
15
+ /**
16
+ * @param {string} wikitext wikitext
17
+ * @param {accum} accum
18
+ */
19
+ constructor(wikitext, config = Parser.getConfig(), accum = []) {
20
+ super(undefined, config, accum);
21
+ wikitext = parseBrackets(wikitext, config, accum);
22
+ accum.splice(accum.indexOf(this), 1);
23
+ accum.push(this);
24
+ if (wikitext) {
25
+ const SingleLineAtomToken = AtomToken;
26
+ this.append(...wikitext.split('\n').map(line => new SingleLineAtomToken(line, 'param-line', config, accum, {
27
+ })));
28
+ }
29
+ }
30
+ }
31
+
32
+ module.exports = InputboxToken;
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const {extUrlChar, extUrlCharFirst} = require('../util/string'),
4
+ {generateForChild} = require('../util/lint'),
5
+ Parser = require('..'),
6
+ Token = require('.');
7
+
8
+ /**
9
+ * 模板或魔术字参数
10
+ * @classdesc `{childNodes: [Token, Token]}`
11
+ */
12
+ class ParameterToken extends Token {
13
+ type = 'parameter';
14
+
15
+ /** 是否是匿名参数 */
16
+ get anon() {
17
+ return this.firstChild.length === 0;
18
+ }
19
+
20
+ /**
21
+ * @param {string|number} key 参数名
22
+ * @param {string} value 参数值
23
+ * @param {accum} accum
24
+ */
25
+ constructor(key, value, config = Parser.getConfig(), accum = []) {
26
+ super(undefined, config, true, accum);
27
+ const keyToken = new Token(typeof key === 'number' ? undefined : key, config, true, accum, {
28
+ }),
29
+ token = new Token(value, config, true, accum);
30
+ keyToken.type = 'parameter-key';
31
+ token.type = 'parameter-value';
32
+ this.append(keyToken, token.setAttribute('stage', 2));
33
+ }
34
+
35
+ /** @override */
36
+ afterBuild() {
37
+ if (!this.anon) {
38
+ const TranscludeToken = require('./transclude');
39
+ const name = String(this.firstChild).replace(/<!--.*?-->/gu, '')
40
+ .replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1'),
41
+ {parentNode} = this;
42
+ this.setAttribute('name', name);
43
+ if (parentNode instanceof TranscludeToken) {
44
+ parentNode.getArgs(name, false, false).add(this);
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @override
51
+ * @returns {string}
52
+ */
53
+ toString(selector) {
54
+ return this.anon
55
+ ? this.lastChild.toString(selector)
56
+ : super.toString(selector, '=');
57
+ }
58
+
59
+ /**
60
+ * @override
61
+ * @returns {string}
62
+ */
63
+ text() {
64
+ return this.anon ? this.lastChild.text() : super.text('=');
65
+ }
66
+
67
+ /** @override */
68
+ getGaps() {
69
+ return this.anon ? 0 : 1;
70
+ }
71
+
72
+ /**
73
+ * @override
74
+ * @param {number} start 起始位置
75
+ */
76
+ lint(start = 0) {
77
+ const errors = super.lint(start),
78
+ {firstChild, lastChild} = this,
79
+ link = new RegExp(`https?://${extUrlCharFirst}${extUrlChar}$`, 'iu')
80
+ .exec(String(firstChild).replace(/<!--.*?-->/gu, ''))?.[0];
81
+ if (link && new URL(link).search) {
82
+ const e = generateForChild(firstChild, {start}, '匿名参数中未转义的查询参数');
83
+ errors.push({
84
+ ...e,
85
+ startIndex: e.endIndex,
86
+ endIndex: e.endIndex + 1,
87
+ startLine: e.endLine,
88
+ startCol: e.endCol,
89
+ endCol: e.endCol + 1,
90
+ excerpt: `${String(firstChild).slice(-25)}=${String(lastChild).slice(0, 25)}`,
91
+ });
92
+ }
93
+ return errors;
94
+ }
95
+ }
96
+
97
+ module.exports = ParameterToken;
package/src/syntax.js ADDED
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ const Parser = require('..'),
4
+ Token = require('.');
5
+
6
+ /**
7
+ * 满足特定语法格式的plain Token
8
+ * @classdesc `{childNodes: ...AstText|Token}`
9
+ */
10
+ class SyntaxToken extends Token {
11
+ /**
12
+ * @param {string} wikitext 语法wikitext
13
+ * @param {RegExp} pattern 语法正则
14
+ * @param {string} type Token.type
15
+ * @param {accum} accum
16
+ */
17
+ constructor(wikitext, pattern, type = 'plain', config = Parser.getConfig(), accum = [], acceptable = undefined) {
18
+ super(wikitext, config, true, accum, acceptable);
19
+ this.type = type;
20
+ }
21
+ }
22
+
23
+ module.exports = SyntaxToken;
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const {generateForChild} = require('../../util/lint'),
4
+ TrToken = require('./tr'),
5
+ SyntaxToken = require('../syntax');
6
+
7
+ /**
8
+ * 表格
9
+ * @classdesc `{childNodes: [SyntaxToken, AttributesToken, ?Token, ...TdToken, ...TrToken, ?SyntaxToken]}`
10
+ */
11
+ class TableToken extends TrToken {
12
+ type = 'table';
13
+
14
+ /** 表格是否闭合 */
15
+ get closed() {
16
+ return this.lastChild.type === 'table-syntax';
17
+ }
18
+
19
+ /**
20
+ * @override
21
+ * @param {number} start 起始位置
22
+ */
23
+ lint(start = 0) {
24
+ const errors = super.lint(start);
25
+ if (!this.closed) {
26
+ const {firstChild, lastChild: tr} = this,
27
+ {lastChild: td} = tr,
28
+ error = generateForChild(firstChild, {start}, '未闭合的表格');
29
+ errors.push({...error, excerpt: String(td?.type === 'td' ? td : tr).slice(0, 50)});
30
+ }
31
+ return errors;
32
+ }
33
+
34
+ /**
35
+ * 闭合表格语法
36
+ * @complexity `n`
37
+ * @param {string} syntax 表格结尾语法
38
+ */
39
+ close(syntax = '\n|}', halfParsed = false) {
40
+ const config = this.getAttribute('config'),
41
+ accum = this.getAttribute('accum');
42
+ super.insertAt(new SyntaxToken(syntax, undefined, 'table-syntax', config, accum));
43
+ }
44
+ }
45
+
46
+ module.exports = TableToken;
@@ -0,0 +1,119 @@
1
+ 'use strict';
2
+
3
+ const {generateForChild} = require('../../util/lint'),
4
+ Parser = require('../..'),
5
+ Token = require('..'),
6
+ TrToken = require('./tr');
7
+
8
+ /**
9
+ * `<td>`、`<th>`和`<caption>`
10
+ * @classdesc `{childNodes: [SyntaxToken, AttributesToken, Token]}`
11
+ */
12
+ class TdToken extends TrToken {
13
+ type = 'td';
14
+ #innerSyntax = '';
15
+
16
+ /**
17
+ * 单元格类型
18
+ * @complexity `n`
19
+ */
20
+ get subtype() {
21
+ return this.getSyntax().subtype;
22
+ }
23
+
24
+ /**
25
+ * 获取单元格语法信息
26
+ * @returns {{subtype: 'td'|'th'|'caption'}}
27
+ * @complexity `n`
28
+ */
29
+ getSyntax() {
30
+ const syntax = this.firstChild.text(),
31
+ char = syntax.at(-1);
32
+ let subtype = 'td';
33
+ if (char === '!') {
34
+ subtype = 'th';
35
+ } else if (char === '+') {
36
+ subtype = 'caption';
37
+ }
38
+ return {subtype};
39
+ }
40
+
41
+ /**
42
+ * @param {string} syntax 单元格语法
43
+ * @param {string} inner 内部wikitext
44
+ * @param {accum} accum
45
+ */
46
+ constructor(syntax, inner, config = Parser.getConfig(), accum = []) {
47
+ let innerSyntax = inner?.match(/\||\0\d+!\x7F/u),
48
+ attr = innerSyntax ? inner.slice(0, innerSyntax.index) : '';
49
+ if (/\[\[|-\{/u.test(attr)) {
50
+ innerSyntax = undefined;
51
+ attr = '';
52
+ }
53
+ super(syntax, attr, config, accum);
54
+ if (innerSyntax) {
55
+ [this.#innerSyntax] = innerSyntax;
56
+ }
57
+ // eslint-disable-next-line no-unsafe-optional-chaining
58
+ const innerToken = new Token(inner?.slice(innerSyntax?.index + this.#innerSyntax.length), config, true, accum);
59
+ innerToken.type = 'td-inner';
60
+ this.insertAt(innerToken.setAttribute('stage', 4));
61
+ }
62
+
63
+ /** @override */
64
+ afterBuild() {
65
+ if (this.#innerSyntax.includes('\0')) {
66
+ this.#innerSyntax = this.getAttribute('buildFromStr')(this.#innerSyntax, 'string');
67
+ }
68
+ }
69
+
70
+ /**
71
+ * @override
72
+ * @returns {string}
73
+ * @complexity `n`
74
+ */
75
+ toString(selector) {
76
+ const {childNodes: [syntax, attr, inner]} = this;
77
+ return `${syntax.toString()}${attr.toString()}${this.#innerSyntax}${inner.toString()}`;
78
+ }
79
+
80
+ /**
81
+ * @override
82
+ * @returns {string}
83
+ * @complexity `n`
84
+ */
85
+ text() {
86
+ const {childNodes: [syntax, attr, inner]} = this;
87
+ return `${syntax.text()}${attr.text()}${this.#innerSyntax}${inner.text()}`;
88
+ }
89
+
90
+ /**
91
+ * @override
92
+ * @param {number} i 子节点位置
93
+ */
94
+ getGaps(i = 0) {
95
+ i = i < 0 ? i + this.length : i;
96
+ if (i === 1) {
97
+ return this.#innerSyntax.length;
98
+ }
99
+ return 0;
100
+ }
101
+
102
+ /**
103
+ * @override
104
+ * @param {number} start 起始位置
105
+ */
106
+ lint(start = 0) {
107
+ const errors = super.lint(start),
108
+ {lastChild} = this;
109
+ start += this.getRelativeIndex(-1);
110
+ for (const child of lastChild.childNodes) {
111
+ if (child.type === 'text' && child.data.includes('|')) {
112
+ errors.push(generateForChild(child, {start}, '表格单元格中多余的"|"', 'warning'));
113
+ }
114
+ }
115
+ return errors;
116
+ }
117
+ }
118
+
119
+ module.exports = TdToken;
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ const {generateForChild} = require('../../util/lint'),
4
+ Parser = require('../..'),
5
+ Token = require('..'),
6
+ SyntaxToken = require('../syntax'),
7
+ AttributesToken = require('../attributes');
8
+
9
+ /**
10
+ * 表格行,含开头的换行,不含结尾的换行
11
+ * @classdesc `{childNodes: [SyntaxToken, AttributesToken, ?Token, ...TdToken]}`
12
+ */
13
+ class TrToken extends Token {
14
+ type = 'tr';
15
+
16
+ /**
17
+ * @param {string} syntax 表格语法
18
+ * @param {string} attr 表格属性
19
+ * @param {accum} accum
20
+ * @param {RegExp} pattern 表格语法正则
21
+ */
22
+ constructor(syntax, attr = '', config = Parser.getConfig(), accum = [], pattern = undefined) {
23
+ super(undefined, config, true, accum, {
24
+ });
25
+ this.append(
26
+ new SyntaxToken(syntax, pattern, 'table-syntax', config, accum, {
27
+ }),
28
+ new AttributesToken(attr, 'table-attrs', this.type, config, accum),
29
+ );
30
+ }
31
+
32
+ /**
33
+ * @override
34
+ * @param {number} start 起始位置
35
+ */
36
+ lint(start = 0) {
37
+ const TranscludeToken = require('../transclude'),
38
+ ArgToken = require('../arg');
39
+ const errors = super.lint(start),
40
+ inter = this.childNodes.find(({type}) => type === 'table-inter');
41
+ if (!inter) {
42
+ return errors;
43
+ }
44
+ const /** @type {TranscludeToken & ArgToken} */ first = inter.childNodes.find(child => child.text().trim()),
45
+ tdPattern = /^\s*(?:!|\{\{\s*![!-]?\s*\}\})/u;
46
+ if (!first || tdPattern.test(String(first)) || first.type === 'arg' && tdPattern.test(first.default || '')) {
47
+ return errors;
48
+ } else if (first.type === 'magic-word') {
49
+ try {
50
+ const possibleValues = first.getPossibleValues();
51
+ if (possibleValues.every(token => tdPattern.test(token.text()))) {
52
+ return errors;
53
+ }
54
+ } catch {}
55
+ }
56
+ const error = generateForChild(inter, {start}, '将被移出表格的内容');
57
+ errors.push({
58
+ ...error,
59
+ startIndex: error.startIndex + 1,
60
+ startLine: error.startLine + 1,
61
+ startCol: 0,
62
+ excerpt: error.excerpt.slice(1),
63
+ });
64
+ return errors;
65
+ }
66
+
67
+ /** @override */
68
+ text() {
69
+ const str = super.text();
70
+ return this.type === 'tr' && !str.trim().includes('\n') ? '' : str;
71
+ }
72
+ }
73
+
74
+ module.exports = TrToken;
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ const {generateForSelf} = require('../../util/lint'),
4
+ Parser = require('../..'),
5
+ Token = require('..'),
6
+ TagPairToken = require('.'),
7
+ AttributesToken = require('../attributes');
8
+
9
+ /**
10
+ * 扩展标签
11
+ * @classdesc `{childNodes: [AttributesToken, NowikiToken|Token]}`
12
+ */
13
+ class ExtToken extends TagPairToken {
14
+ type = 'ext';
15
+ closed = true;
16
+
17
+ /**
18
+ * @param {string} name 标签名
19
+ * @param {string} attr 标签属性
20
+ * @param {string} inner 内部wikitext
21
+ * @param {string|undefined} closed 是否封闭
22
+ * @param {accum} accum
23
+ */
24
+ constructor(name, attr = '', inner = '', closed = undefined, config = Parser.getConfig(), accum = []) {
25
+ attr = !attr || /^\s/u.test(attr) ? attr : ` ${attr}`;
26
+ const lcName = name.toLowerCase(),
27
+ attrToken = new AttributesToken(attr, 'ext-attrs', lcName, config, accum),
28
+ /** @type {ParserConfig} */ newConfig = {...config, excludes: [...config.excludes]},
29
+ ext = new Set(newConfig.ext);
30
+ let /** @type {Token} */ innerToken;
31
+ ext.delete(lcName);
32
+ newConfig.ext = [...ext];
33
+ switch (lcName) {
34
+ case 'tab':
35
+ ext.delete('tabs');
36
+ newConfig.ext = [...ext];
37
+ // fall through
38
+ case 'indicator':
39
+ case 'poem':
40
+ case 'ref':
41
+ case 'option':
42
+ case 'combooption':
43
+ case 'tabs':
44
+ case 'poll':
45
+ case 'seo':
46
+ if (lcName === 'poem') {
47
+ newConfig.excludes.push('heading');
48
+ }
49
+ innerToken = new Token(inner, newConfig, true, accum);
50
+ break;
51
+ case 'gallery': {
52
+ const GalleryToken = require('../gallery');
53
+ innerToken = new GalleryToken(inner, newConfig, accum);
54
+ break;
55
+ }
56
+ case 'pre': {
57
+ const PreToken = require('../hasNowiki/pre');
58
+ innerToken = new PreToken(inner, newConfig, accum);
59
+ break;
60
+ }
61
+ case 'references':
62
+ case 'choose':
63
+ case 'combobox': {
64
+ const NestedToken = require('../nested'),
65
+ /** @type {typeof NestedToken} */ NestedExtToken = require(`../nested/${lcName}`);
66
+ innerToken = new NestedExtToken(inner, newConfig, accum);
67
+ break;
68
+ }
69
+ case 'imagemap': {
70
+ const ImagemapToken = require('../imagemap');
71
+ innerToken = new ImagemapToken(inner, config, accum);
72
+ break;
73
+ }
74
+ case 'dynamicpagelist': {
75
+ const ParamTagToken = require('../paramTag');
76
+ innerToken = new ParamTagToken(inner, newConfig, accum);
77
+ break;
78
+ }
79
+ case 'inputbox': {
80
+ newConfig.excludes.push('heading');
81
+ const InputboxToken = require('../paramTag/inputbox');
82
+ innerToken = new InputboxToken(inner, newConfig, accum);
83
+ break;
84
+ }
85
+
86
+ /*
87
+ * 更多定制扩展的代码示例:
88
+ * ```
89
+ * case 'extensionName': {
90
+ * const ExtensionToken = require('../extension');
91
+ * innerToken = new ExtensionToken(inner, newConfig, accum);
92
+ * break;
93
+ * }
94
+ * ```
95
+ */
96
+ default: {
97
+ const NowikiToken = require('../nowiki');
98
+ innerToken = new NowikiToken(inner, config);
99
+ }
100
+ }
101
+ innerToken.setAttribute('name', lcName).type = 'ext-inner';
102
+ super(name, attrToken, innerToken, closed, config, accum);
103
+ }
104
+
105
+ /**
106
+ * @override
107
+ * @param {number} start 起始位置
108
+ */
109
+ lint(start = 0) {
110
+ const errors = super.lint(start);
111
+ if (this.name !== 'nowiki' && this.closest('html-attrs, table-attrs')) {
112
+ const root = this.getRootNode(),
113
+ excerpt = String(root).slice(Math.max(0, start - 25), start + 25),
114
+ rect = {start, ...root.posFromIndex(start)};
115
+ errors.push({...generateForSelf(this, rect, 'HTML标签属性中的扩展标签'), excerpt});
116
+ }
117
+ return errors;
118
+ }
119
+ }
120
+
121
+ module.exports = ExtToken;
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const hidden = require('../../mixin/hidden'),
4
+ Parser = require('../..'),
5
+ TagPairToken = require('.');
6
+
7
+ /**
8
+ * `<includeonly>`或`<noinclude>`
9
+ * @classdesc `{childNodes: [AstText, AstText]}`
10
+ */
11
+ class IncludeToken extends hidden(TagPairToken) {
12
+ type = 'include';
13
+
14
+ /**
15
+ * @param {string} name 标签名
16
+ * @param {string} attr 标签属性
17
+ * @param {string|undefined} inner 内部wikitext
18
+ * @param {string|undefined} closed 是否封闭
19
+ * @param {accum} accum
20
+ */
21
+ constructor(name, attr = '', inner = undefined, closed = undefined, config = Parser.getConfig(), accum = []) {
22
+ super(name, attr, inner ?? '', inner === undefined ? closed : closed ?? '', config, accum);
23
+ }
24
+ }
25
+
26
+ module.exports = IncludeToken;