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.
Files changed (155) hide show
  1. package/README.md +44 -32
  2. package/config/.schema.json +1 -8
  3. package/config/default.json +1 -2
  4. package/config/llwiki.json +1 -36
  5. package/config/moegirl.json +1 -45
  6. package/config/zhwiki.json +1 -467
  7. package/dist/index.d.ts +110 -0
  8. package/dist/lib/element.d.ts +48 -0
  9. package/dist/lib/node.d.ts +108 -0
  10. package/dist/lib/text.d.ts +30 -0
  11. package/dist/lib/title.d.ts +15 -0
  12. package/dist/mixin/hidden.d.ts +8 -0
  13. package/dist/parser/brackets.d.ts +12 -0
  14. package/dist/parser/commentAndExt.d.ts +8 -0
  15. package/dist/parser/converter.d.ts +7 -0
  16. package/dist/parser/externalLinks.d.ts +7 -0
  17. package/dist/parser/hrAndDoubleUnderscore.d.ts +11 -0
  18. package/dist/parser/html.d.ts +7 -0
  19. package/dist/parser/links.d.ts +7 -0
  20. package/dist/parser/list.d.ts +7 -0
  21. package/dist/parser/magicLinks.d.ts +7 -0
  22. package/dist/parser/quotes.d.ts +7 -0
  23. package/dist/parser/table.d.ts +11 -0
  24. package/dist/src/arg.d.ts +25 -0
  25. package/dist/src/atom/hidden.d.ts +5 -0
  26. package/dist/src/atom/index.d.ts +14 -0
  27. package/dist/src/attribute.d.ts +42 -0
  28. package/dist/src/attributes.d.ts +33 -0
  29. package/dist/src/converter.d.ts +29 -0
  30. package/dist/src/converterFlags.d.ts +27 -0
  31. package/dist/src/converterRule.d.ts +29 -0
  32. package/dist/src/extLink.d.ts +22 -0
  33. package/dist/src/gallery.d.ts +19 -0
  34. package/dist/src/hasNowiki/index.d.ts +14 -0
  35. package/dist/src/hasNowiki/pre.d.ts +13 -0
  36. package/dist/src/heading.d.ts +24 -0
  37. package/dist/src/html.d.ts +33 -0
  38. package/dist/src/imageParameter.d.ts +23 -0
  39. package/dist/src/imagemap.d.ts +26 -0
  40. package/dist/src/imagemapLink.d.ts +16 -0
  41. package/dist/src/index.d.ts +53 -0
  42. package/dist/src/link/category.d.ts +8 -0
  43. package/dist/src/link/file.d.ts +27 -0
  44. package/dist/src/link/galleryImage.d.ts +15 -0
  45. package/dist/src/link/index.d.ts +29 -0
  46. package/dist/src/magicLink.d.ts +14 -0
  47. package/dist/src/nested/choose.d.ts +13 -0
  48. package/dist/src/nested/combobox.d.ts +13 -0
  49. package/dist/src/nested/index.d.ts +20 -0
  50. package/dist/src/nested/references.d.ts +13 -0
  51. package/dist/src/nowiki/comment.d.ts +19 -0
  52. package/dist/src/nowiki/dd.d.ts +8 -0
  53. package/dist/src/nowiki/doubleUnderscore.d.ts +12 -0
  54. package/dist/src/nowiki/hr.d.ts +13 -0
  55. package/dist/src/nowiki/index.d.ts +18 -0
  56. package/dist/src/nowiki/list.d.ts +8 -0
  57. package/dist/src/nowiki/noinclude.d.ts +8 -0
  58. package/dist/src/nowiki/quote.d.ts +20 -0
  59. package/dist/src/onlyinclude.d.ts +17 -0
  60. package/dist/src/paramTag/index.d.ts +24 -0
  61. package/dist/src/paramTag/inputbox.d.ts +8 -0
  62. package/dist/src/parameter.d.ts +28 -0
  63. package/dist/src/syntax.d.ts +15 -0
  64. package/dist/src/table/index.d.ts +16 -0
  65. package/dist/src/table/td.d.ts +39 -0
  66. package/dist/src/table/tr.d.ts +17 -0
  67. package/dist/src/tagPair/ext.d.ts +17 -0
  68. package/dist/src/tagPair/include.d.ts +16 -0
  69. package/dist/src/tagPair/index.d.ts +28 -0
  70. package/dist/src/transclude.d.ts +75 -0
  71. package/dist/util/lint.d.ts +28 -0
  72. package/dist/util/string.d.ts +31 -0
  73. package/i18n/zh-hans.json +1 -1
  74. package/i18n/zh-hant.json +1 -1
  75. package/index.js +5 -257
  76. package/lib/element.js +7 -482
  77. package/lib/node.js +11 -540
  78. package/lib/text.js +3 -96
  79. package/lib/title.js +1 -28
  80. package/mixin/hidden.js +0 -3
  81. package/package.json +11 -5
  82. package/parser/brackets.js +3 -2
  83. package/parser/commentAndExt.js +8 -6
  84. package/parser/converter.js +1 -2
  85. package/parser/externalLinks.js +1 -2
  86. package/parser/hrAndDoubleUnderscore.js +1 -2
  87. package/parser/html.js +1 -2
  88. package/parser/links.js +5 -6
  89. package/parser/list.js +1 -2
  90. package/parser/magicLinks.js +1 -2
  91. package/parser/quotes.js +1 -2
  92. package/parser/table.js +1 -2
  93. package/src/arg.js +4 -118
  94. package/src/atom/hidden.js +0 -2
  95. package/src/atom/index.js +1 -18
  96. package/src/attribute.js +6 -190
  97. package/src/attributes.js +5 -308
  98. package/src/converter.js +3 -109
  99. package/src/converterFlags.js +1 -188
  100. package/src/converterRule.js +2 -184
  101. package/src/extLink.js +2 -122
  102. package/src/gallery.js +2 -56
  103. package/src/hasNowiki/index.js +1 -13
  104. package/src/hasNowiki/pre.js +1 -13
  105. package/src/heading.js +4 -55
  106. package/src/html.js +5 -120
  107. package/src/imageParameter.js +3 -165
  108. package/src/imagemap.js +3 -62
  109. package/src/imagemapLink.js +2 -14
  110. package/src/index.js +9 -530
  111. package/src/link/category.js +1 -32
  112. package/src/link/file.js +3 -158
  113. package/src/link/galleryImage.js +3 -61
  114. package/src/link/index.js +4 -273
  115. package/src/magicLink.js +6 -87
  116. package/src/nested/choose.js +1 -2
  117. package/src/nested/combobox.js +1 -2
  118. package/src/nested/index.js +8 -32
  119. package/src/nested/references.js +1 -2
  120. package/src/nowiki/comment.js +2 -26
  121. package/src/nowiki/dd.js +1 -47
  122. package/src/nowiki/doubleUnderscore.js +1 -31
  123. package/src/nowiki/hr.js +2 -21
  124. package/src/nowiki/index.js +2 -24
  125. package/src/nowiki/list.js +2 -5
  126. package/src/nowiki/noinclude.js +0 -14
  127. package/src/nowiki/quote.js +2 -16
  128. package/src/onlyinclude.js +2 -27
  129. package/src/paramTag/index.js +2 -25
  130. package/src/paramTag/inputbox.js +2 -5
  131. package/src/parameter.js +6 -148
  132. package/src/syntax.js +1 -69
  133. package/src/table/index.js +2 -939
  134. package/src/table/td.js +6 -226
  135. package/src/table/tr.js +3 -248
  136. package/src/tagPair/ext.js +4 -23
  137. package/src/tagPair/include.js +1 -25
  138. package/src/tagPair/index.js +3 -52
  139. package/src/transclude.js +6 -513
  140. package/typings/api.d.ts +9 -0
  141. package/typings/index.d.ts +51 -0
  142. package/typings/node.d.ts +16 -0
  143. package/typings/parser.d.ts +5 -0
  144. package/typings/token.d.ts +28 -0
  145. package/util/lint.js +2 -0
  146. package/util/string.js +0 -51
  147. package/lib/ranges.js +0 -130
  148. package/mixin/attributeParent.js +0 -117
  149. package/mixin/fixedToken.js +0 -40
  150. package/mixin/singleLine.js +0 -31
  151. package/mixin/sol.js +0 -54
  152. package/parser/selector.js +0 -177
  153. package/src/charinsert.js +0 -97
  154. package/tool/index.js +0 -1202
  155. 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, noWrap} = require('../../util/string'),
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 typeof key === 'string'
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;
@@ -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 singleLine(FileToken) {
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.setAttribute('name', titleObj.title);
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 && !(selector && this.matches(selector)) ? `[[${str}]]` : str;
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;