wikiparser-node 0.8.1-m → 0.9.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/README.md +39 -0
- package/config/moegirl.json +1 -0
- package/i18n/zh-hans.json +44 -0
- package/i18n/zh-hant.json +44 -0
- package/index.js +264 -10
- package/lib/element.js +507 -33
- package/lib/node.js +550 -6
- package/lib/ranges.js +130 -0
- package/lib/text.js +111 -41
- package/lib/title.js +28 -5
- 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 +9 -8
- package/parser/brackets.js +9 -2
- package/parser/commentAndExt.js +3 -5
- 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 +6 -5
- package/parser/list.js +1 -0
- package/parser/magicLinks.js +5 -4
- package/parser/quotes.js +1 -0
- package/parser/selector.js +177 -0
- package/parser/table.js +1 -0
- package/src/arg.js +123 -5
- package/src/atom/hidden.js +2 -0
- package/src/atom/index.js +17 -0
- package/src/attribute.js +191 -8
- package/src/attributes.js +311 -8
- package/src/charinsert.js +97 -0
- package/src/converter.js +108 -2
- package/src/converterFlags.js +190 -3
- package/src/converterRule.js +185 -4
- package/src/extLink.js +122 -2
- package/src/gallery.js +59 -11
- package/src/hasNowiki/index.js +12 -0
- package/src/hasNowiki/pre.js +12 -0
- package/src/heading.js +57 -6
- package/src/html.js +133 -12
- package/src/imageParameter.js +232 -38
- package/src/imagemap.js +65 -6
- package/src/imagemapLink.js +14 -2
- package/src/index.js +537 -8
- package/src/link/category.js +32 -1
- package/src/link/file.js +173 -11
- package/src/link/galleryImage.js +63 -5
- package/src/link/index.js +268 -9
- package/src/magicLink.js +92 -11
- package/src/nested/choose.js +1 -0
- package/src/nested/combobox.js +1 -0
- package/src/nested/index.js +31 -7
- package/src/nested/references.js +1 -0
- package/src/nowiki/comment.js +27 -3
- 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 +25 -3
- package/src/nowiki/list.js +5 -2
- package/src/nowiki/noinclude.js +14 -0
- package/src/nowiki/quote.js +17 -3
- package/src/onlyinclude.js +26 -1
- package/src/paramTag/index.js +27 -4
- package/src/paramTag/inputbox.js +4 -1
- package/src/parameter.js +150 -8
- package/src/syntax.js +68 -0
- package/src/table/index.js +941 -4
- package/src/table/td.js +229 -10
- package/src/table/tr.js +249 -4
- package/src/tagPair/ext.js +36 -9
- package/src/tagPair/include.js +24 -0
- package/src/tagPair/index.js +51 -2
- package/src/transclude.js +547 -29
- package/tool/index.js +1202 -0
- package/util/debug.js +73 -0
- package/util/lint.js +8 -7
- package/util/string.js +67 -1
- package/config/minimum.json +0 -142
package/src/link/file.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {explode} = require('../../util/string'),
|
|
3
|
+
const {explode, noWrap} = require('../../util/string'),
|
|
4
4
|
{generateForChild} = require('../../util/lint'),
|
|
5
5
|
Parser = require('../..'),
|
|
6
6
|
LinkToken = require('.'),
|
|
@@ -17,6 +17,48 @@ const frame = new Set(['manualthumb', 'frameless', 'framed', 'thumbnail']),
|
|
|
17
17
|
class FileToken extends LinkToken {
|
|
18
18
|
type = 'file';
|
|
19
19
|
|
|
20
|
+
/** 图片链接 */
|
|
21
|
+
get link() {
|
|
22
|
+
return this.getArg('link')?.link;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
set link(value) {
|
|
26
|
+
this.setValue('link', value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 图片大小 */
|
|
30
|
+
get size() {
|
|
31
|
+
return this.getArg('width')?.size;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 图片宽度 */
|
|
35
|
+
get width() {
|
|
36
|
+
return this.size?.width;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
set width(width) {
|
|
40
|
+
const arg = this.getArg('width');
|
|
41
|
+
if (arg) {
|
|
42
|
+
arg.width = width;
|
|
43
|
+
} else {
|
|
44
|
+
this.setValue('width', width);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 图片高度 */
|
|
49
|
+
get height() {
|
|
50
|
+
return this.size?.height;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
set height(height) {
|
|
54
|
+
const arg = this.getArg('width');
|
|
55
|
+
if (arg) {
|
|
56
|
+
arg.height = height;
|
|
57
|
+
} else {
|
|
58
|
+
this.setValue('width', `x${height}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
20
62
|
/**
|
|
21
63
|
* @param {string} link 文件名
|
|
22
64
|
* @param {string|undefined} text 图片参数
|
|
@@ -24,19 +66,27 @@ class FileToken extends LinkToken {
|
|
|
24
66
|
* @param {string} delimiter `|`
|
|
25
67
|
* @complexity `n`
|
|
26
68
|
*/
|
|
27
|
-
constructor(link, text,
|
|
28
|
-
super(link, undefined,
|
|
69
|
+
constructor(link, text, config = Parser.getConfig(), accum = [], delimiter = '|') {
|
|
70
|
+
super(link, undefined, config, accum, delimiter);
|
|
71
|
+
this.setAttribute('acceptable', {AtomToken: 0, ImageParameterToken: '1:'});
|
|
29
72
|
this.append(...explode('-{', '}-', '|', text).map(part => new ImageParameterToken(part, config, accum)));
|
|
73
|
+
this.seal(
|
|
74
|
+
['selfLink', 'interwiki', 'setLangLink', 'setFragment', 'asSelfLink', 'setLinkText', 'pipeTrick'],
|
|
75
|
+
true,
|
|
76
|
+
);
|
|
30
77
|
}
|
|
31
78
|
|
|
32
79
|
/**
|
|
33
80
|
* @override
|
|
34
81
|
* @param {number} start 起始位置
|
|
35
82
|
*/
|
|
36
|
-
lint(start =
|
|
83
|
+
lint(start = this.getAbsoluteIndex()) {
|
|
37
84
|
const errors = super.lint(start),
|
|
38
|
-
args = this.getAllArgs()
|
|
39
|
-
|
|
85
|
+
args = this.getAllArgs().filter(({childNodes}) => {
|
|
86
|
+
const visibleNodes = childNodes.filter(node => node.text().trim());
|
|
87
|
+
return visibleNodes.length !== 1 || visibleNodes[0].type !== 'arg';
|
|
88
|
+
}),
|
|
89
|
+
keys = [...new Set(args.map(({name}) => name))].filter(key => key !== 'invalid'),
|
|
40
90
|
frameKeys = keys.filter(key => frame.has(key)),
|
|
41
91
|
horizAlignKeys = keys.filter(key => horizAlign.has(key)),
|
|
42
92
|
vertAlignKeys = keys.filter(key => vertAlign.has(key));
|
|
@@ -55,24 +105,28 @@ class FileToken extends LinkToken {
|
|
|
55
105
|
];
|
|
56
106
|
}
|
|
57
107
|
if (relevantArgs.length > 1) {
|
|
58
|
-
errors.push(...relevantArgs.map(
|
|
108
|
+
errors.push(...relevantArgs.map(
|
|
109
|
+
arg => generateForChild(arg, rect, Parser.msg('duplicated image $1 parameter', key)),
|
|
110
|
+
));
|
|
59
111
|
}
|
|
60
112
|
}
|
|
61
113
|
if (frameKeys.size > 1) {
|
|
62
114
|
errors.push(
|
|
63
|
-
...args.filter(({name}) => frame.has(name)).map(
|
|
115
|
+
...args.filter(({name}) => frame.has(name)).map(
|
|
116
|
+
arg => generateForChild(arg, rect, 'conflicting image $1 parameter', 'frame'),
|
|
117
|
+
),
|
|
64
118
|
);
|
|
65
119
|
}
|
|
66
120
|
if (horizAlignKeys.size > 1) {
|
|
67
121
|
errors.push(
|
|
68
122
|
...args.filter(({name}) => horizAlign.has(name))
|
|
69
|
-
.map(arg => generateForChild(arg, rect, '
|
|
123
|
+
.map(arg => generateForChild(arg, rect, 'conflicting image $1 parameter', 'horizontal-alignment')),
|
|
70
124
|
);
|
|
71
125
|
}
|
|
72
126
|
if (vertAlignKeys.size > 1) {
|
|
73
127
|
errors.push(
|
|
74
128
|
...args.filter(({name}) => vertAlign.has(name))
|
|
75
|
-
.map(arg => generateForChild(arg, rect, '
|
|
129
|
+
.map(arg => generateForChild(arg, rect, 'conflicting image $1 parameter', 'vertical-alignment')),
|
|
76
130
|
);
|
|
77
131
|
}
|
|
78
132
|
return errors;
|
|
@@ -92,7 +146,9 @@ class FileToken extends LinkToken {
|
|
|
92
146
|
* @complexity `n`
|
|
93
147
|
*/
|
|
94
148
|
getArgs(key) {
|
|
95
|
-
return
|
|
149
|
+
return typeof key === 'string'
|
|
150
|
+
? this.getAllArgs().filter(({name}) => key === name)
|
|
151
|
+
: this.typeError('getArgs', 'String');
|
|
96
152
|
}
|
|
97
153
|
|
|
98
154
|
/**
|
|
@@ -103,6 +159,9 @@ class FileToken extends LinkToken {
|
|
|
103
159
|
*/
|
|
104
160
|
#getTypedArgs(keys, type) {
|
|
105
161
|
const args = this.getAllArgs().filter(({name}) => keys.has(name));
|
|
162
|
+
if (args.length > 1) {
|
|
163
|
+
Parser.warn(`图片 ${this.name} 带有 ${args.length} 个${type}参数,只有最后 1 个 ${args[0].name} 会生效!`);
|
|
164
|
+
}
|
|
106
165
|
return args;
|
|
107
166
|
}
|
|
108
167
|
|
|
@@ -120,6 +179,109 @@ class FileToken extends LinkToken {
|
|
|
120
179
|
getVertAlignArgs() {
|
|
121
180
|
return this.#getTypedArgs(vertAlign, '垂直对齐');
|
|
122
181
|
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 获取生效的指定图片参数
|
|
185
|
+
* @param {string} key 参数名
|
|
186
|
+
* @complexity `n`
|
|
187
|
+
*/
|
|
188
|
+
getArg(key) {
|
|
189
|
+
return this.getArgs(key).at(-1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 是否具有指定图片参数
|
|
194
|
+
* @param {string} key 参数名
|
|
195
|
+
* @complexity `n`
|
|
196
|
+
*/
|
|
197
|
+
hasArg(key) {
|
|
198
|
+
return this.getArgs(key).length > 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 移除指定图片参数
|
|
203
|
+
* @param {string} key 参数名
|
|
204
|
+
* @complexity `n`
|
|
205
|
+
*/
|
|
206
|
+
removeArg(key) {
|
|
207
|
+
for (const token of this.getArgs(key)) {
|
|
208
|
+
this.removeChild(token);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 获取图片参数名
|
|
214
|
+
* @complexity `n`
|
|
215
|
+
*/
|
|
216
|
+
getKeys() {
|
|
217
|
+
return this.getAllArgs().map(({name}) => name);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 获取指定的图片参数值
|
|
222
|
+
* @param {string} key 参数名
|
|
223
|
+
* @complexity `n`
|
|
224
|
+
*/
|
|
225
|
+
getValues(key) {
|
|
226
|
+
return this.getArgs(key).map(token => token.getValue());
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 获取生效的指定图片参数值
|
|
231
|
+
* @param {string} key 参数名
|
|
232
|
+
* @complexity `n`
|
|
233
|
+
*/
|
|
234
|
+
getValue(key) {
|
|
235
|
+
return this.getArg(key)?.getValue();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 设置图片参数
|
|
240
|
+
* @param {string} key 参数名
|
|
241
|
+
* @param {string|boolean} value 参数值
|
|
242
|
+
* @complexity `n`
|
|
243
|
+
* @throws `RangeError` 未定义的图片参数
|
|
244
|
+
* @throws `SyntaxError` 非法的参数
|
|
245
|
+
*/
|
|
246
|
+
setValue(key, value) {
|
|
247
|
+
if (typeof key !== 'string') {
|
|
248
|
+
this.typeError('setValue', 'String');
|
|
249
|
+
} else if (value === false) {
|
|
250
|
+
this.removeArg(key);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const token = this.getArg(key);
|
|
254
|
+
value = value === true ? value : String(value);
|
|
255
|
+
if (token) {
|
|
256
|
+
token.setValue(value);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
let syntax = '';
|
|
260
|
+
const config = this.getAttribute('config');
|
|
261
|
+
if (key !== 'caption') {
|
|
262
|
+
syntax = Object.entries(config.img).find(([, name]) => name === key)?.[0];
|
|
263
|
+
if (!syntax) {
|
|
264
|
+
throw new RangeError(`未定义的图片参数: ${key}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (value === true) {
|
|
268
|
+
if (syntax.includes('$1')) {
|
|
269
|
+
this.typeError('setValue', 'Boolean');
|
|
270
|
+
}
|
|
271
|
+
const newArg = Parser.run(() => new ImageParameterToken(syntax, config));
|
|
272
|
+
this.insertAt(newArg);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const wikitext = `[[File:F|${syntax ? syntax.replace('$1', value) : value}]]`,
|
|
276
|
+
root = Parser.parse(wikitext, this.getAttribute('include'), 6, config),
|
|
277
|
+
{length, firstChild: file} = root,
|
|
278
|
+
{name, type, length: fileLength, lastChild: imageParameter} = file;
|
|
279
|
+
if (length !== 1 || type !== 'file' || name !== 'File:F' || fileLength !== 2 || imageParameter.name !== key) {
|
|
280
|
+
throw new SyntaxError(`非法的 ${key} 参数:${noWrap(value)}`);
|
|
281
|
+
}
|
|
282
|
+
this.insertAt(imageParameter);
|
|
283
|
+
}
|
|
123
284
|
}
|
|
124
285
|
|
|
286
|
+
Parser.classes.FileToken = __filename;
|
|
125
287
|
module.exports = FileToken;
|
package/src/link/galleryImage.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {generateForSelf} = require('../../util/lint'),
|
|
4
|
+
{undo} = require('../../util/debug'),
|
|
5
|
+
singleLine = require('../../mixin/singleLine'),
|
|
4
6
|
Parser = require('../..'),
|
|
5
7
|
Token = require('..'),
|
|
6
8
|
FileToken = require('./file');
|
|
@@ -9,16 +11,27 @@ const {generateForSelf} = require('../../util/lint'),
|
|
|
9
11
|
* 图片
|
|
10
12
|
* @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
|
|
11
13
|
*/
|
|
12
|
-
class GalleryImageToken extends FileToken {
|
|
14
|
+
class GalleryImageToken extends singleLine(FileToken) {
|
|
13
15
|
type = 'gallery-image';
|
|
14
16
|
#invalid = false;
|
|
15
17
|
|
|
18
|
+
/** 图片链接 */
|
|
19
|
+
get link() {
|
|
20
|
+
return this.type === 'imagemap-image' ? undefined : super.link;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
set link(value) {
|
|
24
|
+
if (this.type !== 'imagemap-image') {
|
|
25
|
+
super.link = value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
/**
|
|
17
30
|
* @param {string} link 图片文件名
|
|
18
31
|
* @param {string|undefined} text 图片参数
|
|
19
32
|
* @param {accum} accum
|
|
20
33
|
*/
|
|
21
|
-
constructor(link, text,
|
|
34
|
+
constructor(link, text, config = Parser.getConfig(), accum = []) {
|
|
22
35
|
let token;
|
|
23
36
|
if (text !== undefined) {
|
|
24
37
|
token = new Token(text, config, true, accum);
|
|
@@ -28,17 +41,41 @@ class GalleryImageToken extends FileToken {
|
|
|
28
41
|
}
|
|
29
42
|
accum.splice(accum.indexOf(token), 1);
|
|
30
43
|
}
|
|
31
|
-
super(link, token?.toString(),
|
|
44
|
+
super(link, token?.toString(), config, accum);
|
|
32
45
|
this.setAttribute('bracket', false);
|
|
46
|
+
if (!Object.values(config.img).includes('width')) {
|
|
47
|
+
this.seal(['size', 'width', 'height'], true);
|
|
48
|
+
}
|
|
33
49
|
}
|
|
34
50
|
|
|
35
51
|
/**
|
|
36
52
|
* @override
|
|
53
|
+
* @throws `Error` 非法的内链目标
|
|
54
|
+
* @throws `Error` 不可更改命名空间
|
|
37
55
|
*/
|
|
38
56
|
afterBuild() {
|
|
39
57
|
const initImagemap = this.type === 'imagemap-image',
|
|
40
58
|
titleObj = this.normalizeTitle(String(this.firstChild), initImagemap ? 0 : 6, true, !initImagemap);
|
|
59
|
+
this.setAttribute('name', titleObj.title);
|
|
41
60
|
this.#invalid = titleObj.interwiki || titleObj.ns !== 6; // 只用于gallery-image的首次解析
|
|
61
|
+
const /** @type {AstListener} */ linkListener = (e, data) => {
|
|
62
|
+
const {prevTarget} = e;
|
|
63
|
+
if (prevTarget?.type === 'link-target') {
|
|
64
|
+
const name = String(prevTarget),
|
|
65
|
+
imagemap = this.type === 'imagemap-image',
|
|
66
|
+
{title, interwiki, ns, valid} = this.normalizeTitle(name, imagemap ? 0 : 6, true, !imagemap);
|
|
67
|
+
if (!valid) {
|
|
68
|
+
undo(e, data);
|
|
69
|
+
throw new Error(`非法的图片文件名:${name}`);
|
|
70
|
+
} else if (interwiki || ns !== 6) {
|
|
71
|
+
undo(e, data);
|
|
72
|
+
throw new Error(`图片链接不可更改命名空间:${name}`);
|
|
73
|
+
}
|
|
74
|
+
this.setAttribute('name', title);
|
|
75
|
+
this.#invalid = false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
this.addEventListener(['remove', 'insert', 'replace', 'text'], linkListener);
|
|
42
79
|
}
|
|
43
80
|
|
|
44
81
|
/** @override */
|
|
@@ -50,13 +87,34 @@ class GalleryImageToken extends FileToken {
|
|
|
50
87
|
* @override
|
|
51
88
|
* @param {number} start 起始位置
|
|
52
89
|
*/
|
|
53
|
-
lint(start =
|
|
90
|
+
lint(start = this.getAbsoluteIndex()) {
|
|
54
91
|
const errors = super.lint(start);
|
|
55
92
|
if (this.#invalid) {
|
|
56
|
-
errors.push(generateForSelf(this, {start}, '
|
|
93
|
+
errors.push(generateForSelf(this, {start}, 'invalid gallery image'));
|
|
57
94
|
}
|
|
58
95
|
return errors;
|
|
59
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @override
|
|
100
|
+
* @param {string} link 链接目标
|
|
101
|
+
* @throws `SyntaxError` 非法的链接目标
|
|
102
|
+
*/
|
|
103
|
+
setTarget(link) {
|
|
104
|
+
link = String(link);
|
|
105
|
+
const include = this.getAttribute('include'),
|
|
106
|
+
config = this.getAttribute('config'),
|
|
107
|
+
root = Parser.parse(`<gallery>${link}</gallery>`, include, 1, config),
|
|
108
|
+
{length, firstChild: gallery} = root,
|
|
109
|
+
{type, lastChild: {length: galleryLength, firstChild: image}} = gallery;
|
|
110
|
+
if (length !== 1 || type !== 'ext' || galleryLength !== 1 || image.type !== 'gallery-image') {
|
|
111
|
+
throw new SyntaxError(`非法的图库文件名:${link}`);
|
|
112
|
+
}
|
|
113
|
+
const {firstChild} = image;
|
|
114
|
+
image.destroy(true);
|
|
115
|
+
this.firstChild.safeReplaceWith(firstChild);
|
|
116
|
+
}
|
|
60
117
|
}
|
|
61
118
|
|
|
119
|
+
Parser.classes.GalleryImageToken = __filename;
|
|
62
120
|
module.exports = GalleryImageToken;
|