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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Parser = require('../..'),
|
|
4
|
+
HasNowikiToken = require('.');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<pre>`
|
|
8
|
+
* @classdesc `{childNodes: [...AstText|NoincludeToken|ConverterToken]}`
|
|
9
|
+
*/
|
|
10
|
+
class PreToken extends HasNowikiToken {
|
|
11
|
+
name = 'pre';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} wikitext wikitext
|
|
15
|
+
* @param {accum} accum
|
|
16
|
+
*/
|
|
17
|
+
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
18
|
+
super(wikitext, 'ext-inner', config, accum);
|
|
19
|
+
this.setAttribute('stage', Parser.MAX_STAGE - 1);
|
|
20
|
+
this.setAttribute('acceptable', {AstText: ':', NoincludeToken: ':', ConverterToken: ':'});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** @override */
|
|
24
|
+
isPlain() {
|
|
25
|
+
return true;
|
|
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
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Parser.classes.PreToken = __filename;
|
|
40
|
+
module.exports = PreToken;
|
package/src/heading.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const {generateForSelf} = require('../util/lint'),
|
|
4
|
+
fixedToken = require('../mixin/fixedToken'),
|
|
4
5
|
sol = require('../mixin/sol'),
|
|
5
6
|
Parser = require('..'),
|
|
6
7
|
Token = require('.');
|
|
@@ -14,7 +15,7 @@ class HeadingToken extends fixedToken(sol(Token)) {
|
|
|
14
15
|
|
|
15
16
|
/** 内部wikitext */
|
|
16
17
|
get innerText() {
|
|
17
|
-
return this.
|
|
18
|
+
return this.firstChild.text();
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -27,7 +28,8 @@ class HeadingToken extends fixedToken(sol(Token)) {
|
|
|
27
28
|
this.setAttribute('name', String(level));
|
|
28
29
|
const token = new Token(input[0], config, true, accum);
|
|
29
30
|
token.type = 'heading-title';
|
|
30
|
-
token.setAttribute('name', this.name)
|
|
31
|
+
token.setAttribute('name', this.name);
|
|
32
|
+
token.setAttribute('stage', 2);
|
|
31
33
|
const SyntaxToken = require('./syntax');
|
|
32
34
|
const trail = new SyntaxToken(input[1], /^[^\S\n]*$/u, 'heading-trail', config, accum, {
|
|
33
35
|
'Stage-1': ':', '!ExtToken': '',
|
|
@@ -35,27 +37,19 @@ class HeadingToken extends fixedToken(sol(Token)) {
|
|
|
35
37
|
this.append(token, trail);
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
/** @override */
|
|
39
|
-
cloneNode() {
|
|
40
|
-
const [title, trail] = this.cloneChildNodes(),
|
|
41
|
-
token = Parser.run(() => new HeadingToken(Number(this.name), [], this.getAttribute('config')));
|
|
42
|
-
token.firstElementChild.safeReplaceWith(title);
|
|
43
|
-
token.lastElementChild.safeReplaceWith(trail);
|
|
44
|
-
return token;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
40
|
/**
|
|
48
41
|
* @override
|
|
49
42
|
* @this {{prependNewLine(): ''|'\n', appendNewLine(): ''|'\n'} & HeadingToken}
|
|
50
43
|
* @param {string} selector
|
|
44
|
+
* @returns {string}
|
|
51
45
|
*/
|
|
52
46
|
toString(selector) {
|
|
53
47
|
const equals = '='.repeat(Number(this.name));
|
|
54
48
|
return selector && this.matches(selector)
|
|
55
49
|
? ''
|
|
56
50
|
: `${this.prependNewLine()}${equals}${
|
|
57
|
-
this.
|
|
58
|
-
}${equals}${this.
|
|
51
|
+
this.firstChild.toString(selector)
|
|
52
|
+
}${equals}${this.lastChild.toString(selector)}${this.appendNewLine()}`;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
/** @override */
|
|
@@ -68,6 +62,35 @@ class HeadingToken extends fixedToken(sol(Token)) {
|
|
|
68
62
|
return Number(this.name);
|
|
69
63
|
}
|
|
70
64
|
|
|
65
|
+
/** @override */
|
|
66
|
+
print() {
|
|
67
|
+
const equals = '='.repeat(Number(this.name));
|
|
68
|
+
return super.print({pre: equals, sep: equals});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @override
|
|
73
|
+
* @param {number} start 起始位置
|
|
74
|
+
*/
|
|
75
|
+
lint(start = 0) {
|
|
76
|
+
const errors = super.lint(start);
|
|
77
|
+
if (this.name === '1') {
|
|
78
|
+
errors.push(generateForSelf(this, this.getRootNode().posFromIndex(start), '<h1>'));
|
|
79
|
+
}
|
|
80
|
+
return errors;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** @override */
|
|
84
|
+
cloneNode() {
|
|
85
|
+
const [title, trail] = this.cloneChildNodes();
|
|
86
|
+
return Parser.run(() => {
|
|
87
|
+
const token = new HeadingToken(Number(this.name), [], this.getAttribute('config'));
|
|
88
|
+
token.firsthild.safeReplaceWith(title);
|
|
89
|
+
token.lastChild.safeReplaceWith(trail);
|
|
90
|
+
return token;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
71
94
|
/**
|
|
72
95
|
* @override
|
|
73
96
|
* @this {HeadingToken & {prependNewLine(): ''|'\n', appendNewLine(): ''|'\n'}}
|
|
@@ -75,7 +98,7 @@ class HeadingToken extends fixedToken(sol(Token)) {
|
|
|
75
98
|
*/
|
|
76
99
|
text() {
|
|
77
100
|
const equals = '='.repeat(Number(this.name));
|
|
78
|
-
return `${this.prependNewLine()}${equals}${this.
|
|
101
|
+
return `${this.prependNewLine()}${equals}${this.firstChild.text()}${equals}${this.appendNewLine()}`;
|
|
79
102
|
}
|
|
80
103
|
|
|
81
104
|
/**
|
|
@@ -83,16 +106,16 @@ class HeadingToken extends fixedToken(sol(Token)) {
|
|
|
83
106
|
* @param {number} n 标题层级
|
|
84
107
|
*/
|
|
85
108
|
setLevel(n) {
|
|
86
|
-
if (
|
|
109
|
+
if (!Number.isInteger(n)) {
|
|
87
110
|
this.typeError('setLevel', 'Number');
|
|
88
111
|
}
|
|
89
112
|
n = Math.min(Math.max(n, 1), 6);
|
|
90
|
-
this.setAttribute('name', String(n)).
|
|
113
|
+
this.setAttribute('name', String(n)).firstChild.setAttribute('name', this.name);
|
|
91
114
|
}
|
|
92
115
|
|
|
93
116
|
/** 移除标题后的不可见内容 */
|
|
94
117
|
removeTrail() {
|
|
95
|
-
this.
|
|
118
|
+
this.lastChild.replaceChildren();
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
|
package/src/html.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {noWrap} = require('../util/string'),
|
|
4
|
+
{generateForSelf} = require('../util/lint'),
|
|
4
5
|
fixedToken = require('../mixin/fixedToken'),
|
|
5
6
|
attributeParent = require('../mixin/attributeParent'),
|
|
6
7
|
Parser = require('..'),
|
|
@@ -27,11 +28,11 @@ class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
|
27
28
|
this.#closing = false;
|
|
28
29
|
return;
|
|
29
30
|
} else if (this.#selfClosing) {
|
|
30
|
-
throw new Error(
|
|
31
|
+
throw new Error('这是一个自闭合标签!');
|
|
31
32
|
}
|
|
32
33
|
const {html: [,, tags]} = this.getAttribute('config');
|
|
33
34
|
if (tags.includes(this.name)) {
|
|
34
|
-
throw new Error(
|
|
35
|
+
throw new Error('这是一个空标签!');
|
|
35
36
|
}
|
|
36
37
|
this.#closing = true;
|
|
37
38
|
}
|
|
@@ -65,30 +66,13 @@ class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
|
65
66
|
*/
|
|
66
67
|
constructor(name, attr, closing, selfClosing, config = Parser.getConfig(), accum = []) {
|
|
67
68
|
super(undefined, config, true, accum);
|
|
68
|
-
this.
|
|
69
|
+
this.insertAt(attr);
|
|
69
70
|
this.setAttribute('name', name.toLowerCase());
|
|
70
71
|
this.#closing = closing;
|
|
71
72
|
this.#selfClosing = selfClosing;
|
|
72
73
|
this.#tag = name;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
/** @override */
|
|
76
|
-
cloneNode() {
|
|
77
|
-
const [attr] = this.cloneChildNodes(),
|
|
78
|
-
config = this.getAttribute('config');
|
|
79
|
-
return Parser.run(() => new HtmlToken(this.#tag, attr, this.#closing, this.#selfClosing, config));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @override
|
|
84
|
-
* @template {string} T
|
|
85
|
-
* @param {T} key 属性键
|
|
86
|
-
* @returns {TokenAttribute<T>}
|
|
87
|
-
*/
|
|
88
|
-
getAttribute(key) {
|
|
89
|
-
return key === 'tag' ? this.#tag : super.getAttribute(key);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
76
|
/**
|
|
93
77
|
* @override
|
|
94
78
|
* @param {string} selector
|
|
@@ -105,21 +89,31 @@ class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
|
105
89
|
}
|
|
106
90
|
|
|
107
91
|
/** @override */
|
|
108
|
-
|
|
109
|
-
return
|
|
92
|
+
print() {
|
|
93
|
+
return super.print({
|
|
94
|
+
pre: `<${this.#closing ? '/' : ''}${this.#tag}`, post: `${this.#selfClosing ? '/' : ''}>`,
|
|
95
|
+
});
|
|
110
96
|
}
|
|
111
97
|
|
|
112
98
|
/**
|
|
113
|
-
*
|
|
114
|
-
* @param {
|
|
115
|
-
* @throws `RangeError` 非法的HTML标签
|
|
99
|
+
* @override
|
|
100
|
+
* @param {number} start 起始位置
|
|
116
101
|
*/
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
102
|
+
lint(start = 0) {
|
|
103
|
+
const errors = super.lint(start);
|
|
104
|
+
let /** @type {LintError} */ refError;
|
|
105
|
+
if (this.name === 'h1' && !this.#closing) {
|
|
106
|
+
refError = generateForSelf(this, this.getRootNode().posFromIndex(start), '<h1>');
|
|
107
|
+
errors.push(refError);
|
|
121
108
|
}
|
|
122
|
-
|
|
109
|
+
try {
|
|
110
|
+
this.findMatchingTag();
|
|
111
|
+
} catch ({message: errorMsg}) {
|
|
112
|
+
const [message] = errorMsg.split(':');
|
|
113
|
+
refError ||= generateForSelf(this, this.getRootNode().posFromIndex(start), '');
|
|
114
|
+
errors.push({...refError, message, severity: message === '未闭合的标签' ? 'warning' : 'error'});
|
|
115
|
+
}
|
|
116
|
+
return errors;
|
|
123
117
|
}
|
|
124
118
|
|
|
125
119
|
/**
|
|
@@ -131,24 +125,23 @@ class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
|
131
125
|
*/
|
|
132
126
|
findMatchingTag() {
|
|
133
127
|
const {html} = this.getAttribute('config'),
|
|
134
|
-
{name, parentNode
|
|
128
|
+
{name: tagName, parentNode} = this,
|
|
135
129
|
string = noWrap(String(this));
|
|
136
|
-
if (closing && selfClosing) {
|
|
130
|
+
if (this.#closing && this.#selfClosing) {
|
|
137
131
|
throw new SyntaxError(`同时闭合和自封闭的标签:${string}`);
|
|
138
|
-
} else if (html[2].includes(
|
|
132
|
+
} else if (html[2].includes(tagName) || this.#selfClosing && html[1].includes(tagName)) { // 自封闭标签
|
|
139
133
|
return this;
|
|
140
|
-
} else if (selfClosing && html[0].includes(
|
|
134
|
+
} else if (this.#selfClosing && html[0].includes(tagName)) {
|
|
141
135
|
throw new SyntaxError(`无效自封闭标签:${string}`);
|
|
142
136
|
} else if (!parentNode) {
|
|
143
137
|
return undefined;
|
|
144
138
|
}
|
|
145
|
-
const {
|
|
146
|
-
i =
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
let imbalance = closing ? -1 : 1;
|
|
139
|
+
const {childNodes} = parentNode,
|
|
140
|
+
i = childNodes.indexOf(this),
|
|
141
|
+
siblings = this.#closing
|
|
142
|
+
? childNodes.slice(0, i).reverse().filter(({type, name}) => type === 'html' && name === tagName)
|
|
143
|
+
: childNodes.slice(i + 1).filter(({type, name}) => type === 'html' && name === tagName);
|
|
144
|
+
let imbalance = this.#closing ? -1 : 1;
|
|
152
145
|
for (const token of siblings) {
|
|
153
146
|
if (token.closing) {
|
|
154
147
|
imbalance--;
|
|
@@ -159,7 +152,42 @@ class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
|
159
152
|
return token;
|
|
160
153
|
}
|
|
161
154
|
}
|
|
162
|
-
throw new SyntaxError(`未${closing ? '匹配的闭合' : '闭合的'}标签:${string}`);
|
|
155
|
+
throw new SyntaxError(`未${this.#closing ? '匹配的闭合' : '闭合的'}标签:${string}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** @override */
|
|
159
|
+
cloneNode() {
|
|
160
|
+
const [attr] = this.cloneChildNodes(),
|
|
161
|
+
config = this.getAttribute('config');
|
|
162
|
+
return Parser.run(() => new HtmlToken(this.#tag, attr, this.#closing, this.#selfClosing, config));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @override
|
|
167
|
+
* @template {string} T
|
|
168
|
+
* @param {T} key 属性键
|
|
169
|
+
* @returns {TokenAttribute<T>}
|
|
170
|
+
*/
|
|
171
|
+
getAttribute(key) {
|
|
172
|
+
return key === 'tag' ? this.#tag : super.getAttribute(key);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @override */
|
|
176
|
+
text() {
|
|
177
|
+
return `<${this.#closing ? '/' : ''}${this.#tag}${super.text()}${this.#selfClosing ? '/' : ''}>`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 更换标签名
|
|
182
|
+
* @param {string} tag 标签名
|
|
183
|
+
* @throws `RangeError` 非法的HTML标签
|
|
184
|
+
*/
|
|
185
|
+
replaceTag(tag) {
|
|
186
|
+
const name = tag.toLowerCase();
|
|
187
|
+
if (!this.getAttribute('config').html.flat().includes(name)) {
|
|
188
|
+
throw new RangeError(`非法的HTML标签:${tag}`);
|
|
189
|
+
}
|
|
190
|
+
this.setAttribute('name', name).#tag = tag;
|
|
163
191
|
}
|
|
164
192
|
|
|
165
193
|
/** 局部闭合 */
|
|
@@ -176,17 +204,17 @@ class HtmlToken extends attributeParent(fixedToken(Token)) {
|
|
|
176
204
|
*/
|
|
177
205
|
fix() {
|
|
178
206
|
const config = this.getAttribute('config'),
|
|
179
|
-
{parentNode, name,
|
|
180
|
-
if (!parentNode || !this.#selfClosing || !config.html[0].includes(
|
|
207
|
+
{parentNode, name: tagName, firstChild} = this;
|
|
208
|
+
if (!parentNode || !this.#selfClosing || !config.html[0].includes(tagName)) {
|
|
181
209
|
return;
|
|
182
|
-
} else if (
|
|
210
|
+
} else if (firstChild.text().trim()) {
|
|
183
211
|
this.#localMatch();
|
|
184
212
|
return;
|
|
185
213
|
}
|
|
186
|
-
const {
|
|
187
|
-
i =
|
|
214
|
+
const {childNodes} = parentNode,
|
|
215
|
+
i = childNodes.indexOf(this),
|
|
188
216
|
/** @type {HtmlToken[]} */
|
|
189
|
-
prevSiblings =
|
|
217
|
+
prevSiblings = childNodes.slice(0, i).filter(({type, name}) => type === 'html' && name === tagName),
|
|
190
218
|
imbalance = prevSiblings.reduce((acc, {closing}) => acc + (closing ? 1 : -1), 0);
|
|
191
219
|
if (imbalance < 0) {
|
|
192
220
|
this.#selfClosing = false;
|
package/src/imageParameter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {text, noWrap, extUrlChar} = require('../util/string'),
|
|
3
|
+
const {text, noWrap, print, extUrlChar} = require('../util/string'),
|
|
4
4
|
Parser = require('..'),
|
|
5
5
|
Token = require('.'),
|
|
6
6
|
AstText = require('../lib/text');
|
|
@@ -21,30 +21,36 @@ class ImageParameterToken extends Token {
|
|
|
21
21
|
*/
|
|
22
22
|
static #validate(key, value, config = Parser.getConfig(), halfParsed = false) {
|
|
23
23
|
value = value.replaceAll(/\0\d+t\x7F/gu, '').trim();
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
24
|
+
switch (key) {
|
|
25
|
+
case 'width':
|
|
26
|
+
return /^\d*(?:x\d*)?$/u.test(value);
|
|
27
|
+
case 'link': {
|
|
28
|
+
if (!value) {
|
|
29
|
+
return this.noLink;
|
|
30
|
+
}
|
|
31
|
+
const regex = new RegExp(`(?:${config.protocol}|//)${extUrlChar}(?=\0\\d+t\x7F|$)`, 'iu');
|
|
32
|
+
if (regex.test(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
} else if (value.startsWith('[[') && value.endsWith(']]')) {
|
|
35
|
+
value = value.slice(2, -2);
|
|
36
|
+
}
|
|
37
|
+
if (value.includes('%')) {
|
|
38
|
+
try {
|
|
39
|
+
value = decodeURIComponent(value);
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
const title = Parser.normalizeTitle(value, 0, false, config, halfParsed);
|
|
43
|
+
return title.valid && String(title);
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
case 'lang':
|
|
46
|
+
return config.variants.includes(value);
|
|
47
|
+
case 'alt':
|
|
48
|
+
case 'class':
|
|
49
|
+
case 'manualthumb':
|
|
50
|
+
return true;
|
|
51
|
+
default:
|
|
52
|
+
return !isNaN(value);
|
|
46
53
|
}
|
|
47
|
-
return !isNaN(value);
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
type = 'image-parameter';
|
|
@@ -89,7 +95,6 @@ class ImageParameterToken extends Token {
|
|
|
89
95
|
}
|
|
90
96
|
str.splitText(str.data.indexOf('x'));
|
|
91
97
|
str.nextSibling.splitText(1);
|
|
92
|
-
// eslint-disable-next-line unicorn/consistent-destructuring
|
|
93
98
|
return {width: text(token.childNodes.slice(0, i + 1)), height: text(token.childNodes.slice(i + 2))};
|
|
94
99
|
}
|
|
95
100
|
return undefined;
|
|
@@ -147,13 +152,42 @@ class ImageParameterToken extends Token {
|
|
|
147
152
|
this.setAttribute('name', 'caption').setAttribute('stage', 7);
|
|
148
153
|
}
|
|
149
154
|
|
|
155
|
+
/** @override */
|
|
156
|
+
isPlain() {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @override
|
|
162
|
+
* @param {string} selector
|
|
163
|
+
*/
|
|
164
|
+
toString(selector) {
|
|
165
|
+
return this.#syntax && !(selector && this.matches(selector))
|
|
166
|
+
? this.#syntax.replace('$1', super.toString(selector))
|
|
167
|
+
: super.toString(selector);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** @override */
|
|
171
|
+
getPadding() {
|
|
172
|
+
return Math.max(0, this.#syntax.indexOf('$1'));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @override */
|
|
176
|
+
print() {
|
|
177
|
+
return this.#syntax
|
|
178
|
+
? `<span class="wpb-image-parameter">${this.#syntax.replace('$1', print(this.childNodes))}</span>`
|
|
179
|
+
: super.print({class: 'image-caption'});
|
|
180
|
+
}
|
|
181
|
+
|
|
150
182
|
/** @override */
|
|
151
183
|
cloneNode() {
|
|
152
184
|
const cloned = this.cloneChildNodes(),
|
|
153
|
-
config = this.getAttribute('config')
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
185
|
+
config = this.getAttribute('config');
|
|
186
|
+
return Parser.run(() => {
|
|
187
|
+
const token = new ImageParameterToken(this.#syntax.replace('$1', ''), config);
|
|
188
|
+
token.replaceChildren(...cloned);
|
|
189
|
+
return token;
|
|
190
|
+
});
|
|
157
191
|
}
|
|
158
192
|
|
|
159
193
|
/**
|
|
@@ -166,29 +200,17 @@ class ImageParameterToken extends Token {
|
|
|
166
200
|
return key === 'syntax' ? this.#syntax : super.getAttribute(key);
|
|
167
201
|
}
|
|
168
202
|
|
|
169
|
-
/** @override */
|
|
170
|
-
isPlain() {
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/** 是否是不可变参数 */
|
|
175
|
-
#isVoid() {
|
|
176
|
-
return this.#syntax && !this.#syntax.includes('$1');
|
|
177
|
-
}
|
|
178
|
-
|
|
179
203
|
/**
|
|
180
204
|
* @override
|
|
181
|
-
* @param {
|
|
205
|
+
* @param {PropertyKey} key 属性键
|
|
182
206
|
*/
|
|
183
|
-
|
|
184
|
-
return
|
|
185
|
-
? this.#syntax.replace('$1', super.toString(selector))
|
|
186
|
-
: super.toString(selector);
|
|
207
|
+
hasAttribute(key) {
|
|
208
|
+
return key === 'syntax' || super.hasAttribute(key);
|
|
187
209
|
}
|
|
188
210
|
|
|
189
|
-
/**
|
|
190
|
-
|
|
191
|
-
return
|
|
211
|
+
/** 是否是不可变参数 */
|
|
212
|
+
#isVoid() {
|
|
213
|
+
return this.#syntax && !this.#syntax.includes('$1');
|
|
192
214
|
}
|
|
193
215
|
|
|
194
216
|
/** @override */
|
|
@@ -239,14 +261,14 @@ class ImageParameterToken extends Token {
|
|
|
239
261
|
const root = Parser.parse(`[[File:F|${
|
|
240
262
|
this.#syntax ? this.#syntax.replace('$1', value) : value
|
|
241
263
|
}]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
|
|
242
|
-
{
|
|
243
|
-
|
|
244
|
-
if (length !== 1 ||
|
|
245
|
-
||
|
|
264
|
+
{length, firstChild: file} = root,
|
|
265
|
+
{lastChild: imageParameter, type, name, length: fileLength} = file;
|
|
266
|
+
if (length !== 1 || type !== 'file' || name !== 'File:F' || fileLength !== 2
|
|
267
|
+
|| imageParameter.name !== this.name
|
|
246
268
|
) {
|
|
247
269
|
throw new SyntaxError(`非法的 ${this.name} 参数:${noWrap(value)}`);
|
|
248
270
|
}
|
|
249
|
-
this.replaceChildren(...
|
|
271
|
+
this.replaceChildren(...imageParameter.childNodes);
|
|
250
272
|
}
|
|
251
273
|
}
|
|
252
274
|
|