wikiparser-node 0.10.0 → 0.11.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/README.md +44 -32
- package/config/.schema.json +1 -8
- package/config/default.json +1 -2
- package/config/llwiki.json +1 -36
- package/config/moegirl.json +1 -45
- package/config/zhwiki.json +1 -467
- package/dist/index.d.ts +110 -0
- package/dist/lib/element.d.ts +48 -0
- package/dist/lib/node.d.ts +108 -0
- package/dist/lib/text.d.ts +30 -0
- package/dist/lib/title.d.ts +15 -0
- package/dist/mixin/hidden.d.ts +8 -0
- package/dist/parser/brackets.d.ts +12 -0
- package/dist/parser/commentAndExt.d.ts +8 -0
- package/dist/parser/converter.d.ts +7 -0
- package/dist/parser/externalLinks.d.ts +7 -0
- package/dist/parser/hrAndDoubleUnderscore.d.ts +11 -0
- package/dist/parser/html.d.ts +7 -0
- package/dist/parser/links.d.ts +7 -0
- package/dist/parser/list.d.ts +7 -0
- package/dist/parser/magicLinks.d.ts +7 -0
- package/dist/parser/quotes.d.ts +7 -0
- package/dist/parser/table.d.ts +11 -0
- package/dist/src/arg.d.ts +25 -0
- package/dist/src/atom/hidden.d.ts +5 -0
- package/dist/src/atom/index.d.ts +14 -0
- package/dist/src/attribute.d.ts +42 -0
- package/dist/src/attributes.d.ts +33 -0
- package/dist/src/converter.d.ts +29 -0
- package/dist/src/converterFlags.d.ts +27 -0
- package/dist/src/converterRule.d.ts +29 -0
- package/dist/src/extLink.d.ts +22 -0
- package/dist/src/gallery.d.ts +19 -0
- package/dist/src/hasNowiki/index.d.ts +14 -0
- package/dist/src/hasNowiki/pre.d.ts +13 -0
- package/dist/src/heading.d.ts +24 -0
- package/dist/src/html.d.ts +33 -0
- package/dist/src/imageParameter.d.ts +23 -0
- package/dist/src/imagemap.d.ts +26 -0
- package/dist/src/imagemapLink.d.ts +16 -0
- package/dist/src/index.d.ts +53 -0
- package/dist/src/link/category.d.ts +8 -0
- package/dist/src/link/file.d.ts +27 -0
- package/dist/src/link/galleryImage.d.ts +15 -0
- package/dist/src/link/index.d.ts +29 -0
- package/dist/src/magicLink.d.ts +14 -0
- package/dist/src/nested/choose.d.ts +13 -0
- package/dist/src/nested/combobox.d.ts +13 -0
- package/dist/src/nested/index.d.ts +20 -0
- package/dist/src/nested/references.d.ts +13 -0
- package/dist/src/nowiki/comment.d.ts +19 -0
- package/dist/src/nowiki/dd.d.ts +8 -0
- package/dist/src/nowiki/doubleUnderscore.d.ts +12 -0
- package/dist/src/nowiki/hr.d.ts +13 -0
- package/dist/src/nowiki/index.d.ts +18 -0
- package/dist/src/nowiki/list.d.ts +8 -0
- package/dist/src/nowiki/noinclude.d.ts +8 -0
- package/dist/src/nowiki/quote.d.ts +20 -0
- package/dist/src/onlyinclude.d.ts +17 -0
- package/dist/src/paramTag/index.d.ts +24 -0
- package/dist/src/paramTag/inputbox.d.ts +8 -0
- package/dist/src/parameter.d.ts +28 -0
- package/dist/src/syntax.d.ts +15 -0
- package/dist/src/table/index.d.ts +16 -0
- package/dist/src/table/td.d.ts +39 -0
- package/dist/src/table/tr.d.ts +17 -0
- package/dist/src/tagPair/ext.d.ts +17 -0
- package/dist/src/tagPair/include.d.ts +16 -0
- package/dist/src/tagPair/index.d.ts +28 -0
- package/dist/src/transclude.d.ts +75 -0
- package/dist/util/lint.d.ts +28 -0
- package/dist/util/string.d.ts +31 -0
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/index.js +5 -257
- package/lib/element.js +7 -482
- package/lib/node.js +11 -540
- package/lib/text.js +3 -96
- package/lib/title.js +1 -28
- package/mixin/hidden.js +0 -3
- package/package.json +11 -5
- package/parser/brackets.js +3 -2
- package/parser/commentAndExt.js +8 -6
- package/parser/converter.js +1 -2
- package/parser/externalLinks.js +1 -2
- package/parser/hrAndDoubleUnderscore.js +1 -2
- package/parser/html.js +1 -2
- package/parser/links.js +5 -6
- package/parser/list.js +1 -2
- package/parser/magicLinks.js +1 -2
- package/parser/quotes.js +1 -2
- package/parser/table.js +1 -2
- package/src/arg.js +4 -118
- package/src/atom/hidden.js +0 -2
- package/src/atom/index.js +1 -18
- package/src/attribute.js +6 -190
- package/src/attributes.js +5 -308
- package/src/converter.js +3 -109
- package/src/converterFlags.js +1 -188
- package/src/converterRule.js +2 -184
- package/src/extLink.js +2 -122
- package/src/gallery.js +2 -56
- package/src/hasNowiki/index.js +1 -13
- package/src/hasNowiki/pre.js +1 -13
- package/src/heading.js +4 -55
- package/src/html.js +5 -120
- package/src/imageParameter.js +3 -165
- package/src/imagemap.js +3 -62
- package/src/imagemapLink.js +2 -14
- package/src/index.js +9 -530
- package/src/link/category.js +1 -32
- package/src/link/file.js +3 -158
- package/src/link/galleryImage.js +3 -61
- package/src/link/index.js +4 -273
- package/src/magicLink.js +6 -87
- package/src/nested/choose.js +1 -2
- package/src/nested/combobox.js +1 -2
- package/src/nested/index.js +8 -32
- package/src/nested/references.js +1 -2
- package/src/nowiki/comment.js +2 -26
- package/src/nowiki/dd.js +1 -47
- package/src/nowiki/doubleUnderscore.js +1 -31
- package/src/nowiki/hr.js +2 -21
- package/src/nowiki/index.js +2 -24
- package/src/nowiki/list.js +2 -5
- package/src/nowiki/noinclude.js +0 -14
- package/src/nowiki/quote.js +2 -16
- package/src/onlyinclude.js +2 -27
- package/src/paramTag/index.js +2 -25
- package/src/paramTag/inputbox.js +2 -5
- package/src/parameter.js +6 -148
- package/src/syntax.js +1 -69
- package/src/table/index.js +2 -939
- package/src/table/td.js +6 -226
- package/src/table/tr.js +3 -248
- package/src/tagPair/ext.js +4 -23
- package/src/tagPair/include.js +1 -25
- package/src/tagPair/index.js +3 -52
- package/src/transclude.js +6 -513
- package/typings/api.d.ts +9 -0
- package/typings/index.d.ts +51 -0
- package/typings/node.d.ts +16 -0
- package/typings/parser.d.ts +5 -0
- package/typings/token.d.ts +28 -0
- package/util/lint.js +2 -0
- package/util/string.js +0 -51
- package/lib/ranges.js +0 -130
- package/mixin/attributeParent.js +0 -117
- package/mixin/fixedToken.js +0 -40
- package/mixin/singleLine.js +0 -31
- package/mixin/sol.js +0 -54
- package/parser/selector.js +0 -177
- package/src/charinsert.js +0 -97
- package/tool/index.js +0 -1202
- package/util/debug.js +0 -73
package/src/link/file.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {explode
|
|
3
|
+
const {explode} = require('../../util/string'),
|
|
4
4
|
{generateForChild} = require('../../util/lint'),
|
|
5
5
|
Parser = require('../..'),
|
|
6
6
|
LinkToken = require('.'),
|
|
@@ -17,63 +17,16 @@ 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
|
-
|
|
62
20
|
/**
|
|
63
21
|
* @param {string} link 文件名
|
|
64
22
|
* @param {string|undefined} text 图片参数
|
|
65
|
-
* @param {accum} accum
|
|
23
|
+
* @param {import('../../typings/token').accum} accum
|
|
66
24
|
* @param {string} delimiter `|`
|
|
67
25
|
* @complexity `n`
|
|
68
26
|
*/
|
|
69
27
|
constructor(link, text, config = Parser.getConfig(), accum = [], delimiter = '|') {
|
|
70
28
|
super(link, undefined, config, accum, delimiter);
|
|
71
|
-
this.setAttribute('acceptable', {AtomToken: 0, ImageParameterToken: '1:'});
|
|
72
29
|
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
|
-
);
|
|
77
30
|
}
|
|
78
31
|
|
|
79
32
|
/**
|
|
@@ -146,9 +99,7 @@ class FileToken extends LinkToken {
|
|
|
146
99
|
* @complexity `n`
|
|
147
100
|
*/
|
|
148
101
|
getArgs(key) {
|
|
149
|
-
return
|
|
150
|
-
? this.getAllArgs().filter(({name}) => key === name)
|
|
151
|
-
: this.typeError('getArgs', 'String');
|
|
102
|
+
return this.getAllArgs().filter(({name}) => key === name);
|
|
152
103
|
}
|
|
153
104
|
|
|
154
105
|
/**
|
|
@@ -159,9 +110,6 @@ class FileToken extends LinkToken {
|
|
|
159
110
|
*/
|
|
160
111
|
#getTypedArgs(keys, type) {
|
|
161
112
|
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
|
-
}
|
|
165
113
|
return args;
|
|
166
114
|
}
|
|
167
115
|
|
|
@@ -179,109 +127,6 @@ class FileToken extends LinkToken {
|
|
|
179
127
|
getVertAlignArgs() {
|
|
180
128
|
return this.#getTypedArgs(vertAlign, '垂直对齐');
|
|
181
129
|
}
|
|
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
|
-
}
|
|
284
130
|
}
|
|
285
131
|
|
|
286
|
-
Parser.classes.FileToken = __filename;
|
|
287
132
|
module.exports = FileToken;
|
package/src/link/galleryImage.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {generateForSelf} = require('../../util/lint'),
|
|
4
|
-
{undo} = require('../../util/debug'),
|
|
5
|
-
singleLine = require('../../mixin/singleLine'),
|
|
6
4
|
Parser = require('../..'),
|
|
7
5
|
Token = require('..'),
|
|
8
6
|
FileToken = require('./file');
|
|
@@ -11,25 +9,14 @@ const {generateForSelf} = require('../../util/lint'),
|
|
|
11
9
|
* 图片
|
|
12
10
|
* @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
|
|
13
11
|
*/
|
|
14
|
-
class GalleryImageToken extends
|
|
12
|
+
class GalleryImageToken extends FileToken {
|
|
15
13
|
type = 'gallery-image';
|
|
16
14
|
#invalid = false;
|
|
17
15
|
|
|
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
|
-
|
|
29
16
|
/**
|
|
30
17
|
* @param {string} link 图片文件名
|
|
31
18
|
* @param {string|undefined} text 图片参数
|
|
32
|
-
* @param {accum} accum
|
|
19
|
+
* @param {import('../../typings/token').accum} accum
|
|
33
20
|
*/
|
|
34
21
|
constructor(link, text, config = Parser.getConfig(), accum = []) {
|
|
35
22
|
let token;
|
|
@@ -43,39 +30,15 @@ class GalleryImageToken extends singleLine(FileToken) {
|
|
|
43
30
|
}
|
|
44
31
|
super(link, token?.toString(), config, accum);
|
|
45
32
|
this.setAttribute('bracket', false);
|
|
46
|
-
if (!Object.values(config.img).includes('width')) {
|
|
47
|
-
this.seal(['size', 'width', 'height'], true);
|
|
48
|
-
}
|
|
49
33
|
}
|
|
50
34
|
|
|
51
35
|
/**
|
|
52
36
|
* @override
|
|
53
|
-
* @throws `Error` 非法的内链目标
|
|
54
|
-
* @throws `Error` 不可更改命名空间
|
|
55
37
|
*/
|
|
56
38
|
afterBuild() {
|
|
57
39
|
const initImagemap = this.type === 'imagemap-image',
|
|
58
40
|
titleObj = this.normalizeTitle(String(this.firstChild), initImagemap ? 0 : 6, true, !initImagemap);
|
|
59
|
-
this
|
|
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);
|
|
41
|
+
this.#invalid = titleObj.ns !== 6; // 只用于gallery-image的首次解析
|
|
79
42
|
}
|
|
80
43
|
|
|
81
44
|
/** @override */
|
|
@@ -94,27 +57,6 @@ class GalleryImageToken extends singleLine(FileToken) {
|
|
|
94
57
|
}
|
|
95
58
|
return errors;
|
|
96
59
|
}
|
|
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
|
-
}
|
|
117
60
|
}
|
|
118
61
|
|
|
119
|
-
Parser.classes.GalleryImageToken = __filename;
|
|
120
62
|
module.exports = GalleryImageToken;
|
package/src/link/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {generateForChild} = require('../../util/lint'),
|
|
4
|
-
{noWrap} = require('../../util/string'),
|
|
5
|
-
{undo} = require('../../util/debug'),
|
|
6
4
|
Parser = require('../..'),
|
|
7
5
|
AstText = require('../../lib/text'),
|
|
8
6
|
Token = require('..'),
|
|
@@ -19,134 +17,43 @@ class LinkToken extends Token {
|
|
|
19
17
|
#fragment;
|
|
20
18
|
#encoded = false;
|
|
21
19
|
|
|
22
|
-
/** 完整链接,和FileToken保持一致 */
|
|
23
|
-
get link() {
|
|
24
|
-
return this.#getTitle();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
set link(link) {
|
|
28
|
-
this.setTarget(link);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** 是否链接到自身 */
|
|
32
|
-
get selfLink() {
|
|
33
|
-
const {title, fragment} = this.#getTitle();
|
|
34
|
-
return !title && Boolean(fragment);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
set selfLink(selfLink) {
|
|
38
|
-
if (selfLink === true) {
|
|
39
|
-
this.asSelfLink();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** fragment */
|
|
44
|
-
get fragment() {
|
|
45
|
-
return this.#getTitle().fragment;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
set fragment(fragment) {
|
|
49
|
-
this.#setFragment(fragment);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** interwiki */
|
|
53
|
-
get interwiki() {
|
|
54
|
-
return this.#getTitle().interwiki;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
set interwiki(interwiki) {
|
|
58
|
-
if (typeof interwiki !== 'string') {
|
|
59
|
-
this.typeError('set interwiki', 'String');
|
|
60
|
-
}
|
|
61
|
-
const {prefix, main, fragment} = this.#getTitle(),
|
|
62
|
-
link = `${interwiki}:${prefix}${main}${fragment === undefined ? '' : `#${fragment}`}`;
|
|
63
|
-
if (interwiki && !this.isInterwiki(link)) {
|
|
64
|
-
throw new RangeError(`${interwiki} 不是合法的跨维基前缀!`);
|
|
65
|
-
}
|
|
66
|
-
this.setTarget(link);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** 链接显示文字 */
|
|
70
|
-
get innerText() {
|
|
71
|
-
if (this.type === 'link') {
|
|
72
|
-
return this.length > 1
|
|
73
|
-
? this.lastChild.text()
|
|
74
|
-
: this.firstChild.text().replace(/^\s*:/u, '');
|
|
75
|
-
}
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
20
|
/**
|
|
80
21
|
* @param {string} link 链接标题
|
|
81
22
|
* @param {string|undefined} linkText 链接显示文字
|
|
82
|
-
* @param {accum} accum
|
|
23
|
+
* @param {import('../../typings/token').accum} accum
|
|
83
24
|
* @param {string} delimiter `|`
|
|
84
25
|
*/
|
|
85
26
|
constructor(link, linkText, config = Parser.getConfig(), accum = [], delimiter = '|') {
|
|
86
27
|
super(undefined, config, true, accum, {
|
|
87
|
-
AtomToken: 0, Token: 1,
|
|
88
28
|
});
|
|
89
29
|
this.insertAt(new AtomToken(link, 'link-target', config, accum, {
|
|
90
|
-
'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '',
|
|
91
30
|
}));
|
|
92
31
|
if (linkText !== undefined) {
|
|
93
32
|
const inner = new Token(linkText, config, true, accum, {
|
|
94
|
-
'Stage-5': ':', ConverterToken: ':',
|
|
95
33
|
});
|
|
96
34
|
inner.type = 'link-text';
|
|
97
35
|
this.insertAt(inner.setAttribute('stage', Parser.MAX_STAGE - 1));
|
|
98
36
|
}
|
|
99
37
|
this.#delimiter = delimiter;
|
|
100
|
-
this.getAttribute('protectChildren')(0);
|
|
101
38
|
}
|
|
102
39
|
|
|
103
40
|
/**
|
|
104
41
|
* @override
|
|
105
|
-
* @throws `Error` 非法的内链目标
|
|
106
|
-
* @throws `Error` 不可更改命名空间
|
|
107
42
|
*/
|
|
108
43
|
afterBuild() {
|
|
109
44
|
const titleObj = this.normalizeTitle(this.firstChild.text(), 0, false, true, true);
|
|
110
|
-
this.setAttribute('name', titleObj.title);
|
|
111
45
|
this.#fragment = titleObj.fragment;
|
|
112
46
|
this.#encoded = titleObj.encoded;
|
|
113
47
|
if (this.#delimiter?.includes('\0')) {
|
|
114
48
|
this.#delimiter = this.getAttribute('buildFromStr')(this.#delimiter, 'string');
|
|
115
49
|
}
|
|
116
|
-
const /** @type {AstListener} */ linkListener = (e, data) => {
|
|
117
|
-
const {prevTarget} = e;
|
|
118
|
-
if (prevTarget?.type === 'link-target') {
|
|
119
|
-
const name = prevTarget.text(),
|
|
120
|
-
{title, interwiki, ns, valid, fragment, encoded} = this.normalizeTitle(name, 0, false, true, true);
|
|
121
|
-
if (!valid) {
|
|
122
|
-
undo(e, data);
|
|
123
|
-
throw new Error(`非法的内链目标:${name}`);
|
|
124
|
-
} else if (this.type === 'category' && (interwiki || ns !== 14)
|
|
125
|
-
|| this.type === 'file' && (interwiki || ns !== 6)
|
|
126
|
-
) {
|
|
127
|
-
undo(e, data);
|
|
128
|
-
throw new Error(`${this.type === 'file' ? '文件' : '分类'}链接不可更改命名空间:${name}`);
|
|
129
|
-
} else if (this.type === 'link' && !interwiki && (ns === 6 || ns === 14) && name.trim()[0] !== ':') {
|
|
130
|
-
const /** @type {{firstChild: AstText}} */ {firstChild} = prevTarget;
|
|
131
|
-
if (firstChild.type === 'text') {
|
|
132
|
-
firstChild.insertData(0, ':');
|
|
133
|
-
} else {
|
|
134
|
-
prevTarget.prepend(':');
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
this.setAttribute('name', title);
|
|
138
|
-
this.#fragment = fragment;
|
|
139
|
-
this.#encoded = encoded;
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
this.addEventListener(['remove', 'insert', 'replace', 'text'], linkListener);
|
|
143
50
|
}
|
|
144
51
|
|
|
145
52
|
/**
|
|
146
53
|
* @override
|
|
147
54
|
* @template {string} T
|
|
148
55
|
* @param {T} key 属性键
|
|
149
|
-
* @param {TokenAttribute<T>} value 属性值
|
|
56
|
+
* @param {import('../../typings/node').TokenAttribute<T>} value 属性值
|
|
150
57
|
*/
|
|
151
58
|
setAttribute(key, value) {
|
|
152
59
|
if (key === 'bracket') {
|
|
@@ -158,11 +65,10 @@ class LinkToken extends Token {
|
|
|
158
65
|
|
|
159
66
|
/**
|
|
160
67
|
* @override
|
|
161
|
-
* @param {string} selector
|
|
162
68
|
*/
|
|
163
69
|
toString(selector) {
|
|
164
70
|
const str = super.toString(selector, this.#delimiter);
|
|
165
|
-
return this.#bracket
|
|
71
|
+
return this.#bracket ? `[[${str}]]` : str;
|
|
166
72
|
}
|
|
167
73
|
|
|
168
74
|
/** @override */
|
|
@@ -181,11 +87,6 @@ class LinkToken extends Token {
|
|
|
181
87
|
return this.#delimiter.length;
|
|
182
88
|
}
|
|
183
89
|
|
|
184
|
-
/** @override */
|
|
185
|
-
print() {
|
|
186
|
-
return super.print(this.#bracket ? {pre: '[[', post: ']]', sep: this.#delimiter} : {sep: this.#delimiter});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
90
|
/**
|
|
190
91
|
* @override
|
|
191
92
|
* @param {number} start 起始位置
|
|
@@ -194,7 +95,7 @@ class LinkToken extends Token {
|
|
|
194
95
|
const errors = super.lint(start),
|
|
195
96
|
{childNodes: [target, linkText], type: linkType} = this;
|
|
196
97
|
let rect;
|
|
197
|
-
if (target.childNodes.some(({type}) => type === 'template')) {
|
|
98
|
+
if (linkType === 'link' && target.childNodes.some(({type}) => type === 'template')) {
|
|
198
99
|
rect = {start, ...this.getRootNode().posFromIndex(start)};
|
|
199
100
|
errors.push(generateForChild(target, rect, 'template in an internal link target', 'warning'));
|
|
200
101
|
}
|
|
@@ -213,176 +114,6 @@ class LinkToken extends Token {
|
|
|
213
114
|
}
|
|
214
115
|
return errors;
|
|
215
116
|
}
|
|
216
|
-
|
|
217
|
-
/** 生成Title对象 */
|
|
218
|
-
#getTitle() {
|
|
219
|
-
return this.normalizeTitle(this.firstChild.text(), 0, false, true, true);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* @override
|
|
224
|
-
* @this {LinkToken & {constructor: typeof LinkToken}}
|
|
225
|
-
*/
|
|
226
|
-
cloneNode() {
|
|
227
|
-
const [link, ...linkText] = this.cloneChildNodes();
|
|
228
|
-
return Parser.run(() => {
|
|
229
|
-
const token = new this.constructor('', undefined, this.#getTitle(), this.getAttribute('config'));
|
|
230
|
-
token.firstChild.safeReplaceWith(link);
|
|
231
|
-
token.append(...linkText);
|
|
232
|
-
token.afterBuild();
|
|
233
|
-
return token;
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* 设置链接目标
|
|
239
|
-
* @param {string} link 链接目标
|
|
240
|
-
* @throws `SyntaxError` 非法的链接目标
|
|
241
|
-
*/
|
|
242
|
-
setTarget(link) {
|
|
243
|
-
link = String(link);
|
|
244
|
-
if (this.type === 'link' && !/^\s*[:#]/u.test(link)) {
|
|
245
|
-
link = `:${link}`;
|
|
246
|
-
}
|
|
247
|
-
const root = Parser.parse(`[[${link}]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
|
|
248
|
-
{length, firstChild: wikiLink} = root,
|
|
249
|
-
{type, firstChild, length: linkLength} = wikiLink;
|
|
250
|
-
if (length !== 1 || type !== this.type || linkLength !== 1) {
|
|
251
|
-
const msgs = {link: '内链', file: '文件链接', category: '分类'};
|
|
252
|
-
throw new SyntaxError(`非法的${msgs[this.type]}目标:${link}`);
|
|
253
|
-
}
|
|
254
|
-
wikiLink.destroy(true);
|
|
255
|
-
this.firstChild.safeReplaceWith(firstChild);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* 设置跨语言链接
|
|
260
|
-
* @param {string} lang 语言前缀
|
|
261
|
-
* @param {string} link 页面标题
|
|
262
|
-
* @throws `SyntaxError` 非法的跨语言链接
|
|
263
|
-
*/
|
|
264
|
-
setLangLink(lang, link) {
|
|
265
|
-
if (typeof lang !== 'string') {
|
|
266
|
-
this.typeError('setLangLink', 'String');
|
|
267
|
-
}
|
|
268
|
-
link = String(link).trim();
|
|
269
|
-
const [char] = link;
|
|
270
|
-
if (char === '#') {
|
|
271
|
-
throw new SyntaxError('跨语言链接不能仅为fragment!');
|
|
272
|
-
} else if (char === ':') {
|
|
273
|
-
link = link.slice(1);
|
|
274
|
-
}
|
|
275
|
-
const root = Parser.parse(`[[${lang}:${link}]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
|
|
276
|
-
/** @type {Token & {firstChild: LinkToken}} */ {length, firstChild: wikiLink} = root,
|
|
277
|
-
{type, length: linkLength, interwiki, firstChild} = wikiLink;
|
|
278
|
-
if (length !== 1 || type !== 'link' || linkLength !== 1 || interwiki !== lang.toLowerCase()) {
|
|
279
|
-
throw new SyntaxError(`非法的跨语言链接目标:${lang}:${link}`);
|
|
280
|
-
}
|
|
281
|
-
wikiLink.destroy(true);
|
|
282
|
-
this.firstChild.safeReplaceWith(firstChild);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* 设置fragment
|
|
287
|
-
* @param {string} fragment fragment
|
|
288
|
-
* @param {boolean} page 是否是其他页面
|
|
289
|
-
* @throws `SyntaxError` 非法的fragment
|
|
290
|
-
*/
|
|
291
|
-
#setFragment(fragment, page = true) {
|
|
292
|
-
fragment &&= String(fragment).replace(/[<>[\]#|=]/gu, p => encodeURIComponent(p));
|
|
293
|
-
const include = this.getAttribute('include'),
|
|
294
|
-
config = this.getAttribute('config'),
|
|
295
|
-
root = Parser.parse(`[[${page ? `:${this.name}` : ''}${
|
|
296
|
-
fragment === undefined ? '' : `#${fragment}`
|
|
297
|
-
}]]`, include, 6, config),
|
|
298
|
-
{length, firstChild: wikiLink} = root,
|
|
299
|
-
{type, length: linkLength, firstChild} = wikiLink;
|
|
300
|
-
if (length !== 1 || type !== 'link' || linkLength !== 1) {
|
|
301
|
-
throw new SyntaxError(`非法的 fragment:${fragment}`);
|
|
302
|
-
} else if (page) {
|
|
303
|
-
Parser.warn(`${this.constructor.name}.setFragment 方法会同时规范化页面名!`);
|
|
304
|
-
}
|
|
305
|
-
wikiLink.destroy(true);
|
|
306
|
-
this.firstChild.safeReplaceWith(firstChild);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* 设置fragment
|
|
311
|
-
* @param {string} fragment fragment
|
|
312
|
-
*/
|
|
313
|
-
setFragment(fragment) {
|
|
314
|
-
this.#setFragment(fragment);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* 修改为到自身的链接
|
|
319
|
-
* @param {string} fragment fragment
|
|
320
|
-
* @throws `RangeError` 空fragment
|
|
321
|
-
*/
|
|
322
|
-
asSelfLink(fragment = this.fragment) {
|
|
323
|
-
fragment &&= String(fragment);
|
|
324
|
-
if (!fragment?.trim()) {
|
|
325
|
-
throw new RangeError(`${this.constructor.name}.asSelfLink 方法必须指定非空的 fragment!`);
|
|
326
|
-
}
|
|
327
|
-
this.#setFragment(fragment, false);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* 设置链接显示文字
|
|
332
|
-
* @param {string} linkText 链接显示文字
|
|
333
|
-
* @throws `SyntaxError` 非法的链接显示文字
|
|
334
|
-
*/
|
|
335
|
-
setLinkText(linkText = '') {
|
|
336
|
-
linkText = String(linkText);
|
|
337
|
-
let lastChild;
|
|
338
|
-
const config = this.getAttribute('config');
|
|
339
|
-
if (linkText) {
|
|
340
|
-
const root = Parser.parse(`[[${
|
|
341
|
-
this.type === 'category' ? 'Category:' : ''
|
|
342
|
-
}L|${linkText}]]`, this.getAttribute('include'), 6, config),
|
|
343
|
-
{length, firstChild: wikiLink} = root;
|
|
344
|
-
if (length !== 1 || wikiLink.type !== this.type || wikiLink.length !== 2) {
|
|
345
|
-
throw new SyntaxError(`非法的${this.type === 'link' ? '内链文字' : '分类关键字'}:${noWrap(linkText)}`);
|
|
346
|
-
}
|
|
347
|
-
({lastChild} = wikiLink);
|
|
348
|
-
} else {
|
|
349
|
-
lastChild = Parser.run(() => new Token('', config));
|
|
350
|
-
lastChild.setAttribute('stage', 7).type = 'link-text';
|
|
351
|
-
}
|
|
352
|
-
if (this.length === 1) {
|
|
353
|
-
this.insertAt(lastChild);
|
|
354
|
-
} else {
|
|
355
|
-
this.lastChild.safeReplaceWith(lastChild);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* 自动生成管道符后的链接文字
|
|
361
|
-
* @throws `Error` 带有"#"或"%"时不可用
|
|
362
|
-
*/
|
|
363
|
-
pipeTrick() {
|
|
364
|
-
const linkText = this.firstChild.text();
|
|
365
|
-
if (linkText.includes('#') || linkText.includes('%')) {
|
|
366
|
-
throw new Error('Pipe trick 不能用于带有"#"或"%"的场合!');
|
|
367
|
-
}
|
|
368
|
-
const m1 = /^:?(?:[ \w\x80-\xFF-]+:)?([^(]+)\(.+\)$/u.exec(linkText);
|
|
369
|
-
if (m1) {
|
|
370
|
-
this.setLinkText(m1[1].trim());
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
const m2 = /^:?(?:[ \w\x80-\xFF-]+:)?([^(]+)(.+)$/u.exec(linkText);
|
|
374
|
-
if (m2) {
|
|
375
|
-
this.setLinkText(m2[1].trim());
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
const m3 = /^:?(?:[ \w\x80-\xFF-]+:)?(.+?)(?:(?<!\()\(.+\))?(?:, |,|، )./u.exec(linkText);
|
|
379
|
-
if (m3) {
|
|
380
|
-
this.setLinkText(m3[1].trim());
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
this.setLinkText(linkText);
|
|
384
|
-
}
|
|
385
117
|
}
|
|
386
118
|
|
|
387
|
-
Parser.classes.LinkToken = __filename;
|
|
388
119
|
module.exports = LinkToken;
|