wikiparser-node 0.4.0 → 0.6.1
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/config/default.json +129 -66
- package/config/zhwiki.json +4 -4
- package/index.js +97 -65
- package/lib/element.js +159 -302
- package/lib/node.js +384 -198
- package/lib/ranges.js +3 -4
- package/lib/text.js +65 -36
- package/lib/title.js +9 -8
- package/mixin/fixedToken.js +4 -4
- package/mixin/hidden.js +2 -0
- package/mixin/sol.js +16 -7
- package/package.json +14 -3
- package/parser/brackets.js +8 -2
- package/parser/commentAndExt.js +1 -1
- package/parser/converter.js +1 -1
- package/parser/externalLinks.js +2 -2
- package/parser/hrAndDoubleUnderscore.js +8 -7
- package/parser/links.js +8 -9
- package/parser/magicLinks.js +1 -1
- package/parser/selector.js +5 -5
- package/parser/table.js +18 -16
- package/src/arg.js +71 -42
- package/src/atom/index.js +7 -5
- package/src/attribute.js +102 -64
- package/src/charinsert.js +91 -0
- package/src/converter.js +34 -15
- package/src/converterFlags.js +87 -40
- package/src/converterRule.js +59 -53
- package/src/extLink.js +45 -37
- package/src/gallery.js +71 -16
- package/src/hasNowiki/index.js +42 -0
- package/src/hasNowiki/pre.js +40 -0
- package/src/heading.js +41 -18
- package/src/html.js +76 -48
- package/src/imageParameter.js +73 -51
- package/src/imagemap.js +205 -0
- package/src/imagemapLink.js +43 -0
- package/src/index.js +243 -138
- package/src/link/category.js +10 -14
- package/src/link/file.js +112 -56
- package/src/link/galleryImage.js +74 -10
- package/src/link/index.js +86 -61
- package/src/magicLink.js +48 -21
- package/src/nested/choose.js +24 -0
- package/src/nested/combobox.js +23 -0
- package/src/nested/index.js +88 -0
- package/src/nested/references.js +23 -0
- package/src/nowiki/comment.js +18 -4
- package/src/nowiki/dd.js +2 -2
- package/src/nowiki/doubleUnderscore.js +16 -11
- package/src/nowiki/index.js +12 -0
- package/src/nowiki/quote.js +28 -1
- package/src/onlyinclude.js +15 -8
- package/src/paramTag/index.js +83 -0
- package/src/paramTag/inputbox.js +42 -0
- package/src/parameter.js +73 -46
- package/src/syntax.js +9 -1
- package/src/table/index.js +58 -44
- package/src/table/td.js +63 -63
- package/src/table/tr.js +52 -35
- package/src/tagPair/ext.js +60 -43
- package/src/tagPair/include.js +11 -1
- package/src/tagPair/index.js +29 -20
- package/src/transclude.js +214 -166
- package/tool/index.js +720 -439
- package/util/base.js +17 -0
- package/util/debug.js +1 -1
- package/{test/util.js → util/diff.js} +15 -19
- package/util/lint.js +40 -0
- package/util/string.js +37 -20
- package/.eslintrc.json +0 -714
- package/errors/README +0 -1
- package/jsconfig.json +0 -7
- package/printed/README +0 -1
- package/printed/example.json +0 -120
- package/test/api.js +0 -83
- package/test/real.js +0 -133
- package/test/test.js +0 -28
- package/typings/api.d.ts +0 -13
- package/typings/array.d.ts +0 -28
- package/typings/event.d.ts +0 -24
- package/typings/index.d.ts +0 -94
- package/typings/node.d.ts +0 -29
- package/typings/parser.d.ts +0 -16
- package/typings/table.d.ts +0 -14
- package/typings/token.d.ts +0 -22
- package/typings/tool.d.ts +0 -11
package/src/magicLink.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const {generateForChild} = require('../util/lint'),
|
|
4
|
+
Parser = require('..'),
|
|
4
5
|
Token = require('.');
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -19,11 +20,14 @@ class MagicLinkToken extends Token {
|
|
|
19
20
|
set protocol(value) {
|
|
20
21
|
if (typeof value !== 'string') {
|
|
21
22
|
this.typeError('protocol', 'String');
|
|
22
|
-
}
|
|
23
|
-
if (!new RegExp(`${this.#protocolRegex.source}$`, 'iu').test(value)) {
|
|
23
|
+
} else if (!new RegExp(`${this.#protocolRegex.source}$`, 'iu').test(value)) {
|
|
24
24
|
throw new RangeError(`非法的外链协议:${value}`);
|
|
25
25
|
}
|
|
26
|
-
this
|
|
26
|
+
const {link} = this;
|
|
27
|
+
if (!this.#protocolRegex.test(link)) {
|
|
28
|
+
throw new Error(`特殊外链无法更改协议!${link}`);
|
|
29
|
+
}
|
|
30
|
+
this.replaceChildren(link.replace(this.#protocolRegex, value));
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/** 和内链保持一致 */
|
|
@@ -48,25 +52,41 @@ class MagicLinkToken extends Token {
|
|
|
48
52
|
this.#protocolRegex = new RegExp(`^(?:${config.protocol}${doubleSlash ? '|//' : ''})`, 'iu');
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
/**
|
|
56
|
+
* @override
|
|
57
|
+
* @param {number} start 起始位置
|
|
58
|
+
*/
|
|
59
|
+
lint(start = 0) {
|
|
60
|
+
const errors = super.lint(start);
|
|
61
|
+
let /** @type {{top: number, left: number}} */ rect;
|
|
62
|
+
for (const child of this.childNodes) {
|
|
63
|
+
const str = String(child);
|
|
64
|
+
if (child.type !== 'text' || !/[,;。:!?()【】]/u.test(str)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
rect ||= this.getRootNode().posFromIndex(start);
|
|
68
|
+
const refError = generateForChild(child, rect, 'URL中的全角标点', 'warning');
|
|
69
|
+
errors.push(...[...str.matchAll(/[,;。:!?()【】]/gu)].map(({index}) => {
|
|
70
|
+
const lines = str.slice(0, index).split('\n'),
|
|
71
|
+
{length: top} = lines,
|
|
72
|
+
{length: left} = lines.at(-1),
|
|
73
|
+
startLine = refError.startLine + top - 1,
|
|
74
|
+
startCol = top > 1 ? left : refError.startCol + left;
|
|
75
|
+
return {...refError, startLine, endLine: startLine, startCol, endCol: startCol + 1};
|
|
76
|
+
}));
|
|
57
77
|
}
|
|
58
|
-
return
|
|
78
|
+
return errors;
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
/** @override */
|
|
62
82
|
cloneNode() {
|
|
63
|
-
const cloned = this.cloneChildNodes()
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
const cloned = this.cloneChildNodes();
|
|
84
|
+
return Parser.run(() => {
|
|
85
|
+
const token = new MagicLinkToken(undefined, this.type === 'ext-link-url', this.getAttribute('config'));
|
|
86
|
+
token.append(...cloned);
|
|
87
|
+
token.afterBuild();
|
|
88
|
+
return token;
|
|
89
|
+
});
|
|
70
90
|
}
|
|
71
91
|
|
|
72
92
|
/**
|
|
@@ -96,11 +116,18 @@ class MagicLinkToken extends Token {
|
|
|
96
116
|
setTarget(url) {
|
|
97
117
|
url = String(url);
|
|
98
118
|
const root = Parser.parse(url, this.getAttribute('include'), 9, this.getAttribute('config')),
|
|
99
|
-
{
|
|
100
|
-
if (length !== 1 ||
|
|
119
|
+
{length, firstChild: freeExtLink} = root;
|
|
120
|
+
if (length !== 1 || freeExtLink.type !== 'free-ext-link') {
|
|
101
121
|
throw new SyntaxError(`非法的自由外链目标:${url}`);
|
|
102
122
|
}
|
|
103
|
-
this.replaceChildren(...
|
|
123
|
+
this.replaceChildren(...freeExtLink.childNodes);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 是否是模板或魔术字参数 */
|
|
127
|
+
isParamValue() {
|
|
128
|
+
const ParameterToken = require('./parameter');
|
|
129
|
+
const /** @type {ParameterToken} */ parameter = this.closest('parameter');
|
|
130
|
+
return parameter?.getValue() === this.text();
|
|
104
131
|
}
|
|
105
132
|
}
|
|
106
133
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Parser = require('../..'),
|
|
4
|
+
NestedToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<choose>`
|
|
8
|
+
* @classdesc `{childNodes: [...ExtToken|NoincludeToken]}`
|
|
9
|
+
*/
|
|
10
|
+
class ChooseToken extends NestedToken {
|
|
11
|
+
name = 'choose';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string|undefined} wikitext wikitext
|
|
15
|
+
* @param {accum} accum
|
|
16
|
+
*/
|
|
17
|
+
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
18
|
+
const regex = /<(option|choicetemplate)(\s[^>]*)?>(.*?)<\/(\1)>/gsu;
|
|
19
|
+
super(wikitext, regex, ['option', 'choicetemplate'], config, accum);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Parser.classes.ChooseToken = __filename;
|
|
24
|
+
module.exports = ChooseToken;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Parser = require('../..'),
|
|
4
|
+
NestedToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<combobox>`
|
|
8
|
+
* @classdesc `{childNodes: [...ExtToken|NoincludeToken]}`
|
|
9
|
+
*/
|
|
10
|
+
class ComboboxToken extends NestedToken {
|
|
11
|
+
name = 'combobox';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string|undefined} wikitext wikitext
|
|
15
|
+
* @param {accum} accum
|
|
16
|
+
*/
|
|
17
|
+
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
18
|
+
super(wikitext, /<(combooption)(\s[^>]*)?>(.*?)<\/(combooption\s*)>/gisu, ['combooption'], config, accum);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Parser.classes.ComboboxToken = __filename;
|
|
23
|
+
module.exports = ComboboxToken;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {generateForChild} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
Token = require('..');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 嵌套式的扩展标签
|
|
9
|
+
* @classdesc `{childNodes: [...ExtToken|NoincludeToken]}`
|
|
10
|
+
*/
|
|
11
|
+
class NestedToken extends Token {
|
|
12
|
+
type = 'ext-inner';
|
|
13
|
+
#tags;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string|undefined} wikitext wikitext
|
|
17
|
+
* @param {RegExp} regex 内层正则
|
|
18
|
+
* @param {string[]} tags 内层标签名
|
|
19
|
+
* @param {accum} accum
|
|
20
|
+
*/
|
|
21
|
+
constructor(wikitext, regex, tags, config = Parser.getConfig(), accum = []) {
|
|
22
|
+
const ExtToken = require('../tagPair/ext'),
|
|
23
|
+
NoincludeToken = require('../nowiki/noinclude');
|
|
24
|
+
const text = wikitext?.replaceAll(
|
|
25
|
+
regex,
|
|
26
|
+
/** @type {function(...string): string} */ (_, name, attr, inner, closing) => {
|
|
27
|
+
const str = `\0${accum.length + 1}e\x7F`;
|
|
28
|
+
new ExtToken(name, attr, inner, closing, config, accum);
|
|
29
|
+
return str;
|
|
30
|
+
},
|
|
31
|
+
)?.replaceAll(/(?<=^|\0\d+e\x7F).*?(?=$|\0\d+e\x7F)/gsu, substr => {
|
|
32
|
+
if (substr === '') {
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
new NoincludeToken(substr, config, accum);
|
|
36
|
+
return `\0${accum.length}c\x7F`;
|
|
37
|
+
});
|
|
38
|
+
super(text, config, true, accum, {NoincludeToken: ':', ExtToken: ':'});
|
|
39
|
+
this.#tags = tags;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @override
|
|
44
|
+
* @param {number} start 起始位置
|
|
45
|
+
*/
|
|
46
|
+
lint(start = 0) {
|
|
47
|
+
let rect;
|
|
48
|
+
return [
|
|
49
|
+
...super.lint(start),
|
|
50
|
+
...this.childNodes.filter(child => {
|
|
51
|
+
if (child.type === 'ext') {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const str = String(child).trim();
|
|
55
|
+
return str && !/^<!--.*-->$/u.test(str);
|
|
56
|
+
}).map(child => {
|
|
57
|
+
rect ||= this.getRootNode().posFromIndex(start);
|
|
58
|
+
return generateForChild(child, rect, `<${this.name}>内的无效内容`);
|
|
59
|
+
}),
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @override
|
|
65
|
+
* @template {string|Token} T
|
|
66
|
+
* @param {T} token 待插入的子节点
|
|
67
|
+
* @param {number} i 插入位置
|
|
68
|
+
*/
|
|
69
|
+
insertAt(token, i = this.childNodes.length) {
|
|
70
|
+
return token.type === 'ext' && !this.#tags.includes(token.name)
|
|
71
|
+
? this.typeError(`${this.constructor.name}只能以${this.#tags.join('或')}标签作为子节点!`)
|
|
72
|
+
: super.insertAt(token, i);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** @override */
|
|
76
|
+
cloneNode() {
|
|
77
|
+
const cloned = this.cloneChildNodes(),
|
|
78
|
+
config = this.getAttribute('config');
|
|
79
|
+
return Parser.run(() => {
|
|
80
|
+
const token = new this.constructor(undefined, config);
|
|
81
|
+
token.append(...cloned);
|
|
82
|
+
return token;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Parser.classes.NestedToken = __filename;
|
|
88
|
+
module.exports = NestedToken;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Parser = require('../..'),
|
|
4
|
+
NestedToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<references>`
|
|
8
|
+
* @classdesc `{childNodes: [...ExtToken|NoincludeToken]}`
|
|
9
|
+
*/
|
|
10
|
+
class ReferencesToken extends NestedToken {
|
|
11
|
+
name = 'references';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string|undefined} wikitext wikitext
|
|
15
|
+
* @param {accum} accum
|
|
16
|
+
*/
|
|
17
|
+
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
18
|
+
super(wikitext, /<(ref)(\s[^>]*)?>(.*?)<\/(ref\s*)>/gisu, ['ref'], config, accum);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Parser.classes.ReferencesToken = __filename;
|
|
23
|
+
module.exports = ReferencesToken;
|
package/src/nowiki/comment.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const hidden = require('../../mixin/hidden'),
|
|
4
|
+
{generateForSelf} = require('../../util/lint'),
|
|
4
5
|
Parser = require('../..'),
|
|
5
6
|
NowikiToken = require('.');
|
|
6
7
|
|
|
@@ -29,8 +30,21 @@ class CommentToken extends hidden(NowikiToken) {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
/** @override */
|
|
32
|
-
|
|
33
|
-
return
|
|
33
|
+
getPadding() {
|
|
34
|
+
return 4;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @override */
|
|
38
|
+
print() {
|
|
39
|
+
return super.print({pre: '<!--', post: this.closed ? '-->' : ''});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @override
|
|
44
|
+
* @param {number} start 起始位置
|
|
45
|
+
*/
|
|
46
|
+
lint(start = 0) {
|
|
47
|
+
return this.closed ? [] : [generateForSelf(this, this.getRootNode().posFromIndex(start), '未闭合的HTML注释')];
|
|
34
48
|
}
|
|
35
49
|
|
|
36
50
|
/**
|
|
@@ -48,8 +62,8 @@ class CommentToken extends hidden(NowikiToken) {
|
|
|
48
62
|
}
|
|
49
63
|
|
|
50
64
|
/** @override */
|
|
51
|
-
|
|
52
|
-
return
|
|
65
|
+
cloneNode() {
|
|
66
|
+
return Parser.run(() => new CommentToken(String(this.firstChild), this.closed, this.getAttribute('config')));
|
|
53
67
|
}
|
|
54
68
|
}
|
|
55
69
|
|
package/src/nowiki/dd.js
CHANGED
|
@@ -32,9 +32,9 @@ class DdToken extends NowikiToken {
|
|
|
32
32
|
|
|
33
33
|
set indent(indent) {
|
|
34
34
|
if (this.type === 'dd') {
|
|
35
|
-
if (
|
|
35
|
+
if (!Number.isInteger(indent)) {
|
|
36
36
|
this.typeError('set indent', 'Number');
|
|
37
|
-
} else if (
|
|
37
|
+
} else if (indent < 0) {
|
|
38
38
|
throw new RangeError(`indent 应为自然数!${indent}`);
|
|
39
39
|
}
|
|
40
40
|
this.setText(':'.repeat(indent));
|
|
@@ -11,18 +11,14 @@ const hidden = require('../../mixin/hidden'),
|
|
|
11
11
|
class DoubleUnderscoreToken extends hidden(NowikiToken) {
|
|
12
12
|
type = 'double-underscore';
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*/
|
|
18
|
-
constructor(word, config = Parser.getConfig(), accum = []) {
|
|
19
|
-
super(word, config, accum);
|
|
20
|
-
this.setAttribute('name', word.toLowerCase());
|
|
14
|
+
/** @override */
|
|
15
|
+
getPadding() {
|
|
16
|
+
return 2;
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
/** @override */
|
|
24
|
-
|
|
25
|
-
return
|
|
20
|
+
print() {
|
|
21
|
+
return super.print({pre: '__', post: '__'});
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
/**
|
|
@@ -33,9 +29,18 @@ class DoubleUnderscoreToken extends hidden(NowikiToken) {
|
|
|
33
29
|
return selector && this.matches(selector) ? '' : `__${String(this.firstChild)}__`;
|
|
34
30
|
}
|
|
35
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} word 状态开关名
|
|
34
|
+
* @param {accum} accum
|
|
35
|
+
*/
|
|
36
|
+
constructor(word, config = Parser.getConfig(), accum = []) {
|
|
37
|
+
super(word, config, accum);
|
|
38
|
+
this.setAttribute('name', word.toLowerCase());
|
|
39
|
+
}
|
|
40
|
+
|
|
36
41
|
/** @override */
|
|
37
|
-
|
|
38
|
-
return
|
|
42
|
+
cloneNode() {
|
|
43
|
+
return Parser.run(() => new DoubleUnderscoreToken(String(this.firstChild), this.getAttribute('config')));
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
/**
|
package/src/nowiki/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fixedToken = require('../../mixin/fixedToken'),
|
|
4
|
+
{generateForSelf} = require('../../util/lint'),
|
|
4
5
|
Parser = require('../..'),
|
|
5
6
|
Token = require('..'),
|
|
6
7
|
AstText = require('../../lib/text');
|
|
@@ -20,6 +21,17 @@ class NowikiToken extends fixedToken(Token) {
|
|
|
20
21
|
super(wikitext, config, true, accum);
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @override
|
|
26
|
+
* @param {number} start 起始位置
|
|
27
|
+
*/
|
|
28
|
+
lint(start = 0) {
|
|
29
|
+
const {type, name} = this;
|
|
30
|
+
return type === 'ext-inner' && (name === 'templatestyles' || name === 'section') && String(this)
|
|
31
|
+
? [generateForSelf(this, this.getRootNode().posFromIndex(start), `<${name}>标签内不应有任何内容`)]
|
|
32
|
+
: super.lint(start);
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
/**
|
|
24
36
|
* @override
|
|
25
37
|
* @this {NowikiToken & {firstChild: AstText, constructor: typeof NowikiToken}}
|
package/src/nowiki/quote.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const {generateForSelf} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
AstText = require('../../lib/text'),
|
|
4
6
|
NowikiToken = require('.');
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -19,6 +21,31 @@ class QuoteToken extends NowikiToken {
|
|
|
19
21
|
this.setAttribute('name', String(n));
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @override
|
|
26
|
+
* @this {AstText}
|
|
27
|
+
* @param {number} start 起始位置
|
|
28
|
+
*/
|
|
29
|
+
lint(start = 0) {
|
|
30
|
+
const {previousSibling, nextSibling} = this,
|
|
31
|
+
message = `孤立的"'"`,
|
|
32
|
+
/** @type {LintError[]} */ errors = [];
|
|
33
|
+
let /** @type {LintError} */ refError;
|
|
34
|
+
if (previousSibling?.type === 'text' && previousSibling.data.at(-1) === "'") {
|
|
35
|
+
refError = generateForSelf(this, this.getRootNode().posFromIndex(start), '');
|
|
36
|
+
const {startLine, startCol} = refError,
|
|
37
|
+
[{length}] = previousSibling.data.match(/(?<!')'+$/u);
|
|
38
|
+
errors.push({message, startLine, startCol: startCol - length, endLine: startLine, endCol: startCol});
|
|
39
|
+
}
|
|
40
|
+
if (nextSibling?.type === 'text' && nextSibling.data[0] === "'") {
|
|
41
|
+
refError ||= generateForSelf(this, this.getRootNode().posFromIndex(start), '');
|
|
42
|
+
const {endLine, endCol} = refError,
|
|
43
|
+
[{length}] = nextSibling.data.match(/^'+/u);
|
|
44
|
+
errors.push({message, startLine: endLine, startCol: endCol, endLine, endCol: endCol + length});
|
|
45
|
+
}
|
|
46
|
+
return errors;
|
|
47
|
+
}
|
|
48
|
+
|
|
22
49
|
/**
|
|
23
50
|
* @override
|
|
24
51
|
* @param {string} str 新文本
|
package/src/onlyinclude.js
CHANGED
|
@@ -23,14 +23,6 @@ class OnlyincludeToken extends Token {
|
|
|
23
23
|
super(inner, config, true, accum);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
/** @override */
|
|
27
|
-
cloneNode() {
|
|
28
|
-
const cloned = this.cloneChildNodes(),
|
|
29
|
-
token = Parser.run(() => new OnlyincludeToken(undefined, this.getAttribute('config')));
|
|
30
|
-
token.append(...cloned);
|
|
31
|
-
return token;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
26
|
/**
|
|
35
27
|
* @override
|
|
36
28
|
* @param {string} selector
|
|
@@ -44,10 +36,25 @@ class OnlyincludeToken extends Token {
|
|
|
44
36
|
return 13;
|
|
45
37
|
}
|
|
46
38
|
|
|
39
|
+
/** @override */
|
|
40
|
+
print() {
|
|
41
|
+
return super.print({pre: '<onlyinclude>', post: '</onlyinclude>'});
|
|
42
|
+
}
|
|
43
|
+
|
|
47
44
|
/** @override */
|
|
48
45
|
isPlain() {
|
|
49
46
|
return true;
|
|
50
47
|
}
|
|
48
|
+
|
|
49
|
+
/** @override */
|
|
50
|
+
cloneNode() {
|
|
51
|
+
const cloned = this.cloneChildNodes();
|
|
52
|
+
return Parser.run(() => {
|
|
53
|
+
const token = new OnlyincludeToken(undefined, this.getAttribute('config'));
|
|
54
|
+
token.append(...cloned);
|
|
55
|
+
return token;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
Parser.classes.OnlyincludeToken = __filename;
|
|
@@ -0,0 +1,83 @@
|
|
|
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, {AtomToken: ':'});
|
|
21
|
+
if (wikitext) {
|
|
22
|
+
this.append(
|
|
23
|
+
...wikitext.split('\n').map(line => new AtomToken(line, 'param-line', config, accum, {AstText: ':'})),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @override
|
|
30
|
+
* @param {string} selector
|
|
31
|
+
*/
|
|
32
|
+
toString(selector) {
|
|
33
|
+
return super.toString(selector, '\n');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** @override */
|
|
37
|
+
getGaps() {
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** @override */
|
|
42
|
+
print() {
|
|
43
|
+
return super.print({sep: '\n'});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @override
|
|
48
|
+
* @param {number} start 起始位置
|
|
49
|
+
*/
|
|
50
|
+
lint(start = 0) {
|
|
51
|
+
let /** @type {{top: number, left: number}} */ rect;
|
|
52
|
+
return this.childNodes.filter(child => {
|
|
53
|
+
const {childNodes} = child,
|
|
54
|
+
i = childNodes.findIndex(({type}) => type !== 'text'),
|
|
55
|
+
str = (i >= 0 ? childNodes.slice(0, i).map(String).join('') : String(child)).trim();
|
|
56
|
+
return str && !(i >= 0 ? /^[a-z]+\s*(?:=|$)/iu : /^[a-z]+\s*=/iu).test(str);
|
|
57
|
+
}).map(child => {
|
|
58
|
+
rect ||= this.getRootNode().posFromIndex(start);
|
|
59
|
+
return generateForChild(child, rect, `${this.name}的无效参数`);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** @override */
|
|
64
|
+
text() {
|
|
65
|
+
return super.text('\n');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @override
|
|
70
|
+
* @this {ParamTagToken & {constructor: typeof ParamTagToken}}
|
|
71
|
+
*/
|
|
72
|
+
cloneNode() {
|
|
73
|
+
const cloned = this.cloneChildNodes();
|
|
74
|
+
return Parser.run(() => {
|
|
75
|
+
const token = new this.constructor(undefined, this.getAttribute('config'));
|
|
76
|
+
token.append(...cloned);
|
|
77
|
+
return token;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Parser.classes.ParamTagToken = __filename;
|
|
83
|
+
module.exports = ParamTagToken;
|
|
@@ -0,0 +1,42 @@
|
|
|
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: ...AtomToken}`
|
|
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
|
+
this.append(...wikitext.split('\n').map(line => new AtomToken(
|
|
26
|
+
line, 'param-line', config, accum, {AstText: ':', ArgToken: ':', TranscludeToken: ':'},
|
|
27
|
+
)));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** @override */
|
|
32
|
+
afterBuild() {
|
|
33
|
+
for (const heading of this.querySelectorAll('heading')) {
|
|
34
|
+
const {firstChild, lastChild, name} = heading,
|
|
35
|
+
syntax = '='.repeat(name);
|
|
36
|
+
heading.replaceWith(syntax, ...firstChild.cloneChildNodes(), `${syntax}${String(lastChild)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Parser.classes.InputboxToken = __filename;
|
|
42
|
+
module.exports = InputboxToken;
|