wikiparser-node 0.4.0 → 0.6.2-b

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 (86) hide show
  1. package/bundle/bundle.min.js +34 -0
  2. package/package.json +12 -5
  3. package/.eslintrc.json +0 -714
  4. package/README.md +0 -39
  5. package/config/default.json +0 -769
  6. package/config/llwiki.json +0 -630
  7. package/config/moegirl.json +0 -727
  8. package/config/zhwiki.json +0 -1269
  9. package/errors/README +0 -1
  10. package/index.js +0 -245
  11. package/jsconfig.json +0 -7
  12. package/lib/element.js +0 -755
  13. package/lib/node.js +0 -585
  14. package/lib/ranges.js +0 -131
  15. package/lib/text.js +0 -146
  16. package/lib/title.js +0 -69
  17. package/mixin/attributeParent.js +0 -113
  18. package/mixin/fixedToken.js +0 -40
  19. package/mixin/hidden.js +0 -19
  20. package/mixin/sol.js +0 -59
  21. package/parser/brackets.js +0 -112
  22. package/parser/commentAndExt.js +0 -63
  23. package/parser/converter.js +0 -45
  24. package/parser/externalLinks.js +0 -31
  25. package/parser/hrAndDoubleUnderscore.js +0 -35
  26. package/parser/html.js +0 -42
  27. package/parser/links.js +0 -98
  28. package/parser/list.js +0 -59
  29. package/parser/magicLinks.js +0 -41
  30. package/parser/quotes.js +0 -64
  31. package/parser/selector.js +0 -175
  32. package/parser/table.js +0 -112
  33. package/printed/README +0 -1
  34. package/printed/example.json +0 -120
  35. package/src/arg.js +0 -169
  36. package/src/atom/hidden.js +0 -13
  37. package/src/atom/index.js +0 -41
  38. package/src/attribute.js +0 -422
  39. package/src/converter.js +0 -157
  40. package/src/converterFlags.js +0 -232
  41. package/src/converterRule.js +0 -253
  42. package/src/extLink.js +0 -167
  43. package/src/gallery.js +0 -91
  44. package/src/heading.js +0 -100
  45. package/src/html.js +0 -202
  46. package/src/imageParameter.js +0 -254
  47. package/src/index.js +0 -737
  48. package/src/link/category.js +0 -53
  49. package/src/link/file.js +0 -265
  50. package/src/link/galleryImage.js +0 -61
  51. package/src/link/index.js +0 -322
  52. package/src/magicLink.js +0 -108
  53. package/src/nowiki/comment.js +0 -57
  54. package/src/nowiki/dd.js +0 -59
  55. package/src/nowiki/doubleUnderscore.js +0 -51
  56. package/src/nowiki/hr.js +0 -41
  57. package/src/nowiki/index.js +0 -44
  58. package/src/nowiki/list.js +0 -16
  59. package/src/nowiki/noinclude.js +0 -28
  60. package/src/nowiki/quote.js +0 -36
  61. package/src/onlyinclude.js +0 -54
  62. package/src/parameter.js +0 -187
  63. package/src/syntax.js +0 -83
  64. package/src/table/index.js +0 -967
  65. package/src/table/td.js +0 -308
  66. package/src/table/tr.js +0 -282
  67. package/src/tagPair/ext.js +0 -105
  68. package/src/tagPair/include.js +0 -50
  69. package/src/tagPair/index.js +0 -117
  70. package/src/transclude.js +0 -703
  71. package/test/api.js +0 -83
  72. package/test/real.js +0 -133
  73. package/test/test.js +0 -28
  74. package/test/util.js +0 -80
  75. package/tool/index.js +0 -918
  76. package/typings/api.d.ts +0 -13
  77. package/typings/array.d.ts +0 -28
  78. package/typings/event.d.ts +0 -24
  79. package/typings/index.d.ts +0 -94
  80. package/typings/node.d.ts +0 -29
  81. package/typings/parser.d.ts +0 -16
  82. package/typings/table.d.ts +0 -14
  83. package/typings/token.d.ts +0 -22
  84. package/typings/tool.d.ts +0 -11
  85. package/util/debug.js +0 -73
  86. package/util/string.js +0 -88
@@ -1,53 +0,0 @@
1
- 'use strict';
2
-
3
- const Title = require('../../lib/title'),
4
- Parser = require('../..'),
5
- LinkToken = require('.'),
6
- Token = require('..');
7
-
8
- /**
9
- * 分类
10
- * @classdesc `{childNodes: [AtomToken, ?Token]}`
11
- */
12
- class CategoryToken extends LinkToken {
13
- type = 'category';
14
-
15
- setLangLink = undefined;
16
- setFragment = undefined;
17
- asSelfLink = undefined;
18
- pipeTrick = undefined;
19
-
20
- /** 分类排序关键字 */
21
- get sortkey() {
22
- return this.children[1]?.text()
23
- ?.replaceAll(/&#(\d+);/gu, /** @param {string} p */ (_, p) => String.fromCodePoint(Number(p)))
24
- ?.replaceAll(/&#x([\da-f]+);/giu, /** @param {string} p */ (_, p) => String.fromCodePoint(parseInt(p, 16)))
25
- ?.replaceAll('\n', '') ?? '';
26
- }
27
-
28
- set sortkey(text) {
29
- this.setSortkey(text);
30
- }
31
-
32
- /**
33
- * @param {string} link 分类名
34
- * @param {string|undefined} text 排序关键字
35
- * @param {Title} title 分类页面标题对象
36
- * @param {accum} accum
37
- */
38
- constructor(link, text, title, config = Parser.getConfig(), accum = []) {
39
- super(link, text, title, config, accum);
40
- this.seal(['setFragment', 'asSelfLink', 'pipeTrick'], true);
41
- }
42
-
43
- /**
44
- * 设置排序关键字
45
- * @param {string} text 排序关键字
46
- */
47
- setSortkey(text) {
48
- this.setLinkText(text);
49
- }
50
- }
51
-
52
- Parser.classes.CategoryToken = __filename;
53
- module.exports = CategoryToken;
package/src/link/file.js DELETED
@@ -1,265 +0,0 @@
1
- 'use strict';
2
-
3
- const Title = require('../../lib/title'),
4
- {explode, noWrap} = require('../../util/string'),
5
- {externalUse} = require('../../util/debug'),
6
- Parser = require('../..'),
7
- LinkToken = require('.'),
8
- ImageParameterToken = require('../imageParameter');
9
-
10
- /**
11
- * 图片
12
- * @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
13
- */
14
- class FileToken extends LinkToken {
15
- type = 'file';
16
- /** @type {Set<string>} */ #keys = new Set();
17
- /** @type {Record<string, Set<ImageParameterToken>>} */ #args = {};
18
-
19
- setLangLink = undefined;
20
- setFragment = undefined;
21
- asSelfLink = undefined;
22
- setLinkText = undefined;
23
- pipeTrick = undefined;
24
-
25
- /** 图片链接 */
26
- get link() {
27
- return this.getArg('link')?.link;
28
- }
29
-
30
- set link(value) {
31
- this.setValue('link', value);
32
- }
33
-
34
- /** 图片大小 */
35
- get size() {
36
- return this.getArg('width')?.size;
37
- }
38
-
39
- /** 图片宽度 */
40
- get width() {
41
- return this.size?.width;
42
- }
43
-
44
- set width(width) {
45
- const arg = this.getArg('width');
46
- if (arg) {
47
- arg.width = width;
48
- } else {
49
- this.setValue('width', width);
50
- }
51
- }
52
-
53
- /** 图片高度 */
54
- get height() {
55
- return this.size?.height;
56
- }
57
-
58
- set height(height) {
59
- const arg = this.getArg('width');
60
- if (arg) {
61
- arg.height = height;
62
- } else {
63
- this.setValue('width', `x${height}`);
64
- }
65
- }
66
-
67
- /**
68
- * @param {string} link 文件名
69
- * @param {string|undefined} text 图片参数
70
- * @param {Title} title 文件标题对象
71
- * @param {accum} accum
72
- * @complexity `n`
73
- */
74
- constructor(link, text, title, config = Parser.getConfig(), accum = []) {
75
- super(link, undefined, title, config, accum);
76
- this.setAttribute('acceptable', {AtomToken: 0, ImageParameterToken: '1:'});
77
- this.append(...explode('-{', '}-', '|', text).map(part => new ImageParameterToken(part, config, accum)));
78
- this.seal(['setLangLink', 'setFragment', 'asSelfLink', 'setLinkText', 'pipeTrick'], true);
79
- }
80
-
81
- /**
82
- * @override
83
- * @param {number} i 移除位置
84
- * @complexity `n`
85
- */
86
- removeAt(i) {
87
- const /** @type {ImageParameterToken} */ token = super.removeAt(i),
88
- args = this.getArgs(token.name, false, false);
89
- args.delete(token);
90
- if (args.size === 0) {
91
- this.#keys.delete(token.name);
92
- }
93
- return token;
94
- }
95
-
96
- /**
97
- * @override
98
- * @param {ImageParameterToken} token 待插入的子节点
99
- * @param {number} i 插入位置
100
- * @complexity `n`
101
- */
102
- insertAt(token, i = this.childNodes.length) {
103
- if (!Parser.running) {
104
- this.getArgs(token.name, false, false).add(token);
105
- this.#keys.add(token.name);
106
- }
107
- return super.insertAt(token, i);
108
- }
109
-
110
- /**
111
- * 获取所有图片参数节点
112
- * @returns {ImageParameterToken[]}
113
- */
114
- getAllArgs() {
115
- return this.childNodes.slice(1);
116
- }
117
-
118
- /**
119
- * 获取图片框架属性参数节点
120
- * @complexity `n`
121
- */
122
- getFrameArgs() {
123
- const args = this.getAllArgs()
124
- .filter(({name}) => ['manualthumb', 'frameless', 'framed', 'thumbnail'].includes(name));
125
- if (args.length > 1) {
126
- Parser.error(`图片 ${this.name} 带有 ${args.length} 个框架参数,只有第 1 个 ${args[0].name} 会生效!`);
127
- }
128
- return args;
129
- }
130
-
131
- /**
132
- * 获取指定图片参数
133
- * @param {string} key 参数名
134
- * @param {boolean} copy 是否返回备份
135
- * @complexity `n`
136
- */
137
- getArgs(key, copy = true) {
138
- if (typeof key !== 'string') {
139
- this.typeError('getArgs', 'String');
140
- }
141
- copy ||= !Parser.debugging && externalUse('getArgs');
142
- let args = this.#args[key];
143
- if (!args) {
144
- args = new Set(this.getAllArgs().filter(({name}) => key === name));
145
- this.#args[key] = args;
146
- }
147
- return copy ? new Set(args) : args;
148
- }
149
-
150
- /**
151
- * 是否具有指定图片参数
152
- * @param {string} key 参数名
153
- * @complexity `n`
154
- */
155
- hasArg(key) {
156
- return this.getArgs(key, false).size > 0;
157
- }
158
-
159
- /**
160
- * 获取生效的指定图片参数
161
- * @param {string} key 参数名
162
- * @complexity `n`
163
- */
164
- getArg(key) {
165
- return [...this.getArgs(key, false)].sort((a, b) => a.compareDocumentPosition(b)).at(-1);
166
- }
167
-
168
- /**
169
- * 移除指定图片参数
170
- * @param {string} key 参数名
171
- * @complexity `n`
172
- */
173
- removeArg(key) {
174
- for (const token of this.getArgs(key, false)) {
175
- this.removeChild(token);
176
- }
177
- }
178
-
179
- /**
180
- * 获取图片参数名
181
- * @complexity `n`
182
- */
183
- getKeys() {
184
- const args = this.getAllArgs();
185
- if (this.#keys.size === 0 && args.length > 0) {
186
- for (const {name} of args) {
187
- this.#keys.add(name);
188
- }
189
- }
190
- return [...this.#keys];
191
- }
192
-
193
- /**
194
- * 获取指定的图片参数值
195
- * @param {string} key 参数名
196
- * @complexity `n`
197
- */
198
- getValues(key) {
199
- return [...this.getArgs(key, false)].map(token => token.getValue());
200
- }
201
-
202
- /**
203
- * 获取生效的指定图片参数值
204
- * @template {string|undefined} T
205
- * @param {T} key 参数名
206
- * @returns {T extends undefined ? Object<string, string> : string|true}
207
- * @complexity `n`
208
- */
209
- getValue(key) {
210
- return key === undefined
211
- ? Object.fromEntries(this.getKeys().map(k => [k, this.getValue(k)]))
212
- : this.getArg(key)?.getValue();
213
- }
214
-
215
- /**
216
- * 设置图片参数
217
- * @param {string} key 参数名
218
- * @param {string|boolean} value 参数值
219
- * @complexity `n`
220
- * @throws `RangeError` 未定义的图片参数
221
- * @throws `SyntaxError` 非法的参数
222
- */
223
- setValue(key, value) {
224
- if (typeof key !== 'string') {
225
- this.typeError('setValue', 'String');
226
- } else if (value === false) {
227
- this.removeArg(key);
228
- return;
229
- }
230
- const token = this.getArg(key);
231
- value = value === true ? value : String(value);
232
- if (token) {
233
- token.setValue(value);
234
- return;
235
- }
236
- let syntax = '';
237
- const config = this.getAttribute('config');
238
- if (key !== 'caption') {
239
- syntax = Object.entries(config.img).find(([, name]) => name === key)?.[0];
240
- if (!syntax) {
241
- throw new RangeError(`未定义的图片参数: ${key}`);
242
- }
243
- }
244
- if (value === true) {
245
- if (syntax.includes('$1')) {
246
- this.typeError('setValue', 'Boolean');
247
- }
248
- const newArg = Parser.run(() => new ImageParameterToken(syntax, config));
249
- this.appendChild(newArg);
250
- return;
251
- }
252
- const wikitext = `[[File:F|${syntax ? syntax.replace('$1', value) : value}]]`,
253
- root = Parser.parse(wikitext, this.getAttribute('include'), 6, config),
254
- {childNodes: {length}, firstElementChild} = root;
255
- if (length !== 1 || !firstElementChild?.matches('file#File\\:F')
256
- || firstElementChild.childNodes.length !== 2 || firstElementChild.lastElementChild.name !== key
257
- ) {
258
- throw new SyntaxError(`非法的 ${key} 参数:${noWrap(value)}`);
259
- }
260
- this.appendChild(firstElementChild.lastChild);
261
- }
262
- }
263
-
264
- Parser.classes.FileToken = __filename;
265
- module.exports = FileToken;
@@ -1,61 +0,0 @@
1
- 'use strict';
2
-
3
- const Title = require('../../lib/title'),
4
- Parser = require('../..'),
5
- Token = require('..'),
6
- FileToken = require('./file');
7
-
8
- /**
9
- * 图片
10
- * @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
11
- */
12
- class GalleryImageToken extends FileToken {
13
- type = 'gallery-image';
14
-
15
- size = undefined;
16
- width = undefined;
17
- height = undefined;
18
-
19
- /**
20
- * @param {string} link 图片文件名
21
- * @param {string|undefined} text 图片参数
22
- * @param {Title} title 图片文件标题对象
23
- * @param {accum} accum
24
- */
25
- constructor(link, text, title, config = Parser.getConfig(), accum = []) {
26
- let token;
27
- if (text !== undefined) {
28
- token = new Token(text, config, true, accum);
29
- token.type = 'temp';
30
- for (let n = 1; n < Parser.MAX_STAGE; n++) {
31
- token.getAttribute('parseOnce')();
32
- }
33
- accum.splice(accum.indexOf(token), 1);
34
- }
35
- const newConfig = structuredClone(config);
36
- newConfig.img = Object.fromEntries(Object.entries(config.img).filter(([, param]) => param !== 'width'));
37
- super(link, token?.toString(), title, newConfig, accum);
38
- this.seal(['size', 'width', 'height'], true);
39
- }
40
-
41
- /** @override */
42
- getPadding() {
43
- return 0;
44
- }
45
-
46
- /**
47
- * @override
48
- * @param {string} selector
49
- */
50
- toString(selector) {
51
- return super.toString(selector).replaceAll('\n', ' ');
52
- }
53
-
54
- /** @override */
55
- text() {
56
- return super.text().replaceAll('\n', ' ');
57
- }
58
- }
59
-
60
- Parser.classes.GalleryImageToken = __filename;
61
- module.exports = GalleryImageToken;
package/src/link/index.js DELETED
@@ -1,322 +0,0 @@
1
- 'use strict';
2
-
3
- const Title = require('../../lib/title'),
4
- {noWrap} = require('../../util/string'),
5
- {undo} = require('../../util/debug'),
6
- Parser = require('../..'),
7
- AstText = require('../../lib/text'),
8
- Token = require('..');
9
-
10
- /**
11
- * 内链
12
- * @classdesc `{childNodes: [AtomToken, ?Token]}`
13
- */
14
- class LinkToken extends Token {
15
- type = 'link';
16
-
17
- /** 完整链接,和FileToken保持一致 */
18
- get link() {
19
- return String(this.#getTitle());
20
- }
21
-
22
- set link(link) {
23
- this.setTarget(link);
24
- }
25
-
26
- /** 是否链接到自身 */
27
- get selfLink() {
28
- return !this.#getTitle().title;
29
- }
30
-
31
- set selfLink(selfLink) {
32
- if (selfLink === true) {
33
- this.asSelfLink();
34
- }
35
- }
36
-
37
- /** fragment */
38
- get fragment() {
39
- return this.#getTitle().fragment;
40
- }
41
-
42
- set fragment(fragment) {
43
- this.setFragment(fragment);
44
- }
45
-
46
- /** interwiki */
47
- get interwiki() {
48
- return this.#getTitle().interwiki;
49
- }
50
-
51
- set interwiki(interwiki) {
52
- if (typeof interwiki !== 'string') {
53
- this.typeError('set interwiki', 'String');
54
- }
55
- const {prefix, main, fragment} = this.#getTitle(),
56
- link = `${interwiki}:${prefix}${main}${fragment && '#'}${fragment}`;
57
- if (interwiki && !this.isInterwiki(link)) {
58
- throw new RangeError(`${interwiki} 不是合法的跨维基前缀!`);
59
- }
60
- this.setTarget(link);
61
- }
62
-
63
- /** 链接显示文字 */
64
- get innerText() {
65
- if (this.type !== 'link') {
66
- return undefined;
67
- }
68
- return this.childNodes.length > 1
69
- ? this.lastElementChild.text()
70
- : this.firstElementChild.text().replace(/^\s*:/u, '');
71
- }
72
-
73
- /**
74
- * @param {string} link 链接标题
75
- * @param {string|undefined} linkText 链接显示文字
76
- * @param {Title} title 链接标题对象
77
- * @param {accum} accum
78
- */
79
- constructor(link, linkText, title, config = Parser.getConfig(), accum = []) {
80
- super(undefined, config, true, accum, {AtomToken: 0, Token: 1});
81
- const AtomToken = require('../atom');
82
- this.appendChild(new AtomToken(link, 'link-target', config, accum, {
83
- 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '',
84
- }));
85
- if (linkText !== undefined) {
86
- const inner = new Token(linkText, config, true, accum, {'Stage-5': ':', ConverterToken: ':'});
87
- inner.type = 'link-text';
88
- this.appendChild(inner.setAttribute('stage', Parser.MAX_STAGE - 1));
89
- }
90
- this.setAttribute('name', title.title).getAttribute('protectChildren')(0);
91
- }
92
-
93
- /** 生成Title对象 */
94
- #getTitle() {
95
- return this.normalizeTitle(this.firstElementChild.text());
96
- }
97
-
98
- /** @override */
99
- cloneNode() {
100
- const [link, ...linkText] = this.cloneChildNodes();
101
- return Parser.run(() => {
102
- /** @type {this & {constructor: typeof LinkToken}} */
103
- const {constructor} = this,
104
- token = new constructor('', undefined, this.#getTitle(), this.getAttribute('config'));
105
- token.firstElementChild.safeReplaceWith(link);
106
- token.append(...linkText);
107
- return token.afterBuild();
108
- });
109
- }
110
-
111
- /**
112
- * @override
113
- * @throws `Error` 非法的内链目标
114
- * @throws `Error` 不可更改命名空间
115
- */
116
- afterBuild() {
117
- const /** @type {AstListener} */ linkListener = (e, data) => {
118
- const {prevTarget} = e;
119
- if (prevTarget?.type === 'link-target') {
120
- const name = prevTarget.text(),
121
- {title, interwiki, ns, valid} = this.normalizeTitle(name);
122
- if (!valid) {
123
- undo(e, data);
124
- throw new Error(`非法的内链目标:${name}`);
125
- } else if (this.type === 'category' && (interwiki || ns !== 14)
126
- || this.type === 'file' && (interwiki || ns !== 6)
127
- ) {
128
- undo(e, data);
129
- throw new Error(`${this.type === 'file' ? '文件' : '分类'}链接不可更改命名空间:${name}`);
130
- } else if (this.type === 'link' && !interwiki && (ns === 6 || ns === 14) && name.trim()[0] !== ':') {
131
- const /** @type {{firstChild: AstText}} */ {firstChild} = prevTarget;
132
- if (firstChild.type === 'text') {
133
- firstChild.insertData(0, ':');
134
- } else {
135
- prevTarget.prepend(':');
136
- }
137
- }
138
- this.setAttribute('name', title);
139
- }
140
- };
141
- this.addEventListener(['remove', 'insert', 'replace', 'text'], linkListener);
142
- return this;
143
- }
144
-
145
- /**
146
- * @override
147
- * @param {string} selector
148
- */
149
- toString(selector) {
150
- const str = super.toString(selector, '|');
151
- return this.type === 'gallery-image' || selector && this.matches(selector) ? str : `[[${str}]]`;
152
- }
153
-
154
- /** @override */
155
- getPadding() {
156
- return 2;
157
- }
158
-
159
- /** @override */
160
- getGaps() {
161
- return 1;
162
- }
163
-
164
- /** @override */
165
- text() {
166
- const str = super.text('|');
167
- return this.type === 'gallery-image' ? str : `[[${str}]]`;
168
- }
169
-
170
- /**
171
- * 设置链接目标
172
- * @param {string} link 链接目标
173
- * @throws `SyntaxError` 非法的链接目标
174
- */
175
- setTarget(link) {
176
- link = String(link);
177
- if (this.type === 'link' && !/^\s*[:#]/u.test(link)) {
178
- link = `:${link}`;
179
- }
180
- const root = Parser.parse(`[[${link}]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
181
- {childNodes: {length}, firstElementChild} = root;
182
- if (length !== 1 || firstElementChild?.type !== this.type || firstElementChild.childNodes.length !== 1) {
183
- const msgs = {link: '内链', file: '文件链接', category: '分类', 'gallery-image': '文件链接'};
184
- throw new SyntaxError(`非法的${msgs[this.type]}目标:${link}`);
185
- }
186
- const {firstChild} = firstElementChild;
187
- firstElementChild.destroy(true);
188
- this.firstElementChild.safeReplaceWith(firstChild);
189
- }
190
-
191
- /**
192
- * 设置跨语言链接
193
- * @param {string} lang 语言前缀
194
- * @param {string} link 页面标题
195
- * @throws `SyntaxError` 非法的跨语言链接
196
- */
197
- setLangLink(lang, link) {
198
- if (typeof lang !== 'string') {
199
- this.typeError('setLangLink', 'String');
200
- }
201
- link = String(link).trim();
202
- const [char] = link;
203
- if (char === '#') {
204
- throw new SyntaxError(`跨语言链接不能仅为fragment!`);
205
- } else if (char === ':') {
206
- link = link.slice(1);
207
- }
208
- const root = Parser.parse(`[[${lang}:${link}]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
209
- /** @type {Token & {firstElementChild: LinkToken}} */ {childNodes: {length}, firstElementChild} = root;
210
- if (length !== 1 || firstElementChild?.type !== 'link' || firstElementChild.childNodes.length !== 1
211
- || firstElementChild.interwiki !== lang.toLowerCase()
212
- ) {
213
- throw new SyntaxError(`非法的跨语言链接目标:${lang}:${link}`);
214
- }
215
- const {firstChild} = firstElementChild;
216
- firstElementChild.destroy(true);
217
- this.firstElementChild.safeReplaceWith(firstChild);
218
- }
219
-
220
- /**
221
- * 设置fragment
222
- * @param {string} fragment fragment
223
- * @param {boolean} page 是否是其他页面
224
- * @throws `SyntaxError` 非法的fragment
225
- */
226
- #setFragment(fragment, page = true) {
227
- fragment = String(fragment).replaceAll(/[<>[\]#|=]/gu, p => encodeURIComponent(p));
228
- const include = this.getAttribute('include'),
229
- config = this.getAttribute('config'),
230
- root = Parser.parse(`[[${page ? `:${this.name}` : ''}#${fragment}]]`, include, 6, config),
231
- {childNodes: {length}, firstElementChild} = root;
232
- if (length !== 1 || firstElementChild?.type !== 'link' || firstElementChild.childNodes.length !== 1) {
233
- throw new SyntaxError(`非法的 fragment:${fragment}`);
234
- }
235
- if (page) {
236
- Parser.warn(`${this.constructor.name}.setFragment 方法会同时规范化页面名!`);
237
- }
238
- const {firstChild} = firstElementChild;
239
- firstElementChild.destroy(true);
240
- this.firstElementChild.safeReplaceWith(firstChild);
241
- }
242
-
243
- /**
244
- * 设置fragment
245
- * @param {string} fragment fragment
246
- */
247
- setFragment(fragment) {
248
- this.#setFragment(fragment);
249
- }
250
-
251
- /**
252
- * 修改为到自身的链接
253
- * @param {string} fragment fragment
254
- * @throws `RangeError` 空fragment
255
- */
256
- asSelfLink(fragment = this.fragment) {
257
- fragment = String(fragment);
258
- if (!fragment.trim()) {
259
- throw new RangeError(`${this.constructor.name}.asSelfLink 方法必须指定非空的 fragment!`);
260
- }
261
- this.#setFragment(fragment, false);
262
- }
263
-
264
- /**
265
- * 设置链接显示文字
266
- * @param {string} linkText 链接显示文字
267
- * @throws `SyntaxError` 非法的链接显示文字
268
- */
269
- setLinkText(linkText = '') {
270
- linkText = String(linkText);
271
- let lastElementChild;
272
- const config = this.getAttribute('config');
273
- if (linkText) {
274
- const root = Parser.parse(`[[${
275
- this.type === 'category' ? 'Category:' : ''
276
- }L|${linkText}]]`, this.getAttribute('include'), 6, config),
277
- {childNodes: {length}, firstElementChild} = root;
278
- if (length !== 1 || firstElementChild?.type !== this.type || firstElementChild.childNodes.length !== 2) {
279
- throw new SyntaxError(`非法的${this.type === 'link' ? '内链文字' : '分类关键字'}:${noWrap(linkText)}`);
280
- }
281
- ({lastElementChild} = firstElementChild);
282
- } else {
283
- lastElementChild = Parser.run(() => new Token('', config));
284
- lastElementChild.setAttribute('stage', 7).type = 'link-text';
285
- }
286
- if (this.childNodes.length === 1) {
287
- this.appendChild(lastElementChild);
288
- } else {
289
- this.lastElementChild.safeReplaceWith(lastElementChild);
290
- }
291
- }
292
-
293
- /**
294
- * 自动生成管道符后的链接文字
295
- * @throws `Error` 带有"#"或"%"时不可用
296
- */
297
- pipeTrick() {
298
- const linkText = this.firstElementChild.text();
299
- if (linkText.includes('#') || linkText.includes('%')) {
300
- throw new Error('Pipe trick 不能用于带有"#"或"%"的场合!');
301
- }
302
- const m1 = /^:?(?:[ \w\x80-\xFF-]+:)?([^(]+)\(.+\)$/u.exec(linkText);
303
- if (m1) {
304
- this.setLinkText(m1[1].trim());
305
- return;
306
- }
307
- const m2 = /^:?(?:[ \w\x80-\xFF-]+:)?([^(]+)(.+)$/u.exec(linkText);
308
- if (m2) {
309
- this.setLinkText(m2[1].trim());
310
- return;
311
- }
312
- const m3 = /^:?(?:[ \w\x80-\xFF-]+:)?(.+?)(?:(?<!\()\(.+\))?(?:, |,|، )./u.exec(linkText);
313
- if (m3) {
314
- this.setLinkText(m3[1].trim());
315
- return;
316
- }
317
- this.setLinkText(linkText);
318
- }
319
- }
320
-
321
- Parser.classes.LinkToken = __filename;
322
- module.exports = LinkToken;