wikiparser-node 0.6.5-b → 0.7.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.
- package/config/default.json +832 -0
- package/config/llwiki.json +595 -0
- package/config/minimum.json +142 -0
- package/config/moegirl.json +684 -0
- package/config/zhwiki.json +803 -0
- package/index.js +73 -0
- package/lib/element.js +137 -0
- package/lib/node.js +226 -0
- package/lib/text.js +124 -0
- package/lib/title.js +53 -0
- package/mixin/hidden.js +18 -0
- package/package.json +9 -8
- package/parser/brackets.js +119 -0
- package/parser/commentAndExt.js +61 -0
- package/parser/converter.js +45 -0
- package/parser/externalLinks.js +32 -0
- package/parser/hrAndDoubleUnderscore.js +37 -0
- package/parser/html.js +41 -0
- package/parser/links.js +93 -0
- package/parser/list.js +58 -0
- package/parser/magicLinks.js +40 -0
- package/parser/quotes.js +63 -0
- package/parser/table.js +113 -0
- package/src/arg.js +89 -0
- package/src/atom/hidden.js +11 -0
- package/src/atom/index.js +26 -0
- package/src/attribute.js +253 -0
- package/src/attributes.js +150 -0
- package/src/charinsert.js +41 -0
- package/src/converter.js +70 -0
- package/src/converterFlags.js +97 -0
- package/src/converterRule.js +75 -0
- package/src/extLink.js +60 -0
- package/src/gallery.js +101 -0
- package/src/hasNowiki/index.js +32 -0
- package/src/hasNowiki/pre.js +28 -0
- package/src/heading.js +83 -0
- package/src/html.js +133 -0
- package/src/imageParameter.js +106 -0
- package/src/imagemap.js +140 -0
- package/src/imagemapLink.js +29 -0
- package/src/index.js +389 -0
- package/src/link/category.js +13 -0
- package/src/link/file.js +125 -0
- package/src/link/galleryImage.js +62 -0
- package/src/link/index.js +115 -0
- package/src/magicLink.js +68 -0
- package/src/nested/choose.js +23 -0
- package/src/nested/combobox.js +22 -0
- package/src/nested/index.js +69 -0
- package/src/nested/references.js +22 -0
- package/src/nowiki/comment.js +47 -0
- package/src/nowiki/dd.js +13 -0
- package/src/nowiki/doubleUnderscore.js +26 -0
- package/src/nowiki/hr.js +22 -0
- package/src/nowiki/index.js +34 -0
- package/src/nowiki/list.js +13 -0
- package/src/nowiki/noinclude.js +14 -0
- package/src/nowiki/quote.js +55 -0
- package/src/onlyinclude.js +39 -0
- package/src/paramTag/index.js +66 -0
- package/src/parameter.js +97 -0
- package/src/syntax.js +23 -0
- package/src/table/index.js +46 -0
- package/src/table/td.js +119 -0
- package/src/table/tr.js +74 -0
- package/src/tagPair/ext.js +118 -0
- package/src/tagPair/include.js +36 -0
- package/src/tagPair/index.js +76 -0
- package/src/transclude.js +323 -0
- package/util/base.js +17 -0
- package/util/diff.js +76 -0
- package/util/lint.js +54 -0
- package/util/string.js +60 -0
- package/bundle/bundle.min.js +0 -40
package/src/link/file.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {explode} = require('../../util/string'),
|
|
4
|
+
{generateForChild} = require('../../util/lint'),
|
|
5
|
+
Parser = require('../..'),
|
|
6
|
+
LinkToken = require('.'),
|
|
7
|
+
ImageParameterToken = require('../imageParameter');
|
|
8
|
+
|
|
9
|
+
const frame = new Set(['manualthumb', 'frameless', 'framed', 'thumbnail']),
|
|
10
|
+
horizAlign = new Set(['left', 'right', 'center', 'none']),
|
|
11
|
+
vertAlign = new Set(['baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom']);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 图片
|
|
15
|
+
* @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
|
|
16
|
+
*/
|
|
17
|
+
class FileToken extends LinkToken {
|
|
18
|
+
type = 'file';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} link 文件名
|
|
22
|
+
* @param {string|undefined} text 图片参数
|
|
23
|
+
* @param {accum} accum
|
|
24
|
+
* @param {string} delimiter `|`
|
|
25
|
+
* @complexity `n`
|
|
26
|
+
*/
|
|
27
|
+
constructor(link, text, title, config = Parser.getConfig(), accum = [], delimiter = '|') {
|
|
28
|
+
super(link, undefined, title, config, accum, delimiter);
|
|
29
|
+
this.append(...explode('-{', '}-', '|', text).map(part => new ImageParameterToken(part, config, accum)));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @override
|
|
34
|
+
* @param {number} start 起始位置
|
|
35
|
+
*/
|
|
36
|
+
lint(start = 0) {
|
|
37
|
+
const errors = super.lint(start),
|
|
38
|
+
args = this.getAllArgs(),
|
|
39
|
+
keys = [...new Set(args.map(({name}) => name))],
|
|
40
|
+
frameKeys = keys.filter(key => frame.has(key)),
|
|
41
|
+
horizAlignKeys = keys.filter(key => horizAlign.has(key)),
|
|
42
|
+
vertAlignKeys = keys.filter(key => vertAlign.has(key));
|
|
43
|
+
if (args.length === keys.length
|
|
44
|
+
&& frameKeys.length < 2 && horizAlignKeys.length < 2 && vertAlignKeys.length < 2
|
|
45
|
+
) {
|
|
46
|
+
return errors;
|
|
47
|
+
}
|
|
48
|
+
const rect = {start, ...this.getRootNode().posFromIndex(start)};
|
|
49
|
+
for (const key of keys) {
|
|
50
|
+
let relevantArgs = args.filter(({name}) => name === key);
|
|
51
|
+
if (key === 'caption') {
|
|
52
|
+
relevantArgs = [
|
|
53
|
+
...relevantArgs.slice(0, -1).filter(arg => arg.text()),
|
|
54
|
+
relevantArgs.at(-1),
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
if (relevantArgs.length > 1) {
|
|
58
|
+
errors.push(...relevantArgs.map(arg => generateForChild(arg, rect, `重复的图片${key}参数`)));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (frameKeys.size > 1) {
|
|
62
|
+
errors.push(
|
|
63
|
+
...args.filter(({name}) => frame.has(name)).map(arg => generateForChild(arg, rect, '冲突的图片框架参数')),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (horizAlignKeys.size > 1) {
|
|
67
|
+
errors.push(
|
|
68
|
+
...args.filter(({name}) => horizAlign.has(name))
|
|
69
|
+
.map(arg => generateForChild(arg, rect, '冲突的图片水平对齐参数')),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (vertAlignKeys.size > 1) {
|
|
73
|
+
errors.push(
|
|
74
|
+
...args.filter(({name}) => vertAlign.has(name))
|
|
75
|
+
.map(arg => generateForChild(arg, rect, '冲突的图片垂直对齐参数')),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return errors;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 获取所有图片参数节点
|
|
83
|
+
* @returns {ImageParameterToken[]}
|
|
84
|
+
*/
|
|
85
|
+
getAllArgs() {
|
|
86
|
+
return this.childNodes.slice(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 获取指定图片参数
|
|
91
|
+
* @param {string} key 参数名
|
|
92
|
+
* @complexity `n`
|
|
93
|
+
*/
|
|
94
|
+
getArgs(key) {
|
|
95
|
+
return this.getAllArgs().filter(({name}) => key === name);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 获取特定类型的图片属性参数节点
|
|
100
|
+
* @param {Set<string>} keys 接受的参数名
|
|
101
|
+
* @param {type} type 类型名
|
|
102
|
+
* @complexity `n`
|
|
103
|
+
*/
|
|
104
|
+
#getTypedArgs(keys, type) {
|
|
105
|
+
const args = this.getAllArgs().filter(({name}) => keys.has(name));
|
|
106
|
+
return args;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** 获取图片框架属性参数节点 */
|
|
110
|
+
getFrameArgs() {
|
|
111
|
+
return this.#getTypedArgs(frame, '框架');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** 获取图片水平对齐参数节点 */
|
|
115
|
+
getHorizAlignArgs() {
|
|
116
|
+
return this.#getTypedArgs(horizAlign, '水平对齐');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** 获取图片垂直对齐参数节点 */
|
|
120
|
+
getVertAlignArgs() {
|
|
121
|
+
return this.#getTypedArgs(vertAlign, '垂直对齐');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = FileToken;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {generateForSelf} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
Token = require('..'),
|
|
6
|
+
FileToken = require('./file');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 图片
|
|
10
|
+
* @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
|
|
11
|
+
*/
|
|
12
|
+
class GalleryImageToken extends FileToken {
|
|
13
|
+
type = 'gallery-image';
|
|
14
|
+
#invalid = false;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} link 图片文件名
|
|
18
|
+
* @param {string|undefined} text 图片参数
|
|
19
|
+
* @param {accum} accum
|
|
20
|
+
*/
|
|
21
|
+
constructor(link, text, title, config = Parser.getConfig(), accum = []) {
|
|
22
|
+
let token;
|
|
23
|
+
if (text !== undefined) {
|
|
24
|
+
token = new Token(text, config, true, accum);
|
|
25
|
+
token.type = 'temp';
|
|
26
|
+
for (let n = 1; n < Parser.MAX_STAGE; n++) {
|
|
27
|
+
token.getAttribute('parseOnce')();
|
|
28
|
+
}
|
|
29
|
+
accum.splice(accum.indexOf(token), 1);
|
|
30
|
+
}
|
|
31
|
+
super(link, token?.toString(), title, config, accum);
|
|
32
|
+
this.setAttribute('bracket', false);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @override
|
|
37
|
+
*/
|
|
38
|
+
afterBuild() {
|
|
39
|
+
const initImagemap = this.type === 'imagemap-image',
|
|
40
|
+
titleObj = this.normalizeTitle(String(this.firstChild), initImagemap ? 0 : 6, true, !initImagemap);
|
|
41
|
+
this.#invalid = titleObj.interwiki || titleObj.ns !== 6; // 只用于gallery-image的首次解析
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** @override */
|
|
45
|
+
getPadding() {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @override
|
|
51
|
+
* @param {number} start 起始位置
|
|
52
|
+
*/
|
|
53
|
+
lint(start = 0) {
|
|
54
|
+
const errors = super.lint(start);
|
|
55
|
+
if (this.#invalid) {
|
|
56
|
+
errors.push(generateForSelf(this, {start}, '无效的图库图片'));
|
|
57
|
+
}
|
|
58
|
+
return errors;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = GalleryImageToken;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {generateForChild} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
AstText = require('../../lib/text'),
|
|
6
|
+
Token = require('..'),
|
|
7
|
+
AtomToken = require('../atom');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 内链
|
|
11
|
+
* @classdesc `{childNodes: [AtomToken, ?Token]}`
|
|
12
|
+
*/
|
|
13
|
+
class LinkToken extends Token {
|
|
14
|
+
type = 'link';
|
|
15
|
+
#bracket = true;
|
|
16
|
+
#delimiter;
|
|
17
|
+
#fragment = '';
|
|
18
|
+
#encoded = false;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} link 链接标题
|
|
22
|
+
* @param {string|undefined} linkText 链接显示文字
|
|
23
|
+
* @param {accum} accum
|
|
24
|
+
* @param {string} delimiter `|`
|
|
25
|
+
*/
|
|
26
|
+
constructor(link, linkText, title, config = Parser.getConfig(), accum = [], delimiter = '|') {
|
|
27
|
+
super(undefined, config, true, accum, {
|
|
28
|
+
});
|
|
29
|
+
this.insertAt(new AtomToken(link, 'link-target', config, accum, {
|
|
30
|
+
}));
|
|
31
|
+
if (linkText !== undefined) {
|
|
32
|
+
const inner = new Token(linkText, config, true, accum, {
|
|
33
|
+
});
|
|
34
|
+
inner.type = 'link-text';
|
|
35
|
+
this.insertAt(inner.setAttribute('stage', Parser.MAX_STAGE - 1));
|
|
36
|
+
}
|
|
37
|
+
this.#delimiter = delimiter;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @override
|
|
42
|
+
*/
|
|
43
|
+
afterBuild() {
|
|
44
|
+
const titleObj = this.normalizeTitle(this.firstChild.text(), 0, false, true, true);
|
|
45
|
+
this.#fragment = titleObj.fragment;
|
|
46
|
+
this.#encoded = titleObj.encoded;
|
|
47
|
+
if (this.#delimiter?.includes('\0')) {
|
|
48
|
+
this.#delimiter = this.getAttribute('buildFromStr')(this.#delimiter, 'string');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @override
|
|
54
|
+
* @template {string} T
|
|
55
|
+
* @param {T} key 属性键
|
|
56
|
+
* @param {TokenAttribute<T>} value 属性值
|
|
57
|
+
*/
|
|
58
|
+
setAttribute(key, value) {
|
|
59
|
+
if (key === 'bracket') {
|
|
60
|
+
this.#bracket = Boolean(value);
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
return super.setAttribute(key, value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @override
|
|
68
|
+
*/
|
|
69
|
+
toString(selector) {
|
|
70
|
+
const str = super.toString(selector, this.#delimiter);
|
|
71
|
+
return this.#bracket ? `[[${str}]]` : str;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @override */
|
|
75
|
+
text() {
|
|
76
|
+
const str = super.text('|');
|
|
77
|
+
return this.#bracket ? `[[${str}]]` : str;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @override */
|
|
81
|
+
getPadding() {
|
|
82
|
+
return 2;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** @override */
|
|
86
|
+
getGaps() {
|
|
87
|
+
return this.#delimiter.length;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @override
|
|
92
|
+
* @param {number} start 起始位置
|
|
93
|
+
*/
|
|
94
|
+
lint(start = 0) {
|
|
95
|
+
const errors = super.lint(start),
|
|
96
|
+
{childNodes: [target, linkText], type: linkType} = this;
|
|
97
|
+
let rect;
|
|
98
|
+
if (this.#encoded) {
|
|
99
|
+
rect = {start, ...this.getRootNode().posFromIndex(start)};
|
|
100
|
+
errors.push(generateForChild(target, rect, '内链中不必要的URL编码'));
|
|
101
|
+
}
|
|
102
|
+
if (linkType === 'link' && linkText?.childNodes?.some(
|
|
103
|
+
/** @param {AstText} */ ({type, data}) => type === 'text' && data.includes('|'),
|
|
104
|
+
)) {
|
|
105
|
+
rect ||= {start, ...this.getRootNode().posFromIndex(start)};
|
|
106
|
+
errors.push(generateForChild(linkText, rect, '链接文本中多余的"|"', 'warning'));
|
|
107
|
+
} else if (linkType !== 'link' && this.#fragment) {
|
|
108
|
+
rect ||= {start, ...this.getRootNode().posFromIndex(start)};
|
|
109
|
+
errors.push(generateForChild(target, rect, '多余的fragment'));
|
|
110
|
+
}
|
|
111
|
+
return errors;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = LinkToken;
|
package/src/magicLink.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {generateForChild} = require('../util/lint'),
|
|
4
|
+
Parser = require('..'),
|
|
5
|
+
Token = require('.');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 自由外链
|
|
9
|
+
* @classdesc `{childNodes: [...AstText|CommentToken|IncludeToken|NoincludeToken]}`
|
|
10
|
+
*/
|
|
11
|
+
class MagicLinkToken extends Token {
|
|
12
|
+
type = 'free-ext-link';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @override
|
|
16
|
+
* @param {number} start 起始位置
|
|
17
|
+
*/
|
|
18
|
+
lint(start = 0) {
|
|
19
|
+
const errors = super.lint(start),
|
|
20
|
+
source = `[,;。:!?()]+${this.type === 'ext-link-url' ? '|\\|+' : ''}`;
|
|
21
|
+
let /** @type {{top: number, left: number}} */ rect;
|
|
22
|
+
for (const child of this.childNodes) {
|
|
23
|
+
const str = String(child);
|
|
24
|
+
if (child.type !== 'text' || !new RegExp(source, 'u').test(str)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
rect ||= {start, ...this.getRootNode().posFromIndex(start)};
|
|
28
|
+
const refError = generateForChild(child, rect, '', 'warning'),
|
|
29
|
+
regex = new RegExp(source, 'gu');
|
|
30
|
+
for (let mt = regex.exec(str); mt; mt = regex.exec(str)) {
|
|
31
|
+
const {index, 0: {0: char, length}} = mt,
|
|
32
|
+
lines = str.slice(0, index).split('\n'),
|
|
33
|
+
{length: top} = lines,
|
|
34
|
+
{length: left} = lines[top - 1],
|
|
35
|
+
startIndex = start + index,
|
|
36
|
+
startLine = refError.startLine + top - 1,
|
|
37
|
+
startCol = (top > 1 ? 0 : refError.startCol) + left;
|
|
38
|
+
errors.push({
|
|
39
|
+
...refError,
|
|
40
|
+
message: `URL中的${char === '|' ? '"|"' : '全角标点'}`,
|
|
41
|
+
startIndex,
|
|
42
|
+
endIndex: startIndex + length,
|
|
43
|
+
startLine,
|
|
44
|
+
endLine: startLine,
|
|
45
|
+
startCol,
|
|
46
|
+
endCol: startCol + length,
|
|
47
|
+
excerpt: str.slice(Math.max(0, index - 25), index + 25),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return errors;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} url 网址
|
|
56
|
+
* @param {boolean} doubleSlash 是否接受"//"作为协议
|
|
57
|
+
* @param {accum} accum
|
|
58
|
+
*/
|
|
59
|
+
constructor(url, doubleSlash, config = Parser.getConfig(), accum = []) {
|
|
60
|
+
super(url, config, true, accum, {
|
|
61
|
+
});
|
|
62
|
+
if (doubleSlash) {
|
|
63
|
+
this.type = 'ext-link-url';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = MagicLinkToken;
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
module.exports = ChooseToken;
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
module.exports = ComboboxToken;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {generateForChild} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
Token = require('..'),
|
|
6
|
+
ExtToken = require('../tagPair/ext'),
|
|
7
|
+
NoincludeToken = require('../nowiki/noinclude'),
|
|
8
|
+
CommentToken = require('../nowiki/comment');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 嵌套式的扩展标签
|
|
12
|
+
* @classdesc `{childNodes: [...ExtToken|NoincludeToken|CommentToken]}`
|
|
13
|
+
*/
|
|
14
|
+
class NestedToken extends Token {
|
|
15
|
+
type = 'ext-inner';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string|undefined} wikitext wikitext
|
|
19
|
+
* @param {RegExp} regex 内层正则
|
|
20
|
+
* @param {string[]} tags 内层标签名
|
|
21
|
+
* @param {accum} accum
|
|
22
|
+
*/
|
|
23
|
+
constructor(wikitext, regex, tags, config = Parser.getConfig(), accum = []) {
|
|
24
|
+
const text = wikitext?.replace(
|
|
25
|
+
regex,
|
|
26
|
+
/** @type {function(...string): string} */ (comment, name, attr, inner, closing) => {
|
|
27
|
+
const str = `\0${accum.length + 1}${name ? 'e' : 'c'}\x7F`;
|
|
28
|
+
if (name) {
|
|
29
|
+
new ExtToken(name, attr, inner, closing, config, accum);
|
|
30
|
+
} else {
|
|
31
|
+
const closed = comment.endsWith('-->');
|
|
32
|
+
new CommentToken(comment.slice(4, closed ? -3 : undefined), closed, config, accum);
|
|
33
|
+
}
|
|
34
|
+
return str;
|
|
35
|
+
},
|
|
36
|
+
)?.replace(/(^|\0\d+[ce]\x7F)(.*?)(?=$|\0\d+[ce]\x7F)/gsu, (_, lead, substr) => {
|
|
37
|
+
if (substr === '') {
|
|
38
|
+
return lead;
|
|
39
|
+
}
|
|
40
|
+
new NoincludeToken(substr, config, accum);
|
|
41
|
+
return `${lead}\0${accum.length}c\x7F`;
|
|
42
|
+
});
|
|
43
|
+
super(text, config, true, accum, {
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @override
|
|
49
|
+
* @param {number} start 起始位置
|
|
50
|
+
*/
|
|
51
|
+
lint(start = 0) {
|
|
52
|
+
let rect;
|
|
53
|
+
return [
|
|
54
|
+
...super.lint(start),
|
|
55
|
+
...this.childNodes.filter(child => {
|
|
56
|
+
if (child.type === 'ext' || child.type === 'comment') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const str = String(child).trim();
|
|
60
|
+
return str && !/^<!--.*-->$/u.test(str);
|
|
61
|
+
}).map(child => {
|
|
62
|
+
rect ||= {start, ...this.getRootNode().posFromIndex(start)};
|
|
63
|
+
return generateForChild(child, rect, `<${this.name}>内的无效内容`);
|
|
64
|
+
}),
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = NestedToken;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Parser = require('../..'),
|
|
4
|
+
NestedToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<references>`
|
|
8
|
+
* @classdesc `{childNodes: [...ExtToken|NoincludeToken|CommentToken]}`
|
|
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
|
+
module.exports = ReferencesToken;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const hidden = require('../../mixin/hidden'),
|
|
4
|
+
{generateForSelf} = require('../../util/lint'),
|
|
5
|
+
Parser = require('../..'),
|
|
6
|
+
NowikiToken = require('.');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* HTML注释,不可见
|
|
10
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
11
|
+
*/
|
|
12
|
+
class CommentToken extends hidden(NowikiToken) {
|
|
13
|
+
type = 'comment';
|
|
14
|
+
closed;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} wikitext wikitext
|
|
18
|
+
* @param {boolean} closed 是否闭合
|
|
19
|
+
* @param {accum} accum
|
|
20
|
+
*/
|
|
21
|
+
constructor(wikitext, closed = true, config = Parser.getConfig(), accum = []) {
|
|
22
|
+
super(wikitext, config, accum);
|
|
23
|
+
this.closed = closed;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @override */
|
|
27
|
+
getPadding() {
|
|
28
|
+
return 4;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @override
|
|
33
|
+
* @param {number} start 起始位置
|
|
34
|
+
*/
|
|
35
|
+
lint(start = 0) {
|
|
36
|
+
return this.closed ? [] : [generateForSelf(this, {start}, '未闭合的HTML注释')];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @override
|
|
41
|
+
*/
|
|
42
|
+
toString(selector) {
|
|
43
|
+
return `<!--${String(this.firstChild)}${this.closed ? '-->' : ''}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = CommentToken;
|
package/src/nowiki/dd.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const hidden = require('../../mixin/hidden'),
|
|
4
|
+
NowikiToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 状态开关
|
|
8
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
9
|
+
*/
|
|
10
|
+
class DoubleUnderscoreToken extends hidden(NowikiToken) {
|
|
11
|
+
type = 'double-underscore';
|
|
12
|
+
|
|
13
|
+
/** @override */
|
|
14
|
+
getPadding() {
|
|
15
|
+
return 2;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @override
|
|
20
|
+
*/
|
|
21
|
+
toString(selector) {
|
|
22
|
+
return `__${String(this.firstChild)}__`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = DoubleUnderscoreToken;
|
package/src/nowiki/hr.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Parser = require('../..'),
|
|
4
|
+
NowikiToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<hr>`
|
|
8
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
9
|
+
*/
|
|
10
|
+
class HrToken extends NowikiToken {
|
|
11
|
+
type = 'hr';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {number} n 字符串长度
|
|
15
|
+
* @param {accum} accum
|
|
16
|
+
*/
|
|
17
|
+
constructor(n, config = Parser.getConfig(), accum = []) {
|
|
18
|
+
super('-'.repeat(n), config, accum);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = HrToken;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {generateForSelf} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
Token = require('..');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 纯文字Token,不会被解析
|
|
9
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
10
|
+
*/
|
|
11
|
+
class NowikiToken extends Token {
|
|
12
|
+
type = 'ext-inner';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {string} wikitext wikitext
|
|
16
|
+
* @param {accum} accum
|
|
17
|
+
*/
|
|
18
|
+
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
19
|
+
super(wikitext, config, true, accum);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @override
|
|
24
|
+
* @param {number} start 起始位置
|
|
25
|
+
*/
|
|
26
|
+
lint(start = 0) {
|
|
27
|
+
const {type, name} = this;
|
|
28
|
+
return type === 'ext-inner' && (name === 'templatestyles' || name === 'section') && String(this)
|
|
29
|
+
? [generateForSelf(this, {start}, `<${name}>标签内不应有任何内容`)]
|
|
30
|
+
: super.lint(start);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = NowikiToken;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const hidden = require('../../mixin/hidden'),
|
|
4
|
+
NowikiToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<noinclude>`和`</noinclude>`,不可进行任何更改
|
|
8
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
9
|
+
*/
|
|
10
|
+
class NoincludeToken extends hidden(NowikiToken) {
|
|
11
|
+
type = 'noinclude';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = NoincludeToken;
|