wikiparser-node 0.7.0-b → 0.7.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.
Files changed (84) hide show
  1. package/README.md +39 -0
  2. package/config/default.json +832 -0
  3. package/config/llwiki.json +630 -0
  4. package/config/moegirl.json +728 -0
  5. package/config/zhwiki.json +1269 -0
  6. package/index.js +321 -0
  7. package/lib/element.js +611 -0
  8. package/lib/node.js +772 -0
  9. package/lib/ranges.js +130 -0
  10. package/lib/text.js +215 -0
  11. package/lib/title.js +80 -0
  12. package/mixin/attributeParent.js +117 -0
  13. package/mixin/fixedToken.js +40 -0
  14. package/mixin/hidden.js +21 -0
  15. package/mixin/singleLine.js +31 -0
  16. package/mixin/sol.js +65 -0
  17. package/package.json +11 -9
  18. package/parser/brackets.js +120 -0
  19. package/parser/commentAndExt.js +62 -0
  20. package/parser/converter.js +46 -0
  21. package/parser/externalLinks.js +33 -0
  22. package/parser/hrAndDoubleUnderscore.js +38 -0
  23. package/parser/html.js +42 -0
  24. package/parser/links.js +94 -0
  25. package/parser/list.js +59 -0
  26. package/parser/magicLinks.js +41 -0
  27. package/parser/quotes.js +64 -0
  28. package/parser/selector.js +177 -0
  29. package/parser/table.js +114 -0
  30. package/src/arg.js +203 -0
  31. package/src/atom/hidden.js +13 -0
  32. package/src/atom/index.js +43 -0
  33. package/src/attribute.js +420 -0
  34. package/src/attributes.js +452 -0
  35. package/src/charinsert.js +97 -0
  36. package/src/converter.js +176 -0
  37. package/src/converterFlags.js +284 -0
  38. package/src/converterRule.js +258 -0
  39. package/src/extLink.js +179 -0
  40. package/src/gallery.js +151 -0
  41. package/src/hasNowiki/index.js +44 -0
  42. package/src/hasNowiki/pre.js +40 -0
  43. package/src/heading.js +134 -0
  44. package/src/html.js +248 -0
  45. package/src/imageParameter.js +277 -0
  46. package/src/imagemap.js +199 -0
  47. package/src/imagemapLink.js +41 -0
  48. package/src/index.js +913 -0
  49. package/src/link/category.js +49 -0
  50. package/src/link/file.js +282 -0
  51. package/src/link/galleryImage.js +120 -0
  52. package/src/link/index.js +383 -0
  53. package/src/magicLink.js +149 -0
  54. package/src/nested/choose.js +24 -0
  55. package/src/nested/combobox.js +23 -0
  56. package/src/nested/index.js +96 -0
  57. package/src/nested/references.js +23 -0
  58. package/src/nowiki/comment.js +71 -0
  59. package/src/nowiki/dd.js +59 -0
  60. package/src/nowiki/doubleUnderscore.js +56 -0
  61. package/src/nowiki/hr.js +41 -0
  62. package/src/nowiki/index.js +56 -0
  63. package/src/nowiki/list.js +16 -0
  64. package/src/nowiki/noinclude.js +28 -0
  65. package/src/nowiki/quote.js +69 -0
  66. package/src/onlyinclude.js +64 -0
  67. package/src/paramTag/index.js +89 -0
  68. package/src/paramTag/inputbox.js +44 -0
  69. package/src/parameter.js +239 -0
  70. package/src/syntax.js +91 -0
  71. package/src/table/index.js +984 -0
  72. package/src/table/td.js +339 -0
  73. package/src/table/tr.js +319 -0
  74. package/src/tagPair/ext.js +138 -0
  75. package/src/tagPair/include.js +60 -0
  76. package/src/tagPair/index.js +126 -0
  77. package/src/transclude.js +824 -0
  78. package/tool/index.js +1202 -0
  79. package/util/base.js +17 -0
  80. package/util/debug.js +73 -0
  81. package/util/diff.js +76 -0
  82. package/util/lint.js +54 -0
  83. package/util/string.js +107 -0
  84. package/bundle/bundle.min.js +0 -40
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ const Title = require('../../lib/title'),
4
+ Parser = require('../..'),
5
+ LinkToken = require('.');
6
+
7
+ /**
8
+ * 分类
9
+ * @classdesc `{childNodes: [AtomToken, ?Token]}`
10
+ */
11
+ class CategoryToken extends LinkToken {
12
+ type = 'category';
13
+
14
+ /** 分类排序关键字 */
15
+ get sortkey() {
16
+ return this.childNodes[1]?.text()?.replace(
17
+ /&#(\d+|x[\da-f]+);|\n/gu,
18
+ /** @param {string} p */
19
+ (_, p) => p ? String.fromCodePoint(p[0] === 'x' ? parseInt(p.slice(1), 16) : Number(p)) : '',
20
+ );
21
+ }
22
+
23
+ set sortkey(text) {
24
+ this.setSortkey(text);
25
+ }
26
+
27
+ /**
28
+ * @param {string} link 分类名
29
+ * @param {string|undefined} text 排序关键字
30
+ * @param {Title} title 分类页面标题对象
31
+ * @param {accum} accum
32
+ * @param {string} delimiter `|`
33
+ */
34
+ constructor(link, text, title, config = Parser.getConfig(), accum = [], delimiter = '|') {
35
+ super(link, text, title, config, accum, delimiter);
36
+ this.seal(['selfLink', 'interwiki', 'setLangLink', 'setFragment', 'asSelfLink', 'pipeTrick'], true);
37
+ }
38
+
39
+ /**
40
+ * 设置排序关键字
41
+ * @param {string} text 排序关键字
42
+ */
43
+ setSortkey(text) {
44
+ this.setLinkText(text);
45
+ }
46
+ }
47
+
48
+ Parser.classes.CategoryToken = __filename;
49
+ module.exports = CategoryToken;
@@ -0,0 +1,282 @@
1
+ 'use strict';
2
+
3
+ const {explode, noWrap} = require('../../util/string'),
4
+ {generateForChild} = require('../../util/lint'),
5
+ Parser = require('../..'),
6
+ Title = require('../../lib/title'),
7
+ LinkToken = require('.'),
8
+ ImageParameterToken = require('../imageParameter');
9
+
10
+ const frame = new Set(['manualthumb', 'frameless', 'framed', 'thumbnail']),
11
+ horizAlign = new Set(['left', 'right', 'center', 'none']),
12
+ vertAlign = new Set(['baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom']);
13
+
14
+ /**
15
+ * 图片
16
+ * @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
17
+ */
18
+ class FileToken extends LinkToken {
19
+ type = 'file';
20
+
21
+ /** 图片链接 */
22
+ get link() {
23
+ return this.getArg('link')?.link;
24
+ }
25
+
26
+ set link(value) {
27
+ this.setValue('link', value);
28
+ }
29
+
30
+ /** 图片大小 */
31
+ get size() {
32
+ return this.getArg('width')?.size;
33
+ }
34
+
35
+ /** 图片宽度 */
36
+ get width() {
37
+ return this.size?.width;
38
+ }
39
+
40
+ set width(width) {
41
+ const arg = this.getArg('width');
42
+ if (arg) {
43
+ arg.width = width;
44
+ } else {
45
+ this.setValue('width', width);
46
+ }
47
+ }
48
+
49
+ /** 图片高度 */
50
+ get height() {
51
+ return this.size?.height;
52
+ }
53
+
54
+ set height(height) {
55
+ const arg = this.getArg('width');
56
+ if (arg) {
57
+ arg.height = height;
58
+ } else {
59
+ this.setValue('width', `x${height}`);
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @param {string} link 文件名
65
+ * @param {string|undefined} text 图片参数
66
+ * @param {Title} title 文件标题对象
67
+ * @param {accum} accum
68
+ * @param {string} delimiter `|`
69
+ * @complexity `n`
70
+ */
71
+ constructor(link, text, title, config = Parser.getConfig(), accum = [], delimiter = '|') {
72
+ super(link, undefined, title, config, accum, delimiter);
73
+ this.setAttribute('acceptable', {AtomToken: 0, ImageParameterToken: '1:'});
74
+ this.append(...explode('-{', '}-', '|', text).map(part => new ImageParameterToken(part, config, accum)));
75
+ this.seal(
76
+ ['selfLink', 'interwiki', 'setLangLink', 'setFragment', 'asSelfLink', 'setLinkText', 'pipeTrick'],
77
+ true,
78
+ );
79
+ }
80
+
81
+ /**
82
+ * @override
83
+ * @param {number} start 起始位置
84
+ */
85
+ lint(start = 0) {
86
+ const errors = super.lint(start),
87
+ args = this.getAllArgs(),
88
+ keys = [...new Set(args.map(({name}) => name))],
89
+ frameKeys = keys.filter(key => frame.has(key)),
90
+ horizAlignKeys = keys.filter(key => horizAlign.has(key)),
91
+ vertAlignKeys = keys.filter(key => vertAlign.has(key));
92
+ if (args.length === keys.length
93
+ && frameKeys.length < 2 && horizAlignKeys.length < 2 && vertAlignKeys.length < 2
94
+ ) {
95
+ return errors;
96
+ }
97
+ const rect = {start, ...this.getRootNode().posFromIndex(start)};
98
+ for (const key of keys) {
99
+ let relevantArgs = args.filter(({name}) => name === key);
100
+ if (key === 'caption') {
101
+ relevantArgs = [
102
+ ...relevantArgs.slice(0, -1).filter(arg => arg.text()),
103
+ relevantArgs.at(-1),
104
+ ];
105
+ }
106
+ if (relevantArgs.length > 1) {
107
+ errors.push(...relevantArgs.map(arg => generateForChild(arg, rect, `重复的图片${key}参数`)));
108
+ }
109
+ }
110
+ if (frameKeys.size > 1) {
111
+ errors.push(
112
+ ...args.filter(({name}) => frame.has(name)).map(arg => generateForChild(arg, rect, '冲突的图片框架参数')),
113
+ );
114
+ }
115
+ if (horizAlignKeys.size > 1) {
116
+ errors.push(
117
+ ...args.filter(({name}) => horizAlign.has(name))
118
+ .map(arg => generateForChild(arg, rect, '冲突的图片水平对齐参数')),
119
+ );
120
+ }
121
+ if (vertAlignKeys.size > 1) {
122
+ errors.push(
123
+ ...args.filter(({name}) => vertAlign.has(name))
124
+ .map(arg => generateForChild(arg, rect, '冲突的图片垂直对齐参数')),
125
+ );
126
+ }
127
+ return errors;
128
+ }
129
+
130
+ /**
131
+ * 获取所有图片参数节点
132
+ * @returns {ImageParameterToken[]}
133
+ */
134
+ getAllArgs() {
135
+ return this.childNodes.slice(1);
136
+ }
137
+
138
+ /**
139
+ * 获取指定图片参数
140
+ * @param {string} key 参数名
141
+ * @complexity `n`
142
+ */
143
+ getArgs(key) {
144
+ return typeof key === 'string'
145
+ ? this.getAllArgs().filter(({name}) => key === name)
146
+ : this.typeError('getArgs', 'String');
147
+ }
148
+
149
+ /**
150
+ * 获取特定类型的图片属性参数节点
151
+ * @param {Set<string>} keys 接受的参数名
152
+ * @param {type} type 类型名
153
+ * @complexity `n`
154
+ */
155
+ #getTypedArgs(keys, type) {
156
+ const args = this.getAllArgs().filter(({name}) => keys.has(name));
157
+ if (args.length > 1) {
158
+ Parser.warn(`图片 ${this.name} 带有 ${args.length} 个${type}参数,只有最后 1 个 ${args[0].name} 会生效!`);
159
+ }
160
+ return args;
161
+ }
162
+
163
+ /** 获取图片框架属性参数节点 */
164
+ getFrameArgs() {
165
+ return this.#getTypedArgs(frame, '框架');
166
+ }
167
+
168
+ /** 获取图片水平对齐参数节点 */
169
+ getHorizAlignArgs() {
170
+ return this.#getTypedArgs(horizAlign, '水平对齐');
171
+ }
172
+
173
+ /** 获取图片垂直对齐参数节点 */
174
+ getVertAlignArgs() {
175
+ return this.#getTypedArgs(vertAlign, '垂直对齐');
176
+ }
177
+
178
+ /**
179
+ * 获取生效的指定图片参数
180
+ * @param {string} key 参数名
181
+ * @complexity `n`
182
+ */
183
+ getArg(key) {
184
+ return this.getArgs(key).at(-1);
185
+ }
186
+
187
+ /**
188
+ * 是否具有指定图片参数
189
+ * @param {string} key 参数名
190
+ * @complexity `n`
191
+ */
192
+ hasArg(key) {
193
+ return this.getArgs(key).length > 0;
194
+ }
195
+
196
+ /**
197
+ * 移除指定图片参数
198
+ * @param {string} key 参数名
199
+ * @complexity `n`
200
+ */
201
+ removeArg(key) {
202
+ for (const token of this.getArgs(key)) {
203
+ this.removeChild(token);
204
+ }
205
+ }
206
+
207
+ /**
208
+ * 获取图片参数名
209
+ * @complexity `n`
210
+ */
211
+ getKeys() {
212
+ return this.getAllArgs().map(({name}) => name);
213
+ }
214
+
215
+ /**
216
+ * 获取指定的图片参数值
217
+ * @param {string} key 参数名
218
+ * @complexity `n`
219
+ */
220
+ getValues(key) {
221
+ return this.getArgs(key).map(token => token.getValue());
222
+ }
223
+
224
+ /**
225
+ * 获取生效的指定图片参数值
226
+ * @param {string} key 参数名
227
+ * @complexity `n`
228
+ */
229
+ getValue(key) {
230
+ return this.getArg(key)?.getValue();
231
+ }
232
+
233
+ /**
234
+ * 设置图片参数
235
+ * @param {string} key 参数名
236
+ * @param {string|boolean} value 参数值
237
+ * @complexity `n`
238
+ * @throws `RangeError` 未定义的图片参数
239
+ * @throws `SyntaxError` 非法的参数
240
+ */
241
+ setValue(key, value) {
242
+ if (typeof key !== 'string') {
243
+ this.typeError('setValue', 'String');
244
+ } else if (value === false) {
245
+ this.removeArg(key);
246
+ return;
247
+ }
248
+ const token = this.getArg(key);
249
+ value = value === true ? value : String(value);
250
+ if (token) {
251
+ token.setValue(value);
252
+ return;
253
+ }
254
+ let syntax = '';
255
+ const config = this.getAttribute('config');
256
+ if (key !== 'caption') {
257
+ syntax = Object.entries(config.img).find(([, name]) => name === key)?.[0];
258
+ if (!syntax) {
259
+ throw new RangeError(`未定义的图片参数: ${key}`);
260
+ }
261
+ }
262
+ if (value === true) {
263
+ if (syntax.includes('$1')) {
264
+ this.typeError('setValue', 'Boolean');
265
+ }
266
+ const newArg = Parser.run(() => new ImageParameterToken(syntax, config));
267
+ this.insertAt(newArg);
268
+ return;
269
+ }
270
+ const wikitext = `[[File:F|${syntax ? syntax.replace('$1', value) : value}]]`,
271
+ root = Parser.parse(wikitext, this.getAttribute('include'), 6, config),
272
+ {length, firstChild: file} = root,
273
+ {name, type, length: fileLength, lastChild: imageParameter} = file;
274
+ if (length !== 1 || type !== 'file' || name !== 'File:F' || fileLength !== 2 || imageParameter.name !== key) {
275
+ throw new SyntaxError(`非法的 ${key} 参数:${noWrap(value)}`);
276
+ }
277
+ this.insertAt(imageParameter);
278
+ }
279
+ }
280
+
281
+ Parser.classes.FileToken = __filename;
282
+ module.exports = FileToken;
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ const {generateForSelf} = require('../../util/lint'),
4
+ {undo} = require('../../util/debug'),
5
+ singleLine = require('../../mixin/singleLine'),
6
+ Title = require('../../lib/title'),
7
+ Parser = require('../..'),
8
+ Token = require('..'),
9
+ FileToken = require('./file');
10
+
11
+ /**
12
+ * 图片
13
+ * @classdesc `{childNodes: [AtomToken, ...ImageParameterToken]}`
14
+ */
15
+ class GalleryImageToken extends singleLine(FileToken) {
16
+ type = 'gallery-image';
17
+ #invalid = false;
18
+
19
+ /** 图片链接 */
20
+ get link() {
21
+ return this.type === 'imagemap-image' ? undefined : super.link;
22
+ }
23
+
24
+ set link(value) {
25
+ super.link = value;
26
+ }
27
+
28
+ /**
29
+ * @param {string} link 图片文件名
30
+ * @param {string|undefined} text 图片参数
31
+ * @param {Title} title 图片文件标题对象
32
+ * @param {accum} accum
33
+ */
34
+ constructor(link, text, title, config = Parser.getConfig(), accum = []) {
35
+ let token;
36
+ if (text !== undefined) {
37
+ token = new Token(text, config, true, accum);
38
+ token.type = 'temp';
39
+ for (let n = 1; n < Parser.MAX_STAGE; n++) {
40
+ token.getAttribute('parseOnce')();
41
+ }
42
+ accum.splice(accum.indexOf(token), 1);
43
+ }
44
+ super(link, token?.toString(), title, config, accum);
45
+ this.setAttribute('bracket', false);
46
+ if (!Object.values(config.img).includes('width')) {
47
+ this.seal(['size', 'width', 'height'], true);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * @override
53
+ * @throws `Error` 非法的内链目标
54
+ * @throws `Error` 不可更改命名空间
55
+ */
56
+ afterBuild() {
57
+ const initImagemap = this.type === 'imagemap-image',
58
+ 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);
79
+ }
80
+
81
+ /** @override */
82
+ getPadding() {
83
+ return 0;
84
+ }
85
+
86
+ /**
87
+ * @override
88
+ * @param {number} start 起始位置
89
+ */
90
+ lint(start = 0) {
91
+ const errors = super.lint(start);
92
+ if (this.#invalid) {
93
+ errors.push(generateForSelf(this, {start}, '无效的图库图片'));
94
+ }
95
+ return errors;
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
+ }
117
+ }
118
+
119
+ Parser.classes.GalleryImageToken = __filename;
120
+ module.exports = GalleryImageToken;