wikiparser-node 0.7.0 → 0.7.1-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 (87) hide show
  1. package/bundle/bundle.min.js +40 -0
  2. package/extensions/editor.css +60 -0
  3. package/extensions/editor.js +324 -0
  4. package/extensions/ui.css +119 -0
  5. package/package.json +12 -11
  6. package/README.md +0 -39
  7. package/config/default.json +0 -832
  8. package/config/llwiki.json +0 -630
  9. package/config/moegirl.json +0 -728
  10. package/config/zhwiki.json +0 -1269
  11. package/index.js +0 -321
  12. package/lib/element.js +0 -611
  13. package/lib/node.js +0 -772
  14. package/lib/ranges.js +0 -130
  15. package/lib/text.js +0 -215
  16. package/lib/title.js +0 -80
  17. package/mixin/attributeParent.js +0 -117
  18. package/mixin/fixedToken.js +0 -40
  19. package/mixin/hidden.js +0 -21
  20. package/mixin/singleLine.js +0 -31
  21. package/mixin/sol.js +0 -65
  22. package/parser/brackets.js +0 -120
  23. package/parser/commentAndExt.js +0 -62
  24. package/parser/converter.js +0 -46
  25. package/parser/externalLinks.js +0 -33
  26. package/parser/hrAndDoubleUnderscore.js +0 -38
  27. package/parser/html.js +0 -42
  28. package/parser/links.js +0 -94
  29. package/parser/list.js +0 -59
  30. package/parser/magicLinks.js +0 -41
  31. package/parser/quotes.js +0 -64
  32. package/parser/selector.js +0 -177
  33. package/parser/table.js +0 -114
  34. package/src/arg.js +0 -203
  35. package/src/atom/hidden.js +0 -13
  36. package/src/atom/index.js +0 -43
  37. package/src/attribute.js +0 -420
  38. package/src/attributes.js +0 -452
  39. package/src/charinsert.js +0 -97
  40. package/src/converter.js +0 -176
  41. package/src/converterFlags.js +0 -284
  42. package/src/converterRule.js +0 -258
  43. package/src/extLink.js +0 -179
  44. package/src/gallery.js +0 -151
  45. package/src/hasNowiki/index.js +0 -44
  46. package/src/hasNowiki/pre.js +0 -40
  47. package/src/heading.js +0 -134
  48. package/src/html.js +0 -248
  49. package/src/imageParameter.js +0 -277
  50. package/src/imagemap.js +0 -199
  51. package/src/imagemapLink.js +0 -41
  52. package/src/index.js +0 -913
  53. package/src/link/category.js +0 -49
  54. package/src/link/file.js +0 -282
  55. package/src/link/galleryImage.js +0 -120
  56. package/src/link/index.js +0 -383
  57. package/src/magicLink.js +0 -149
  58. package/src/nested/choose.js +0 -24
  59. package/src/nested/combobox.js +0 -23
  60. package/src/nested/index.js +0 -96
  61. package/src/nested/references.js +0 -23
  62. package/src/nowiki/comment.js +0 -71
  63. package/src/nowiki/dd.js +0 -59
  64. package/src/nowiki/doubleUnderscore.js +0 -56
  65. package/src/nowiki/hr.js +0 -41
  66. package/src/nowiki/index.js +0 -56
  67. package/src/nowiki/list.js +0 -16
  68. package/src/nowiki/noinclude.js +0 -28
  69. package/src/nowiki/quote.js +0 -69
  70. package/src/onlyinclude.js +0 -64
  71. package/src/paramTag/index.js +0 -89
  72. package/src/paramTag/inputbox.js +0 -44
  73. package/src/parameter.js +0 -239
  74. package/src/syntax.js +0 -91
  75. package/src/table/index.js +0 -984
  76. package/src/table/td.js +0 -339
  77. package/src/table/tr.js +0 -319
  78. package/src/tagPair/ext.js +0 -138
  79. package/src/tagPair/include.js +0 -60
  80. package/src/tagPair/index.js +0 -126
  81. package/src/transclude.js +0 -824
  82. package/tool/index.js +0 -1202
  83. package/util/base.js +0 -17
  84. package/util/debug.js +0 -73
  85. package/util/diff.js +0 -76
  86. package/util/lint.js +0 -54
  87. package/util/string.js +0 -107
package/src/html.js DELETED
@@ -1,248 +0,0 @@
1
- 'use strict';
2
-
3
- const {generateForSelf} = require('../util/lint'),
4
- {noWrap} = require('../util/string'),
5
- fixedToken = require('../mixin/fixedToken'),
6
- attributeParent = require('../mixin/attributeParent'),
7
- Parser = require('..'),
8
- Token = require('.');
9
-
10
- /**
11
- * HTML标签
12
- * @classdesc `{childNodes: [AttributesToken]}`
13
- */
14
- class HtmlToken extends attributeParent(fixedToken(Token)) {
15
- type = 'html';
16
- #closing;
17
- #selfClosing;
18
- #tag;
19
-
20
- /** getter */
21
- get closing() {
22
- return this.#closing;
23
- }
24
-
25
- /** @throws `Error` 自闭合标签或空标签 */
26
- set closing(value) {
27
- if (!value) {
28
- this.#closing = false;
29
- return;
30
- } else if (this.#selfClosing) {
31
- throw new Error('这是一个自闭合标签!');
32
- }
33
- const {html: [,, tags]} = this.getAttribute('config');
34
- if (tags.includes(this.name)) {
35
- throw new Error('这是一个空标签!');
36
- }
37
- this.#closing = true;
38
- }
39
-
40
- /** getter */
41
- get selfClosing() {
42
- return this.#selfClosing;
43
- }
44
-
45
- /** @throws `Error` 闭合标签或无效自闭合标签 */
46
- set selfClosing(value) {
47
- if (!value) {
48
- this.#selfClosing = false;
49
- return;
50
- } else if (this.#closing) {
51
- throw new Error('这是一个闭合标签!');
52
- }
53
- const {html: [tags]} = this.getAttribute('config');
54
- if (tags.includes(this.name)) {
55
- throw new Error(`<${this.name}>标签自闭合无效!`);
56
- }
57
- this.#selfClosing = true;
58
- }
59
-
60
- /**
61
- * @param {string} name 标签名
62
- * @param {AttributesToken} attr 标签属性
63
- * @param {boolean} closing 是否闭合
64
- * @param {boolean} selfClosing 是否自封闭
65
- * @param {accum} accum
66
- */
67
- constructor(name, attr, closing, selfClosing, config = Parser.getConfig(), accum = []) {
68
- super(undefined, config, true, accum);
69
- this.insertAt(attr);
70
- this.setAttribute('name', name.toLowerCase());
71
- this.#closing = closing;
72
- this.#selfClosing = selfClosing;
73
- this.#tag = name;
74
- }
75
-
76
- /**
77
- * @override
78
- * @param {string} selector
79
- */
80
- toString(selector) {
81
- return selector && this.matches(selector)
82
- ? ''
83
- : `<${this.#closing ? '/' : ''}${this.#tag}${super.toString(selector)}${this.#selfClosing ? '/' : ''}>`;
84
- }
85
-
86
- /** @override */
87
- text() {
88
- return `<${this.#closing ? '/' : ''}${this.#tag}${
89
- this.#closing ? '' : super.text()
90
- }${this.#selfClosing ? '/' : ''}>`;
91
- }
92
-
93
- /** @override */
94
- getPadding() {
95
- return this.#tag.length + (this.#closing ? 2 : 1);
96
- }
97
-
98
- /** @override */
99
- print() {
100
- return super.print({
101
- pre: `&lt;${this.#closing ? '/' : ''}${this.#tag}`,
102
- post: `${this.#selfClosing ? '/' : ''}&gt;`,
103
- });
104
- }
105
-
106
- /**
107
- * @override
108
- * @param {number} start 起始位置
109
- */
110
- lint(start = 0) {
111
- const errors = super.lint(start);
112
- let wikitext, /** @type {LintError} */ refError;
113
- if (this.name === 'h1' && !this.#closing) {
114
- wikitext = String(this.getRootNode());
115
- refError = generateForSelf(this, {start}, '<h1>');
116
- errors.push({...refError, excerpt: wikitext.slice(start, start + 50)});
117
- }
118
- if (this.closest('table-attrs')) {
119
- wikitext ||= String(this.getRootNode());
120
- refError ||= generateForSelf(this, {start}, '');
121
- const excerpt = wikitext.slice(Math.max(0, start - 25), start + 25);
122
- errors.push({...refError, message: '表格属性中的HTML标签', excerpt});
123
- }
124
- try {
125
- this.findMatchingTag();
126
- } catch ({message: errorMsg}) {
127
- wikitext ||= String(this.getRootNode());
128
- refError ||= generateForSelf(this, {start}, '');
129
- const [message] = errorMsg.split(':'),
130
- error = {...refError, message, severity: message === '未闭合的标签' ? 'warning' : 'error'};
131
- if (message === '未闭合的标签') {
132
- error.excerpt = wikitext.slice(start, start + 50);
133
- } else if (message === '未匹配的闭合标签') {
134
- const end = start + String(this).length;
135
- error.excerpt = wikitext.slice(Math.max(0, end - 50), end);
136
- }
137
- errors.push(error);
138
- }
139
- return errors;
140
- }
141
-
142
- /**
143
- * 搜索匹配的标签
144
- * @complexity `n`
145
- * @throws `SyntaxError` 同时闭合和自封闭的标签
146
- * @throws `SyntaxError` 无效自封闭标签
147
- * @throws `SyntaxError` 未闭合的标签
148
- */
149
- findMatchingTag() {
150
- const {html} = this.getAttribute('config'),
151
- {name: tagName, parentNode} = this,
152
- string = noWrap(String(this));
153
- if (this.#closing && (this.#selfClosing || html[2].includes(tagName))) {
154
- throw new SyntaxError(`同时闭合和自封闭的标签:${string}`);
155
- } else if (html[2].includes(tagName) || this.#selfClosing && html[1].includes(tagName)) { // 自封闭标签
156
- return this;
157
- } else if (this.#selfClosing && html[0].includes(tagName)) {
158
- throw new SyntaxError(`无效自封闭标签:${string}`);
159
- } else if (!parentNode) {
160
- return undefined;
161
- }
162
- const {childNodes} = parentNode,
163
- i = childNodes.indexOf(this),
164
- siblings = this.#closing
165
- ? childNodes.slice(0, i).reverse().filter(({type, name}) => type === 'html' && name === tagName)
166
- : childNodes.slice(i + 1).filter(({type, name}) => type === 'html' && name === tagName);
167
- let imbalance = this.#closing ? -1 : 1;
168
- for (const token of siblings) {
169
- if (token.closing) {
170
- imbalance--;
171
- } else {
172
- imbalance++;
173
- }
174
- if (imbalance === 0) {
175
- return token;
176
- }
177
- }
178
- throw new SyntaxError(`未${this.#closing ? '匹配的闭合' : '闭合的'}标签:${string}`);
179
- }
180
-
181
- /** @override */
182
- cloneNode() {
183
- const [attr] = this.cloneChildNodes(),
184
- config = this.getAttribute('config');
185
- return Parser.run(() => new HtmlToken(this.#tag, attr, this.#closing, this.#selfClosing, config));
186
- }
187
-
188
- /**
189
- * @override
190
- * @template {string} T
191
- * @param {T} key 属性键
192
- * @returns {TokenAttribute<T>}
193
- */
194
- getAttribute(key) {
195
- return key === 'tag' ? this.#tag : super.getAttribute(key);
196
- }
197
-
198
- /**
199
- * 更换标签名
200
- * @param {string} tag 标签名
201
- * @throws `RangeError` 非法的HTML标签
202
- */
203
- replaceTag(tag) {
204
- const name = tag.toLowerCase();
205
- if (!this.getAttribute('config').html.flat().includes(name)) {
206
- throw new RangeError(`非法的HTML标签:${tag}`);
207
- }
208
- this.setAttribute('name', name).#tag = tag;
209
- }
210
-
211
- /** 局部闭合 */
212
- #localMatch() {
213
- this.#selfClosing = false;
214
- const root = Parser.parse(`</${this.name}>`, false, 3, this.getAttribute('config'));
215
- this.after(root.firstChild);
216
- }
217
-
218
- /**
219
- * 修复无效自封闭标签
220
- * @complexity `n`
221
- * @throws `Error` 无法修复无效自封闭标签
222
- */
223
- fix() {
224
- const config = this.getAttribute('config'),
225
- {parentNode, name: tagName, firstChild} = this;
226
- if (!parentNode || !this.#selfClosing || !config.html[0].includes(tagName)) {
227
- return;
228
- } else if (firstChild.text().trim()) {
229
- this.#localMatch();
230
- return;
231
- }
232
- const {childNodes} = parentNode,
233
- i = childNodes.indexOf(this),
234
- /** @type {HtmlToken[]} */
235
- prevSiblings = childNodes.slice(0, i).filter(({type, name}) => type === 'html' && name === tagName),
236
- imbalance = prevSiblings.reduce((acc, {closing}) => acc + (closing ? 1 : -1), 0);
237
- if (imbalance < 0) {
238
- this.#selfClosing = false;
239
- this.#closing = true;
240
- } else {
241
- Parser.warn('无法修复无效自封闭标签', noWrap(String(this)));
242
- throw new Error(`无法修复无效自封闭标签:前文共有 ${imbalance} 个未匹配的闭合标签`);
243
- }
244
- }
245
- }
246
-
247
- Parser.classes.HtmlToken = __filename;
248
- module.exports = HtmlToken;
@@ -1,277 +0,0 @@
1
- 'use strict';
2
-
3
- const {text, noWrap, print, extUrlChar, extUrlCharFirst} = require('../util/string'),
4
- Parser = require('..'),
5
- AstText = require('../lib/text'),
6
- Token = require('.');
7
-
8
- /**
9
- * 图片参数
10
- * @classdesc `{childNodes: ...(AstText|Token)}`
11
- */
12
- class ImageParameterToken extends Token {
13
- static noLink = Symbol('no-link'); // 这个Symbol需要公开
14
-
15
- /**
16
- * 检查图片参数是否合法
17
- * @template {string} T
18
- * @param {T} key 参数名
19
- * @param {string} value 参数值
20
- * @returns {T extends 'link' ? string|Symbol : boolean}
21
- */
22
- static #validate(key, value, config = Parser.getConfig(), halfParsed = false) {
23
- value = value.replace(/\0\d+t\x7F/gu, '').trim();
24
- switch (key) {
25
- case 'width':
26
- return /^\d*(?:x\d*)?$/u.test(value);
27
- case 'link': {
28
- if (!value) {
29
- return this.noLink;
30
- }
31
- const regex = new RegExp(`(?:(?:${config.protocol}|//)${extUrlCharFirst}|\0\\d+m\x7F)${
32
- extUrlChar
33
- }(?=\0\\d+t\x7F|$)`, 'iu');
34
- if (regex.test(value)) {
35
- return value;
36
- } else if (value.startsWith('[[') && value.endsWith(']]')) {
37
- value = value.slice(2, -2);
38
- }
39
- const title = Parser.normalizeTitle(value, 0, false, config, halfParsed, true, true);
40
- return title.valid && String(title);
41
- }
42
- case 'lang':
43
- return config.variants.includes(value);
44
- case 'alt':
45
- case 'class':
46
- case 'manualthumb':
47
- return true;
48
- default:
49
- return !isNaN(value);
50
- }
51
- }
52
-
53
- type = 'image-parameter';
54
- #syntax = '';
55
-
56
- /** getValue()的getter */
57
- get value() {
58
- return this.getValue();
59
- }
60
-
61
- set value(value) {
62
- this.setValue(value);
63
- }
64
-
65
- /** 图片链接 */
66
- get link() {
67
- return this.name === 'link'
68
- ? ImageParameterToken.#validate('link', this.getValue(), this.getAttribute('config'))
69
- : undefined;
70
- }
71
-
72
- set link(value) {
73
- if (this.name === 'link') {
74
- value = value === ImageParameterToken.noLink ? '' : value;
75
- this.setValue(value);
76
- }
77
- }
78
-
79
- /** 图片大小 */
80
- get size() {
81
- if (this.name === 'width') {
82
- const /** @type {string} */ size = this.getValue().trim();
83
- if (!size.includes('{{')) {
84
- const [width, height = ''] = size.split('x');
85
- return {width, height};
86
- }
87
- const /** @type {{childNodes: AstText[]}} */ token = Parser.parse(size, false, 2, this.getAttribute('config')),
88
- i = token.childNodes.findIndex(({type, data}) => type === 'text' && data.includes('x')),
89
- str = token.childNodes[i];
90
- if (i === -1) {
91
- return {width: size, height: ''};
92
- }
93
- str.splitText(str.data.indexOf('x'));
94
- str.nextSibling.splitText(1);
95
- return {width: text(token.childNodes.slice(0, i + 1)), height: text(token.childNodes.slice(i + 2))};
96
- }
97
- return undefined;
98
- }
99
-
100
- /** 图片宽度 */
101
- get width() {
102
- return this.size?.width;
103
- }
104
-
105
- set width(width) {
106
- if (this.name === 'width') {
107
- const {height} = this;
108
- this.setValue(`${String(width || '')}${height && 'x'}${height}`);
109
- }
110
- }
111
-
112
- /** 图片高度 */
113
- get height() {
114
- return this.size?.height;
115
- }
116
-
117
- set height(height) {
118
- height = String(height || '');
119
- if (this.name === 'width') {
120
- this.setValue(`${this.width}${height && 'x'}${height}`);
121
- }
122
- }
123
-
124
- /**
125
- * @param {string} str 图片参数
126
- * @param {accum} accum
127
- */
128
- constructor(str, config = Parser.getConfig(), accum = []) {
129
- const regexes = Object.entries(config.img).map(
130
- /** @returns {[string, string, RegExp]} */
131
- ([syntax, param]) => [syntax, param, new RegExp(`^(\\s*)${syntax.replace('$1', '(.*)')}(\\s*)$`, 'u')],
132
- ),
133
- param = regexes.find(([,, regex]) => regex.test(str));
134
- if (param) {
135
- const mt = param[2].exec(str);
136
- if (mt.length !== 4 || ImageParameterToken.#validate(param[1], mt[2], config, true)) {
137
- if (mt.length === 3) {
138
- super(undefined, config, true, accum);
139
- this.#syntax = str;
140
- } else {
141
- super(mt[2], config, true, accum, {
142
- 'Stage-2': ':', '!HeadingToken': ':',
143
- });
144
- this.#syntax = `${mt[1]}${param[0]}${mt[3]}`;
145
- }
146
- this.setAttribute('name', param[1]);
147
- return;
148
- }
149
- }
150
- super(str, config, true, accum);
151
- this.setAttribute('name', 'caption').setAttribute('stage', 7);
152
- }
153
-
154
- /** @override */
155
- isPlain() {
156
- return this.name === 'caption';
157
- }
158
-
159
- /**
160
- * @override
161
- * @param {string} selector
162
- */
163
- toString(selector) {
164
- return this.#syntax && !(selector && this.matches(selector))
165
- ? this.#syntax.replace('$1', super.toString(selector))
166
- : super.toString(selector);
167
- }
168
-
169
- /** @override */
170
- text() {
171
- return this.#syntax ? this.#syntax.replace('$1', super.text()).trim() : super.text().trim();
172
- }
173
-
174
- /** @override */
175
- getPadding() {
176
- return Math.max(0, this.#syntax.indexOf('$1'));
177
- }
178
-
179
- /** @override */
180
- print() {
181
- return this.#syntax
182
- ? `<span class="wpb-image-parameter">${
183
- this.#syntax.replace('$1', `<span class="wpb-image-caption">${print(this.childNodes)}</span>`)
184
- }</span>`
185
- : super.print({class: 'image-caption'});
186
- }
187
-
188
- /** @override */
189
- cloneNode() {
190
- const cloned = this.cloneChildNodes(),
191
- config = this.getAttribute('config');
192
- return Parser.run(() => {
193
- const token = new ImageParameterToken(this.#syntax.replace('$1', ''), config);
194
- token.replaceChildren(...cloned);
195
- return token;
196
- });
197
- }
198
-
199
- /**
200
- * @override
201
- * @template {string} T
202
- * @param {T} key 属性键
203
- * @returns {TokenAttribute<T>}
204
- */
205
- getAttribute(key) {
206
- return key === 'syntax' ? this.#syntax : super.getAttribute(key);
207
- }
208
-
209
- /**
210
- * @override
211
- * @param {PropertyKey} key 属性键
212
- */
213
- hasAttribute(key) {
214
- return key === 'syntax' || super.hasAttribute(key);
215
- }
216
-
217
- /** 是否是不可变参数 */
218
- #isVoid() {
219
- return this.#syntax && !this.#syntax.includes('$1');
220
- }
221
-
222
- /**
223
- * @override
224
- * @template {Token} T
225
- * @param {T} token 待插入的子节点
226
- * @param {number} i 插入位置
227
- * @complexity `n`
228
- * @throws `Error` 不接受自定义输入的图片参数
229
- */
230
- insertAt(token, i = this.length) {
231
- if (!Parser.running && this.#isVoid()) {
232
- throw new Error(`图片参数 ${this.name} 不接受自定义输入!`);
233
- }
234
- return super.insertAt(token, i);
235
- }
236
-
237
- /**
238
- * 获取参数值
239
- * @complexity `n`
240
- */
241
- getValue() {
242
- return this.#isVoid() || super.text();
243
- }
244
-
245
- /**
246
- * 设置参数值
247
- * @param {string|boolean} value 参数值
248
- * @complexity `n`
249
- * @throws SyntaxError` 非法的参数值
250
- */
251
- setValue(value) {
252
- if (this.#isVoid()) {
253
- if (typeof value !== 'boolean') {
254
- this.typeError('setValue', 'Boolean');
255
- } else if (value === false) {
256
- this.remove();
257
- }
258
- return;
259
- } else if (typeof value !== 'string') {
260
- this.typeError('setValue', 'String');
261
- }
262
- const root = Parser.parse(`[[File:F|${
263
- this.#syntax ? this.#syntax.replace('$1', value) : value
264
- }]]`, this.getAttribute('include'), 6, this.getAttribute('config')),
265
- {length, firstChild: file} = root,
266
- {lastChild: imageParameter, type, name, length: fileLength} = file;
267
- if (length !== 1 || type !== 'file' || name !== 'File:F' || fileLength !== 2
268
- || imageParameter.name !== this.name
269
- ) {
270
- throw new SyntaxError(`非法的 ${this.name} 参数:${noWrap(value)}`);
271
- }
272
- this.replaceChildren(...imageParameter.childNodes);
273
- }
274
- }
275
-
276
- Parser.classes.ImageParameterToken = __filename;
277
- module.exports = ImageParameterToken;