wikiparser-node 0.11.0-m → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/.schema.json +7 -0
- package/config/default.json +1 -0
- package/config/llwiki.json +35 -0
- package/config/moegirl.json +44 -0
- package/config/zhwiki.json +466 -0
- package/dist/index.d.ts +4 -0
- package/dist/lib/element.d.ts +116 -2
- package/dist/lib/node.d.ts +193 -10
- package/dist/lib/ranges.d.ts +37 -0
- package/dist/lib/text.d.ts +35 -1
- package/dist/lib/title.d.ts +6 -0
- package/dist/mixin/attributeParent.d.ts +9 -0
- package/dist/mixin/fixedToken.d.ts +8 -0
- package/dist/mixin/singleLine.d.ts +8 -0
- package/dist/mixin/sol.d.ts +8 -0
- package/dist/parser/selector.d.ts +12 -0
- package/dist/src/arg.d.ts +30 -1
- package/dist/src/atom/index.d.ts +2 -1
- package/dist/src/attribute.d.ts +24 -1
- package/dist/src/attributes.d.ts +79 -0
- package/dist/src/charinsert.d.ts +32 -0
- package/dist/src/converter.d.ts +75 -1
- package/dist/src/converterFlags.d.ts +57 -1
- package/dist/src/converterRule.d.ts +47 -1
- package/dist/src/extLink.d.ts +41 -1
- package/dist/src/gallery.d.ts +15 -1
- package/dist/src/heading.d.ts +22 -2
- package/dist/src/html.d.ts +25 -2
- package/dist/src/imageParameter.d.ts +43 -1
- package/dist/src/imagemap.d.ts +12 -1
- package/dist/src/imagemapLink.d.ts +5 -0
- package/dist/src/index.d.ts +136 -3
- package/dist/src/link/category.d.ts +8 -0
- package/dist/src/link/file.d.ts +58 -0
- package/dist/src/link/index.d.ts +61 -2
- package/dist/src/magicLink.d.ts +22 -0
- package/dist/src/nested/index.d.ts +3 -5
- package/dist/src/nowiki/comment.d.ts +13 -1
- package/dist/src/nowiki/dd.d.ts +9 -0
- package/dist/src/nowiki/doubleUnderscore.d.ts +11 -1
- package/dist/src/nowiki/index.d.ts +11 -2
- package/dist/src/nowiki/quote.d.ts +0 -7
- package/dist/src/onlyinclude.d.ts +8 -1
- package/dist/src/paramTag/index.d.ts +8 -3
- package/dist/src/parameter.d.ts +48 -1
- package/dist/src/syntax.d.ts +6 -1
- package/dist/src/table/index.d.ts +257 -0
- package/dist/src/table/td.d.ts +67 -6
- package/dist/src/table/tr.d.ts +74 -0
- package/dist/src/tagPair/ext.d.ts +2 -1
- package/dist/src/tagPair/include.d.ts +9 -0
- package/dist/src/tagPair/index.d.ts +14 -1
- package/dist/src/transclude.d.ts +125 -1
- package/dist/tool/index.d.ts +420 -0
- package/dist/util/base.d.ts +10 -0
- package/dist/util/debug.d.ts +20 -0
- package/dist/util/diff.d.ts +8 -0
- package/dist/util/string.d.ts +24 -0
- package/index.js +256 -4
- package/lib/element.js +488 -6
- package/lib/node.js +495 -6
- package/lib/ranges.js +130 -0
- package/lib/text.js +96 -1
- package/lib/title.js +28 -1
- package/mixin/attributeParent.js +117 -0
- package/mixin/fixedToken.js +40 -0
- package/mixin/hidden.js +3 -0
- package/mixin/singleLine.js +31 -0
- package/mixin/sol.js +54 -0
- package/package.json +5 -2
- package/parser/brackets.js +1 -0
- package/parser/commentAndExt.js +1 -0
- package/parser/converter.js +1 -0
- package/parser/externalLinks.js +1 -0
- package/parser/hrAndDoubleUnderscore.js +1 -0
- package/parser/html.js +1 -0
- package/parser/links.js +5 -4
- package/parser/list.js +1 -0
- package/parser/magicLinks.js +1 -0
- package/parser/quotes.js +1 -0
- package/parser/selector.js +180 -0
- package/parser/table.js +1 -0
- package/src/arg.js +116 -2
- package/src/atom/hidden.js +2 -0
- package/src/atom/index.js +17 -0
- package/src/attribute.js +189 -3
- package/src/attributes.js +307 -4
- package/src/charinsert.js +97 -0
- package/src/converter.js +108 -2
- package/src/converterFlags.js +187 -0
- package/src/converterRule.js +183 -1
- package/src/extLink.js +121 -1
- package/src/gallery.js +54 -0
- package/src/hasNowiki/index.js +12 -0
- package/src/hasNowiki/pre.js +12 -0
- package/src/heading.js +54 -3
- package/src/html.js +118 -3
- package/src/imageParameter.js +164 -2
- package/src/imagemap.js +61 -2
- package/src/imagemapLink.js +13 -1
- package/src/index.js +530 -3
- package/src/link/category.js +32 -1
- package/src/link/file.js +157 -2
- package/src/link/galleryImage.js +60 -2
- package/src/link/index.js +270 -1
- package/src/magicLink.js +83 -0
- package/src/nested/choose.js +1 -0
- package/src/nested/combobox.js +1 -0
- package/src/nested/index.js +27 -0
- package/src/nested/references.js +1 -0
- package/src/nowiki/comment.js +25 -1
- package/src/nowiki/dd.js +47 -1
- package/src/nowiki/doubleUnderscore.js +31 -1
- package/src/nowiki/hr.js +20 -1
- package/src/nowiki/index.js +23 -1
- package/src/nowiki/list.js +5 -2
- package/src/nowiki/noinclude.js +14 -0
- package/src/nowiki/quote.js +14 -0
- package/src/onlyinclude.js +26 -1
- package/src/paramTag/index.js +24 -1
- package/src/paramTag/inputbox.js +4 -1
- package/src/parameter.js +147 -5
- package/src/syntax.js +68 -0
- package/src/table/index.js +941 -2
- package/src/table/td.js +230 -5
- package/src/table/tr.js +247 -2
- package/src/tagPair/ext.js +21 -1
- package/src/tagPair/include.js +24 -0
- package/src/tagPair/index.js +56 -2
- package/src/transclude.js +512 -5
- package/tool/index.js +1209 -0
- package/typings/array.d.ts +29 -0
- package/typings/event.d.ts +22 -0
- package/typings/index.d.ts +67 -0
- package/typings/node.d.ts +19 -0
- package/typings/parser.d.ts +7 -0
- package/typings/table.d.ts +10 -0
- package/typings/token.d.ts +3 -0
- package/typings/tool.d.ts +6 -0
- package/util/debug.js +73 -0
- package/util/string.js +51 -0
package/src/hasNowiki/index.js
CHANGED
|
@@ -24,9 +24,21 @@ class HasNowikiToken extends Token {
|
|
|
24
24
|
},
|
|
25
25
|
);
|
|
26
26
|
super(wikitext, config, true, accum, {
|
|
27
|
+
AstText: ':', NoincludeToken: ':',
|
|
27
28
|
});
|
|
28
29
|
this.type = type;
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
/** @override */
|
|
33
|
+
cloneNode() {
|
|
34
|
+
const cloned = this.cloneChildNodes();
|
|
35
|
+
return Parser.run(() => {
|
|
36
|
+
const token = new HasNowikiToken(undefined, this.type, this.getAttribute('config'));
|
|
37
|
+
token.append(...cloned);
|
|
38
|
+
return token;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
30
41
|
}
|
|
31
42
|
|
|
43
|
+
Parser.classes.HasNowikiToken = __filename;
|
|
32
44
|
module.exports = HasNowikiToken;
|
package/src/hasNowiki/pre.js
CHANGED
|
@@ -17,12 +17,24 @@ class PreToken extends HasNowikiToken {
|
|
|
17
17
|
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
18
18
|
super(wikitext, 'ext-inner', config, accum);
|
|
19
19
|
this.setAttribute('stage', Parser.MAX_STAGE - 1);
|
|
20
|
+
this.setAttribute('acceptable', {AstText: ':', NoincludeToken: ':', ConverterToken: ':'});
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/** @override */
|
|
23
24
|
isPlain() {
|
|
24
25
|
return true;
|
|
25
26
|
}
|
|
27
|
+
|
|
28
|
+
/** @override */
|
|
29
|
+
cloneNode() {
|
|
30
|
+
const cloned = this.cloneChildNodes();
|
|
31
|
+
return Parser.run(() => {
|
|
32
|
+
const token = new PreToken(undefined, this.getAttribute('config'));
|
|
33
|
+
token.append(...cloned);
|
|
34
|
+
return token;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
|
|
39
|
+
Parser.classes.PreToken = __filename;
|
|
28
40
|
module.exports = PreToken;
|
package/src/heading.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {generateForSelf} = require('../util/lint'),
|
|
4
|
+
fixedToken = require('../mixin/fixedToken'),
|
|
5
|
+
sol = require('../mixin/sol'),
|
|
4
6
|
Parser = require('..'),
|
|
5
7
|
Token = require('.'),
|
|
6
8
|
SyntaxToken = require('./syntax');
|
|
@@ -9,9 +11,14 @@ const {generateForSelf} = require('../util/lint'),
|
|
|
9
11
|
* 章节标题
|
|
10
12
|
* @classdesc `{childNodes: [Token, SyntaxToken]}`
|
|
11
13
|
*/
|
|
12
|
-
class HeadingToken extends Token {
|
|
14
|
+
class HeadingToken extends fixedToken(sol(Token)) {
|
|
13
15
|
type = 'heading';
|
|
14
16
|
|
|
17
|
+
/** 内部wikitext */
|
|
18
|
+
get innerText() {
|
|
19
|
+
return this.firstChild.text();
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
/**
|
|
16
23
|
* @param {number} level 标题层级
|
|
17
24
|
* @param {string[]} input 标题文字
|
|
@@ -22,28 +29,37 @@ class HeadingToken extends Token {
|
|
|
22
29
|
this.setAttribute('name', String(level));
|
|
23
30
|
const token = new Token(input[0], config, true, accum);
|
|
24
31
|
token.type = 'heading-title';
|
|
32
|
+
token.setAttribute('name', this.name);
|
|
25
33
|
token.setAttribute('stage', 2);
|
|
26
34
|
const trail = new SyntaxToken(input[1], /^[^\S\n]*$/u, 'heading-trail', config, accum, {
|
|
35
|
+
'Stage-1': ':', '!ExtToken': '',
|
|
27
36
|
});
|
|
28
37
|
this.append(token, trail);
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
/**
|
|
32
41
|
* @override
|
|
42
|
+
* @this {{prependNewLine(): ''|'\n'} & HeadingToken}
|
|
43
|
+
* @param {string} selector
|
|
33
44
|
* @returns {string}
|
|
34
45
|
*/
|
|
35
46
|
toString(selector) {
|
|
36
47
|
const equals = '='.repeat(Number(this.name));
|
|
37
|
-
return
|
|
48
|
+
return selector && this.matches(selector)
|
|
49
|
+
? ''
|
|
50
|
+
: `${this.prependNewLine()}${equals}${
|
|
51
|
+
this.firstChild.toString(selector)
|
|
52
|
+
}${equals}${this.lastChild.toString(selector)}`;
|
|
38
53
|
}
|
|
39
54
|
|
|
40
55
|
/**
|
|
41
56
|
* @override
|
|
57
|
+
* @this {HeadingToken & {prependNewLine(): ''|'\n'}}
|
|
42
58
|
* @returns {string}
|
|
43
59
|
*/
|
|
44
60
|
text() {
|
|
45
61
|
const equals = '='.repeat(Number(this.name));
|
|
46
|
-
return `${equals}${this.firstChild.text()}${equals}`;
|
|
62
|
+
return `${this.prependNewLine()}${equals}${this.firstChild.text()}${equals}`;
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
/** @override */
|
|
@@ -56,6 +72,12 @@ class HeadingToken extends Token {
|
|
|
56
72
|
return Number(this.name);
|
|
57
73
|
}
|
|
58
74
|
|
|
75
|
+
/** @override */
|
|
76
|
+
print() {
|
|
77
|
+
const equals = '='.repeat(Number(this.name));
|
|
78
|
+
return super.print({pre: equals, sep: equals});
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
/**
|
|
60
82
|
* @override
|
|
61
83
|
* @param {number} start 起始位置
|
|
@@ -78,6 +100,35 @@ class HeadingToken extends Token {
|
|
|
78
100
|
}
|
|
79
101
|
return errors;
|
|
80
102
|
}
|
|
103
|
+
|
|
104
|
+
/** @override */
|
|
105
|
+
cloneNode() {
|
|
106
|
+
const [title, trail] = this.cloneChildNodes();
|
|
107
|
+
return Parser.run(() => {
|
|
108
|
+
const token = new HeadingToken(Number(this.name), [], this.getAttribute('config'));
|
|
109
|
+
token.firsthild.safeReplaceWith(title);
|
|
110
|
+
token.lastChild.safeReplaceWith(trail);
|
|
111
|
+
return token;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 设置标题层级
|
|
117
|
+
* @param {number} n 标题层级
|
|
118
|
+
*/
|
|
119
|
+
setLevel(n) {
|
|
120
|
+
if (!Number.isInteger(n)) {
|
|
121
|
+
this.typeError('setLevel', 'Number');
|
|
122
|
+
}
|
|
123
|
+
n = Math.min(Math.max(n, 1), 6);
|
|
124
|
+
this.setAttribute('name', String(n)).firstChild.setAttribute('name', this.name);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** 移除标题后的不可见内容 */
|
|
128
|
+
removeTrail() {
|
|
129
|
+
this.lastChild.replaceChildren();
|
|
130
|
+
}
|
|
81
131
|
}
|
|
82
132
|
|
|
133
|
+
Parser.classes.HeadingToken = __filename;
|
|
83
134
|
module.exports = HeadingToken;
|
package/src/html.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {generateForSelf} = require('../util/lint'),
|
|
4
|
+
{noWrap} = require('../util/string'),
|
|
5
|
+
fixedToken = require('../mixin/fixedToken'),
|
|
6
|
+
attributeParent = require('../mixin/attributeParent'),
|
|
4
7
|
Parser = require('..'),
|
|
5
8
|
Token = require('.');
|
|
6
9
|
|
|
@@ -10,7 +13,7 @@ const magicWords = new Set(['if', 'ifeq', 'ifexpr', 'ifexist', 'iferror', 'switc
|
|
|
10
13
|
* HTML标签
|
|
11
14
|
* @classdesc `{childNodes: [AttributesToken]}`
|
|
12
15
|
*/
|
|
13
|
-
class HtmlToken extends Token {
|
|
16
|
+
class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
14
17
|
type = 'html';
|
|
15
18
|
#closing;
|
|
16
19
|
#selfClosing;
|
|
@@ -21,6 +24,41 @@ class HtmlToken extends Token {
|
|
|
21
24
|
return this.#closing;
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
/** @throws `Error` 自闭合标签或空标签 */
|
|
28
|
+
set closing(value) {
|
|
29
|
+
if (!value) {
|
|
30
|
+
this.#closing = false;
|
|
31
|
+
return;
|
|
32
|
+
} else if (this.#selfClosing) {
|
|
33
|
+
throw new Error('这是一个自闭合标签!');
|
|
34
|
+
}
|
|
35
|
+
const {html: [,, tags]} = this.getAttribute('config');
|
|
36
|
+
if (tags.includes(this.name)) {
|
|
37
|
+
throw new Error('这是一个空标签!');
|
|
38
|
+
}
|
|
39
|
+
this.#closing = true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** getter */
|
|
43
|
+
get selfClosing() {
|
|
44
|
+
return this.#selfClosing;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @throws `Error` 闭合标签或无效自闭合标签 */
|
|
48
|
+
set selfClosing(value) {
|
|
49
|
+
if (!value) {
|
|
50
|
+
this.#selfClosing = false;
|
|
51
|
+
return;
|
|
52
|
+
} else if (this.#closing) {
|
|
53
|
+
throw new Error('这是一个闭合标签!');
|
|
54
|
+
}
|
|
55
|
+
const {html: [tags]} = this.getAttribute('config');
|
|
56
|
+
if (tags.includes(this.name)) {
|
|
57
|
+
throw new Error(`<${this.name}>标签自闭合无效!`);
|
|
58
|
+
}
|
|
59
|
+
this.#selfClosing = true;
|
|
60
|
+
}
|
|
61
|
+
|
|
24
62
|
/**
|
|
25
63
|
* @param {string} name 标签名
|
|
26
64
|
* @param {AttributesToken} attr 标签属性
|
|
@@ -39,9 +77,12 @@ class HtmlToken extends Token {
|
|
|
39
77
|
|
|
40
78
|
/**
|
|
41
79
|
* @override
|
|
80
|
+
* @param {string} selector
|
|
42
81
|
*/
|
|
43
82
|
toString(selector) {
|
|
44
|
-
return
|
|
83
|
+
return selector && this.matches(selector)
|
|
84
|
+
? ''
|
|
85
|
+
: `<${this.#closing ? '/' : ''}${this.#tag}${super.toString(selector)}${this.#selfClosing ? '/' : ''}>`;
|
|
45
86
|
}
|
|
46
87
|
|
|
47
88
|
/** @override */
|
|
@@ -56,6 +97,14 @@ class HtmlToken extends Token {
|
|
|
56
97
|
return this.#tag.length + (this.#closing ? 2 : 1);
|
|
57
98
|
}
|
|
58
99
|
|
|
100
|
+
/** @override */
|
|
101
|
+
print() {
|
|
102
|
+
return super.print({
|
|
103
|
+
pre: `<${this.#closing ? '/' : ''}${this.#tag}`,
|
|
104
|
+
post: `${this.#selfClosing ? '/' : ''}>`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
59
108
|
/**
|
|
60
109
|
* @override
|
|
61
110
|
* @param {number} start 起始位置
|
|
@@ -106,7 +155,7 @@ class HtmlToken extends Token {
|
|
|
106
155
|
findMatchingTag() {
|
|
107
156
|
const {html} = this.getAttribute('config'),
|
|
108
157
|
{name: tagName, parentNode} = this,
|
|
109
|
-
string = String(this);
|
|
158
|
+
string = noWrap(String(this));
|
|
110
159
|
if (this.#closing && (this.#selfClosing || html[2].includes(tagName))) {
|
|
111
160
|
throw new SyntaxError(`tag that is both closing and self-closing: ${string}`);
|
|
112
161
|
} else if (html[2].includes(tagName) || this.#selfClosing && html[1].includes(tagName)) { // 自封闭标签
|
|
@@ -134,6 +183,72 @@ class HtmlToken extends Token {
|
|
|
134
183
|
}
|
|
135
184
|
throw new SyntaxError(`${this.#closing ? 'unmatched closing' : 'unclosed'} tag: ${string}`);
|
|
136
185
|
}
|
|
186
|
+
|
|
187
|
+
/** @override */
|
|
188
|
+
cloneNode() {
|
|
189
|
+
const [attr] = this.cloneChildNodes(),
|
|
190
|
+
config = this.getAttribute('config');
|
|
191
|
+
return Parser.run(() => new HtmlToken(this.#tag, attr, this.#closing, this.#selfClosing, config));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @override
|
|
196
|
+
* @template {string} T
|
|
197
|
+
* @param {T} key 属性键
|
|
198
|
+
* @returns {import('../typings/node').TokenAttribute<T>}
|
|
199
|
+
*/
|
|
200
|
+
getAttribute(key) {
|
|
201
|
+
return key === 'tag' ? this.#tag : super.getAttribute(key);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 更换标签名
|
|
206
|
+
* @param {string} tag 标签名
|
|
207
|
+
* @throws `RangeError` 非法的HTML标签
|
|
208
|
+
*/
|
|
209
|
+
replaceTag(tag) {
|
|
210
|
+
const name = tag.toLowerCase();
|
|
211
|
+
if (!this.getAttribute('config').html.flat().includes(name)) {
|
|
212
|
+
throw new RangeError(`非法的HTML标签:${tag}`);
|
|
213
|
+
}
|
|
214
|
+
this.setAttribute('name', name).#tag = tag;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** 局部闭合 */
|
|
218
|
+
#localMatch() {
|
|
219
|
+
this.#selfClosing = false;
|
|
220
|
+
const root = Parser.parse(`</${this.name}>`, false, 3, this.getAttribute('config'));
|
|
221
|
+
this.after(root.firstChild);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 修复无效自封闭标签
|
|
226
|
+
* @complexity `n`
|
|
227
|
+
* @throws `Error` 无法修复无效自封闭标签
|
|
228
|
+
*/
|
|
229
|
+
fix() {
|
|
230
|
+
const config = this.getAttribute('config'),
|
|
231
|
+
{parentNode, name: tagName, firstChild} = this;
|
|
232
|
+
if (!parentNode || !this.#selfClosing || !config.html[0].includes(tagName)) {
|
|
233
|
+
return;
|
|
234
|
+
} else if (firstChild.text().trim()) {
|
|
235
|
+
this.#localMatch();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const {childNodes} = parentNode,
|
|
239
|
+
i = childNodes.indexOf(this),
|
|
240
|
+
/** @type {HtmlToken[]} */
|
|
241
|
+
prevSiblings = childNodes.slice(0, i).filter(({type, name}) => type === 'html' && name === tagName),
|
|
242
|
+
imbalance = prevSiblings.reduce((acc, {closing}) => acc + (closing ? 1 : -1), 0);
|
|
243
|
+
if (imbalance < 0) {
|
|
244
|
+
this.#selfClosing = false;
|
|
245
|
+
this.#closing = true;
|
|
246
|
+
} else {
|
|
247
|
+
Parser.warn('无法修复无效自封闭标签', noWrap(String(this)));
|
|
248
|
+
throw new Error(`无法修复无效自封闭标签:前文共有 ${imbalance} 个未匹配的闭合标签`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
137
251
|
}
|
|
138
252
|
|
|
253
|
+
Parser.classes.HtmlToken = __filename;
|
|
139
254
|
module.exports = HtmlToken;
|
package/src/imageParameter.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {extUrlChar, extUrlCharFirst} = require('../util/string'),
|
|
3
|
+
const {text, noWrap, print, extUrlChar, extUrlCharFirst} = require('../util/string'),
|
|
4
4
|
{generateForSelf} = require('../util/lint'),
|
|
5
5
|
Title = require('../lib/title'),
|
|
6
6
|
Parser = require('..'),
|
|
7
|
+
AstText = require('../lib/text'),
|
|
7
8
|
Token = require('.');
|
|
8
9
|
|
|
9
10
|
const params = new Set(['alt', 'link', 'lang', 'page', 'caption']);
|
|
@@ -61,6 +62,66 @@ class ImageParameterToken extends Token {
|
|
|
61
62
|
return this.name === 'link' ? validate('link', super.text(), this.getAttribute('config')) : undefined;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
set link(value) {
|
|
66
|
+
if (this.name === 'link') {
|
|
67
|
+
this.setValue(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** getValue()的getter */
|
|
72
|
+
get value() {
|
|
73
|
+
return this.getValue();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
set value(value) {
|
|
77
|
+
this.setValue(value);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 图片大小 */
|
|
81
|
+
get size() {
|
|
82
|
+
if (this.name === 'width') {
|
|
83
|
+
const /** @type {string} */ size = this.getValue().trim();
|
|
84
|
+
if (!size.includes('{{')) {
|
|
85
|
+
const [width, height = ''] = size.split('x');
|
|
86
|
+
return {width, height};
|
|
87
|
+
}
|
|
88
|
+
const /** @type {{childNodes: AstText[]}} */ token = Parser.parse(size, false, 2, this.getAttribute('config')),
|
|
89
|
+
i = token.childNodes.findIndex(({type, data}) => type === 'text' && data.includes('x')),
|
|
90
|
+
str = token.childNodes[i];
|
|
91
|
+
if (i === -1) {
|
|
92
|
+
return {width: size, height: ''};
|
|
93
|
+
}
|
|
94
|
+
str.splitText(str.data.indexOf('x'));
|
|
95
|
+
str.nextSibling.splitText(1);
|
|
96
|
+
return {width: text(token.childNodes.slice(0, i + 1)), height: text(token.childNodes.slice(i + 2))};
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** 图片宽度 */
|
|
102
|
+
get width() {
|
|
103
|
+
return this.size?.width;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
set width(width) {
|
|
107
|
+
if (this.name === 'width') {
|
|
108
|
+
const {height} = this;
|
|
109
|
+
this.setValue(`${String(width || '')}${height && 'x'}${height}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** 图片高度 */
|
|
114
|
+
get height() {
|
|
115
|
+
return this.size?.height;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
set height(height) {
|
|
119
|
+
height = String(height || '');
|
|
120
|
+
if (this.name === 'width') {
|
|
121
|
+
this.setValue(`${this.width}${height && 'x'}${height}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
64
125
|
/**
|
|
65
126
|
* @param {string} str 图片参数
|
|
66
127
|
* @param {import('../typings/token').accum} accum
|
|
@@ -81,6 +142,7 @@ class ImageParameterToken extends Token {
|
|
|
81
142
|
this.#syntax = str;
|
|
82
143
|
} else {
|
|
83
144
|
super(mt[2], config, true, accum, {
|
|
145
|
+
'Stage-2': ':', '!HeadingToken': ':',
|
|
84
146
|
});
|
|
85
147
|
this.#syntax = `${mt[1]}${param[0]}${mt[3]}`;
|
|
86
148
|
}
|
|
@@ -105,9 +167,10 @@ class ImageParameterToken extends Token {
|
|
|
105
167
|
|
|
106
168
|
/**
|
|
107
169
|
* @override
|
|
170
|
+
* @param {string} selector
|
|
108
171
|
*/
|
|
109
172
|
toString(selector) {
|
|
110
|
-
return this.#syntax
|
|
173
|
+
return this.#syntax && !(selector && this.matches(selector))
|
|
111
174
|
? this.#syntax.replace('$1', super.toString(selector))
|
|
112
175
|
: super.toString(selector);
|
|
113
176
|
}
|
|
@@ -136,6 +199,105 @@ class ImageParameterToken extends Token {
|
|
|
136
199
|
}
|
|
137
200
|
return errors;
|
|
138
201
|
}
|
|
202
|
+
|
|
203
|
+
/** @override */
|
|
204
|
+
print() {
|
|
205
|
+
return this.#syntax
|
|
206
|
+
? `<span class="wpb-image-parameter">${
|
|
207
|
+
this.#syntax.replace('$1', `<span class="wpb-image-caption">${print(this.childNodes)}</span>`)
|
|
208
|
+
}</span>`
|
|
209
|
+
: super.print({class: 'image-caption'});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** @override */
|
|
213
|
+
cloneNode() {
|
|
214
|
+
const cloned = this.cloneChildNodes(),
|
|
215
|
+
config = this.getAttribute('config');
|
|
216
|
+
return Parser.run(() => {
|
|
217
|
+
const token = new ImageParameterToken(this.#syntax.replace('$1', ''), config);
|
|
218
|
+
token.replaceChildren(...cloned);
|
|
219
|
+
return token;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @override
|
|
225
|
+
* @template {string} T
|
|
226
|
+
* @param {T} key 属性键
|
|
227
|
+
* @returns {import('../typings/node').TokenAttribute<T>}
|
|
228
|
+
*/
|
|
229
|
+
getAttribute(key) {
|
|
230
|
+
return key === 'syntax' ? this.#syntax : super.getAttribute(key);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @override
|
|
235
|
+
* @param {PropertyKey} key 属性键
|
|
236
|
+
*/
|
|
237
|
+
hasAttribute(key) {
|
|
238
|
+
return key === 'syntax' || super.hasAttribute(key);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** 是否是不可变参数 */
|
|
242
|
+
#isVoid() {
|
|
243
|
+
return this.#syntax && !this.#syntax.includes('$1');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @override
|
|
248
|
+
* @template {Token} T
|
|
249
|
+
* @param {T} token 待插入的子节点
|
|
250
|
+
* @param {number} i 插入位置
|
|
251
|
+
* @complexity `n`
|
|
252
|
+
* @throws `Error` 不接受自定义输入的图片参数
|
|
253
|
+
*/
|
|
254
|
+
insertAt(token, i = this.length) {
|
|
255
|
+
if (!Parser.running && this.#isVoid()) {
|
|
256
|
+
throw new Error(`图片参数 ${this.name} 不接受自定义输入!`);
|
|
257
|
+
}
|
|
258
|
+
return super.insertAt(token, i);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 获取参数值
|
|
263
|
+
* @complexity `n`
|
|
264
|
+
*/
|
|
265
|
+
getValue() {
|
|
266
|
+
return this.name === 'invalid' ? this.text() : this.#isVoid() || super.text();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 设置参数值
|
|
271
|
+
* @param {string|boolean} value 参数值
|
|
272
|
+
* @complexity `n`
|
|
273
|
+
* @throws SyntaxError` 非法的参数值
|
|
274
|
+
*/
|
|
275
|
+
setValue(value) {
|
|
276
|
+
if (this.name === 'invalid') {
|
|
277
|
+
throw new Error('无效的图片参数!');
|
|
278
|
+
} else if (this.#isVoid()) {
|
|
279
|
+
if (typeof value !== 'boolean') {
|
|
280
|
+
this.typeError('setValue', 'Boolean');
|
|
281
|
+
} else if (value === false) {
|
|
282
|
+
this.remove();
|
|
283
|
+
}
|
|
284
|
+
return;
|
|
285
|
+
} else if (typeof value !== 'string') {
|
|
286
|
+
this.typeError('setValue', 'String');
|
|
287
|
+
}
|
|
288
|
+
const root = Parser.parse(`[[File:F|${
|
|
289
|
+
this.#syntax ? this.#syntax.replace('$1', value) : value
|
|
290
|
+
}]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
|
|
291
|
+
{length, firstChild: file} = root,
|
|
292
|
+
{lastChild: imageParameter, type, name, length: fileLength} = file;
|
|
293
|
+
if (length !== 1 || type !== 'file' || name !== 'File:F' || fileLength !== 2
|
|
294
|
+
|| imageParameter.name !== this.name
|
|
295
|
+
) {
|
|
296
|
+
throw new SyntaxError(`非法的 ${this.name} 参数:${noWrap(value)}`);
|
|
297
|
+
}
|
|
298
|
+
this.replaceChildren(...imageParameter.childNodes);
|
|
299
|
+
}
|
|
139
300
|
}
|
|
140
301
|
|
|
302
|
+
Parser.classes.ImageParameterToken = __filename;
|
|
141
303
|
module.exports = ImageParameterToken;
|
package/src/imagemap.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {generateForSelf, generateForChild} = require('../util/lint'),
|
|
4
|
+
singleLine = require('../mixin/singleLine'),
|
|
4
5
|
Parser = require('..'),
|
|
5
6
|
Token = require('.'),
|
|
6
7
|
NoincludeToken = require('./nowiki/noinclude'),
|
|
@@ -23,6 +24,14 @@ class ImagemapToken extends Token {
|
|
|
23
24
|
return this.childNodes.find(({type}) => type === 'imagemap-image');
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* 链接
|
|
29
|
+
* @returns {ImagemapLinkToken[]}
|
|
30
|
+
*/
|
|
31
|
+
get links() {
|
|
32
|
+
return this.childNodes.filter(({type}) => type === 'imagemap-link');
|
|
33
|
+
}
|
|
34
|
+
|
|
26
35
|
/**
|
|
27
36
|
* @param {string} inner 标签内部wikitext
|
|
28
37
|
* @param {import('../typings/token').accum} accum
|
|
@@ -30,13 +39,14 @@ class ImagemapToken extends Token {
|
|
|
30
39
|
*/
|
|
31
40
|
constructor(inner, config = Parser.getConfig(), accum = []) {
|
|
32
41
|
super(undefined, config, true, accum, {
|
|
42
|
+
GalleryImageToken: ':', ImagemapLinkToken: ':', SingleLineNoincludeToken: ':', AstText: ':',
|
|
33
43
|
});
|
|
34
44
|
if (!inner) {
|
|
35
45
|
return;
|
|
36
46
|
}
|
|
37
47
|
const lines = inner.split('\n'),
|
|
38
48
|
protocols = new Set(config.protocol.split('|')),
|
|
39
|
-
SingleLineNoincludeToken = NoincludeToken,
|
|
49
|
+
SingleLineNoincludeToken = singleLine(NoincludeToken),
|
|
40
50
|
fallback = /** @param {string} line 一行文本 */ line => {
|
|
41
51
|
super.insertAt(new SingleLineNoincludeToken(line, config, accum));
|
|
42
52
|
};
|
|
@@ -49,7 +59,7 @@ class ImagemapToken extends Token {
|
|
|
49
59
|
} else if (first) {
|
|
50
60
|
const [file, ...options] = line.split('|'),
|
|
51
61
|
title = this.normalizeTitle(file, 0, true);
|
|
52
|
-
if (title.valid && title.ns === 6) {
|
|
62
|
+
if (title.valid && !title.interwiki && title.ns === 6) {
|
|
53
63
|
const token = new GalleryImageToken(
|
|
54
64
|
file, options.length > 0 ? options.join('|') : undefined, config, accum,
|
|
55
65
|
);
|
|
@@ -58,6 +68,7 @@ class ImagemapToken extends Token {
|
|
|
58
68
|
first = false;
|
|
59
69
|
continue;
|
|
60
70
|
} else {
|
|
71
|
+
Parser.error('<imagemap>标签内必须先包含一张合法图片!', line);
|
|
61
72
|
error = true;
|
|
62
73
|
}
|
|
63
74
|
} else if (line.trim().split(/[\t ]/u)[0] === 'desc') {
|
|
@@ -101,6 +112,7 @@ class ImagemapToken extends Token {
|
|
|
101
112
|
|
|
102
113
|
/**
|
|
103
114
|
* @override
|
|
115
|
+
* @param {string} selector
|
|
104
116
|
*/
|
|
105
117
|
toString(selector) {
|
|
106
118
|
return super.toString(selector, '\n');
|
|
@@ -116,6 +128,11 @@ class ImagemapToken extends Token {
|
|
|
116
128
|
return 1;
|
|
117
129
|
}
|
|
118
130
|
|
|
131
|
+
/** @override */
|
|
132
|
+
print() {
|
|
133
|
+
return super.print({sep: '\n'});
|
|
134
|
+
}
|
|
135
|
+
|
|
119
136
|
/**
|
|
120
137
|
* @override
|
|
121
138
|
* @param {number} start 起始位置
|
|
@@ -135,6 +152,48 @@ class ImagemapToken extends Token {
|
|
|
135
152
|
}
|
|
136
153
|
return errors;
|
|
137
154
|
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @override
|
|
158
|
+
* @template {string|Token} T
|
|
159
|
+
* @param {T} token 待插入的节点
|
|
160
|
+
* @param {number} i 插入位置
|
|
161
|
+
* @throws `Error` 当前缺少合法图片
|
|
162
|
+
* @throws `RangeError` 已有一张合法图片
|
|
163
|
+
*/
|
|
164
|
+
insertAt(token, i = 0) {
|
|
165
|
+
const {image} = this;
|
|
166
|
+
if (!image && (token.type === 'imagemap-link' || token.type === 'text')) {
|
|
167
|
+
throw new Error('当前缺少一张合法图片!');
|
|
168
|
+
} else if (image && token.type === 'imagemap-image') {
|
|
169
|
+
throw new RangeError('已有一张合法图片!');
|
|
170
|
+
}
|
|
171
|
+
return super.insertAt(token, i);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @override
|
|
176
|
+
* @param {number} i 移除位置
|
|
177
|
+
* @throws `Error` 禁止移除图片
|
|
178
|
+
*/
|
|
179
|
+
removeAt(i) {
|
|
180
|
+
const child = this.childNodes[i];
|
|
181
|
+
if (child.type === 'imagemap-image') {
|
|
182
|
+
throw new Error('禁止移除<imagemap>内的图片!');
|
|
183
|
+
}
|
|
184
|
+
return super.removeAt(i);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** @override */
|
|
188
|
+
cloneNode() {
|
|
189
|
+
const cloned = this.cloneChildNodes();
|
|
190
|
+
return Parser.run(() => {
|
|
191
|
+
const token = new ImagemapToken(undefined, this.getAttribute('config'));
|
|
192
|
+
token.append(...cloned);
|
|
193
|
+
return token;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
138
196
|
}
|
|
139
197
|
|
|
198
|
+
Parser.classes.ImagemapToken = __filename;
|
|
140
199
|
module.exports = ImagemapToken;
|
package/src/imagemapLink.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const Title = require('../lib/title'),
|
|
4
|
+
fixedToken = require('../mixin/fixedToken'),
|
|
5
|
+
singleLine = require('../mixin/singleLine'),
|
|
6
|
+
Parser = require('..'),
|
|
4
7
|
Token = require('.'),
|
|
5
8
|
NoincludeToken = require('./nowiki/noinclude'),
|
|
6
9
|
LinkToken = require('./link'),
|
|
@@ -10,9 +13,17 @@ const Title = require('../lib/title'),
|
|
|
10
13
|
* `<imagemap>`内的链接
|
|
11
14
|
* @classdesc `{childNodes: [AstText, LinkToken|ExtLinkToken, NoincludeToken]}`
|
|
12
15
|
*/
|
|
13
|
-
class ImagemapLinkToken extends Token {
|
|
16
|
+
class ImagemapLinkToken extends fixedToken(singleLine(Token)) {
|
|
14
17
|
type = 'imagemap-link';
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* 内外链接
|
|
21
|
+
* @this {{childNodes: (LinkToken|ExtLinkToken)[]}}
|
|
22
|
+
*/
|
|
23
|
+
get link() {
|
|
24
|
+
return this.childNodes[1].link;
|
|
25
|
+
}
|
|
26
|
+
|
|
16
27
|
/**
|
|
17
28
|
* @param {string} pre 链接前的文本
|
|
18
29
|
* @param {[string, string, string|Title]} linkStuff 内外链接
|
|
@@ -26,4 +37,5 @@ class ImagemapLinkToken extends Token {
|
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
|
|
40
|
+
Parser.classes.ImagemapLinkToken = __filename;
|
|
29
41
|
module.exports = ImagemapLinkToken;
|