wikiparser-node 0.0.2 → 0.2.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.
- package/README.md +226 -7
- package/config/default.json +12 -1
- package/config/llwiki.json +12 -1
- package/config/moegirl.json +9 -1
- package/errors/2022-07-04T22:30:41.785Z +1 -0
- package/errors/2022-07-04T22:30:41.785Z.err +11 -0
- package/errors/2022-07-04T22:30:41.785Z.json +5 -0
- package/errors/README +1 -0
- package/index.js +85 -9
- package/lib/element.js +72 -13
- package/lib/node.js +17 -9
- package/mixin/sol.js +42 -0
- package/package.json +1 -1
- package/parser/converter.js +44 -0
- package/parser/externalLinks.js +1 -1
- package/parser/list.js +58 -0
- package/parser/table.js +2 -2
- package/printed/README +1 -0
- package/src/arg.js +9 -9
- package/src/attribute.js +33 -23
- package/src/converter.js +135 -0
- package/src/converterFlags.js +214 -0
- package/src/converterRule.js +209 -0
- package/src/extLink.js +23 -10
- package/src/heading.js +15 -20
- package/src/html.js +4 -3
- package/src/imageParameter.js +6 -7
- package/src/index.js +38 -23
- package/src/link/file.js +9 -9
- package/src/link/index.js +9 -11
- package/src/magicLink.js +2 -3
- package/src/nowiki/comment.js +1 -1
- package/src/nowiki/dd.js +49 -0
- package/src/nowiki/hr.js +3 -2
- package/src/nowiki/list.js +16 -0
- package/src/parameter.js +5 -5
- package/src/syntax.js +3 -1
- package/src/table/index.js +35 -30
- package/src/table/td.js +3 -2
- package/src/table/tr.js +6 -12
- package/src/tagPair/index.js +1 -1
- package/src/transclude.js +28 -25
- package/tool/index.js +50 -40
- package/typings/index.d.ts +3 -0
- package/typings/node.d.ts +3 -3
- package/typings/token.d.ts +1 -0
- package/util/debug.js +3 -3
- package/util/string.js +16 -1
- package/src/listToken.js +0 -47
package/src/table/td.js
CHANGED
|
@@ -110,7 +110,7 @@ class TdToken extends fixedToken(TrToken) {
|
|
|
110
110
|
*/
|
|
111
111
|
static create(inner, subtype = 'td', attr = {}, include = false, config = Parser.getConfig()) {
|
|
112
112
|
if (typeof inner !== 'string' && (!(inner instanceof Token) || !inner.isPlain()) || typeof attr !== 'object') {
|
|
113
|
-
|
|
113
|
+
typeError(this, 'create', 'String', 'Token', 'Object');
|
|
114
114
|
} else if (!['td', 'th', 'caption'].includes(subtype)) {
|
|
115
115
|
throw new RangeError('单元格的子类型只能为 "td"、"th" 或 "caption"!');
|
|
116
116
|
} else if (typeof inner === 'string') {
|
|
@@ -196,6 +196,7 @@ class TdToken extends fixedToken(TrToken) {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
getGaps(i = 0) {
|
|
199
|
+
i = i < 0 ? i + this.childNodes.length : i;
|
|
199
200
|
if (i !== 1) {
|
|
200
201
|
return 0;
|
|
201
202
|
}
|
|
@@ -231,7 +232,7 @@ class TdToken extends fixedToken(TrToken) {
|
|
|
231
232
|
*/
|
|
232
233
|
setAttr(key, value) {
|
|
233
234
|
if (typeof key !== 'string') {
|
|
234
|
-
typeError(
|
|
235
|
+
this.typeError('setAttr', 'String');
|
|
235
236
|
}
|
|
236
237
|
key = key.toLowerCase().trim();
|
|
237
238
|
if (typeof value === 'number' && ['rowspan', 'colspan'].includes(key)) {
|
package/src/table/tr.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const attributeParent = require('../../mixin/attributeParent'),
|
|
4
|
-
{typeError} = require('../../util/debug'),
|
|
5
4
|
/** @type {Parser} */ Parser = require('../..'),
|
|
6
5
|
Token = require('..'),
|
|
7
6
|
SyntaxToken = require('../syntax'),
|
|
@@ -38,7 +37,7 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
38
37
|
const token = new Constructor(undefined, undefined, this.getAttribute('config'));
|
|
39
38
|
token.firstElementChild.safeReplaceWith(syntax);
|
|
40
39
|
token.children[1].safeReplaceWith(attr);
|
|
41
|
-
if (token.
|
|
40
|
+
if (token.type === 'td') { // TdToken
|
|
42
41
|
token.children[2].safeReplaceWith(inner);
|
|
43
42
|
} else if (inner !== undefined) {
|
|
44
43
|
token.appendChild(inner);
|
|
@@ -49,15 +48,13 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
#correct() {
|
|
52
|
-
const [,, child] = this.
|
|
53
|
-
if (
|
|
54
|
-
this.setText(`\n${child}`, 2);
|
|
55
|
-
} else if (typeof child !== 'string' && child?.isPlain()) {
|
|
51
|
+
const [,, child] = this.children;
|
|
52
|
+
if (child?.isPlain()) {
|
|
56
53
|
const {firstChild} = child;
|
|
57
54
|
if (typeof firstChild !== 'string') {
|
|
58
55
|
child.prepend('\n');
|
|
59
56
|
} else if (!firstChild.startsWith('\n')) {
|
|
60
|
-
child.setText(`\n${firstChild}
|
|
57
|
+
child.setText(`\n${firstChild}`);
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
}
|
|
@@ -75,9 +72,6 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
75
72
|
|
|
76
73
|
/** @param {SyntaxToken} syntax */
|
|
77
74
|
static escape(syntax) {
|
|
78
|
-
if (!(syntax instanceof SyntaxToken)) {
|
|
79
|
-
typeError('SyntaxToken');
|
|
80
|
-
}
|
|
81
75
|
const wikitext = syntax.childNodes.map(child => typeof child === 'string'
|
|
82
76
|
? child.replaceAll('{|', '{{(!}}').replaceAll('|}', '{{!)}}').replaceAll('||', '{{!!}}')
|
|
83
77
|
.replaceAll('|', '{{!}}')
|
|
@@ -131,7 +125,7 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
131
125
|
*/
|
|
132
126
|
insertAt(token, i = this.childNodes.length) {
|
|
133
127
|
if (!Parser.running && !(token instanceof TrToken)) {
|
|
134
|
-
typeError(
|
|
128
|
+
this.typeError('insertAt', 'TrToken');
|
|
135
129
|
}
|
|
136
130
|
const TdToken = require('./td'),
|
|
137
131
|
child = this.childNodes.at(i);
|
|
@@ -201,7 +195,7 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
201
195
|
*/
|
|
202
196
|
getNthCol(n, insert = false) {
|
|
203
197
|
if (typeof n !== 'number') {
|
|
204
|
-
typeError(
|
|
198
|
+
this.typeError('getNthCol', 'Number');
|
|
205
199
|
}
|
|
206
200
|
const nCols = this.getColCount();
|
|
207
201
|
n = n < 0 ? n + nCols : n;
|
package/src/tagPair/index.js
CHANGED
|
@@ -52,7 +52,7 @@ class TagPairToken extends fixedToken(Token) {
|
|
|
52
52
|
const {closed, firstChild, lastChild, nextSibling, name, selfClosing} = this,
|
|
53
53
|
[opening, closing] = this.#tags;
|
|
54
54
|
if (!closed && nextSibling) {
|
|
55
|
-
Parser.error(`自动闭合 <${name}>`,
|
|
55
|
+
Parser.error(`自动闭合 <${name}>`, lastChild);
|
|
56
56
|
this.closed = true;
|
|
57
57
|
}
|
|
58
58
|
return selfClosing
|
package/src/transclude.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {removeComment, escapeRegExp, text} = require('../util/string'),
|
|
4
|
-
{
|
|
3
|
+
const {removeComment, escapeRegExp, text, noWrap} = require('../util/string'),
|
|
4
|
+
{externalUse} = require('../util/debug'),
|
|
5
5
|
/** @type {Parser} */ Parser = require('..'),
|
|
6
6
|
Token = require('.'),
|
|
7
7
|
ParameterToken = require('./parameter');
|
|
@@ -19,7 +19,7 @@ class TranscludeToken extends Token {
|
|
|
19
19
|
/** @complexity `n` */
|
|
20
20
|
setModifier(modifier = '') {
|
|
21
21
|
if (typeof modifier !== 'string') {
|
|
22
|
-
typeError(
|
|
22
|
+
this.typeError('setModifier', 'String');
|
|
23
23
|
}
|
|
24
24
|
const [,, raw, subst] = this.getAttribute('config').parserFunction,
|
|
25
25
|
lcModifier = modifier.trim().toLowerCase(),
|
|
@@ -27,7 +27,7 @@ class TranscludeToken extends Token {
|
|
|
27
27
|
isSubst = subst.includes(lcModifier),
|
|
28
28
|
wasRaw = raw.includes(this.modifier.trim().toLowerCase());
|
|
29
29
|
if (wasRaw && isRaw || !wasRaw && (isSubst || modifier === '')
|
|
30
|
-
|| (Parser.running || this.
|
|
30
|
+
|| (Parser.running || this.childNodes.length > 1) && (isRaw || isSubst || modifier === '')
|
|
31
31
|
) {
|
|
32
32
|
this.setAttribute('modifier', modifier);
|
|
33
33
|
return Boolean(modifier);
|
|
@@ -180,10 +180,10 @@ class TranscludeToken extends Token {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
toString() {
|
|
183
|
-
const {children,
|
|
183
|
+
const {children, childNodes: {length}, firstChild} = this;
|
|
184
184
|
return `{{${this.modifier}${this.modifier && ':'}${
|
|
185
185
|
this.type === 'magic-word'
|
|
186
|
-
? `${String(firstChild)}${
|
|
186
|
+
? `${String(firstChild)}${length > 1 ? ':' : ''}${children.slice(1).map(String).join('|')}`
|
|
187
187
|
: super.toString('|')
|
|
188
188
|
}}}`;
|
|
189
189
|
}
|
|
@@ -201,10 +201,10 @@ class TranscludeToken extends Token {
|
|
|
201
201
|
* @complexity `n`
|
|
202
202
|
*/
|
|
203
203
|
text() {
|
|
204
|
-
const {children,
|
|
204
|
+
const {children, childNodes: {length}, firstElementChild} = this;
|
|
205
205
|
return `{{${this.modifier}${this.modifier && ':'}${
|
|
206
206
|
this.type === 'magic-word'
|
|
207
|
-
? `${firstElementChild.text()}${
|
|
207
|
+
? `${firstElementChild.text()}${length > 1 ? ':' : ''}${text(children.slice(1), '|')}`
|
|
208
208
|
: super.text('|')
|
|
209
209
|
}}}`;
|
|
210
210
|
}
|
|
@@ -261,7 +261,7 @@ class TranscludeToken extends Token {
|
|
|
261
261
|
* @param {ParameterToken} token
|
|
262
262
|
* @complexity `n`
|
|
263
263
|
*/
|
|
264
|
-
insertAt(token, i = this.
|
|
264
|
+
insertAt(token, i = this.childNodes.length) {
|
|
265
265
|
super.insertAt(token, i);
|
|
266
266
|
if (token.anon) {
|
|
267
267
|
this.#handleAnonArgChange(token);
|
|
@@ -291,7 +291,7 @@ class TranscludeToken extends Token {
|
|
|
291
291
|
*/
|
|
292
292
|
getArgs(key, exact = false, copy = true) {
|
|
293
293
|
if (!['string', 'number'].includes(typeof key)) {
|
|
294
|
-
typeError(
|
|
294
|
+
this.typeError('getArgs', 'String', 'Number');
|
|
295
295
|
} else if (!copy && !Parser.debugging && externalUse('getArgs')) {
|
|
296
296
|
this.debugOnly('getArgs');
|
|
297
297
|
}
|
|
@@ -381,9 +381,9 @@ class TranscludeToken extends Token {
|
|
|
381
381
|
root = Parser.parse(wikitext, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
382
382
|
{childNodes: {length}, firstElementChild} = root;
|
|
383
383
|
if (length !== 1 || !firstElementChild?.matches(templateLike ? 'template#T' : 'magic-word#lc')
|
|
384
|
-
|| firstElementChild.
|
|
384
|
+
|| firstElementChild.childNodes.length !== 2 || !firstElementChild.lastElementChild.anon
|
|
385
385
|
) {
|
|
386
|
-
throw new SyntaxError(`非法的匿名参数:${val
|
|
386
|
+
throw new SyntaxError(`非法的匿名参数:${noWrap(val)}`);
|
|
387
387
|
}
|
|
388
388
|
return this.appendChild(firstElementChild.lastChild);
|
|
389
389
|
}
|
|
@@ -395,7 +395,7 @@ class TranscludeToken extends Token {
|
|
|
395
395
|
*/
|
|
396
396
|
setValue(key, value) {
|
|
397
397
|
if (typeof key !== 'string') {
|
|
398
|
-
typeError(
|
|
398
|
+
this.typeError('setValue', 'String');
|
|
399
399
|
} else if (!this.matches('template, magic-word#invoke')) {
|
|
400
400
|
throw new Error(`${this.constructor.name}.setValue 方法仅供模板使用!`);
|
|
401
401
|
}
|
|
@@ -409,9 +409,9 @@ class TranscludeToken extends Token {
|
|
|
409
409
|
root = Parser.parse(wikitext, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
410
410
|
{childNodes: {length}, firstElementChild} = root;
|
|
411
411
|
if (length !== 1 || !firstElementChild?.matches('template#T')
|
|
412
|
-
|| firstElementChild.
|
|
412
|
+
|| firstElementChild.childNodes.length !== 2 || firstElementChild.lastElementChild.name !== key
|
|
413
413
|
) {
|
|
414
|
-
throw new SyntaxError(`非法的命名参数:${key}=${value
|
|
414
|
+
throw new SyntaxError(`非法的命名参数:${key}=${noWrap(value)}`);
|
|
415
415
|
}
|
|
416
416
|
this.appendChild(firstElementChild.lastChild);
|
|
417
417
|
}
|
|
@@ -432,11 +432,11 @@ class TranscludeToken extends Token {
|
|
|
432
432
|
if (this.type === 'magic-word') {
|
|
433
433
|
throw new Error(`${this.constructor.name}.replaceTemplate 方法仅用于更换模板!`);
|
|
434
434
|
} else if (typeof title !== 'string') {
|
|
435
|
-
typeError(
|
|
435
|
+
this.typeError('replaceTemplate', 'String');
|
|
436
436
|
}
|
|
437
437
|
const root = Parser.parse(`{{${title}}}`, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
438
438
|
{childNodes: {length}, firstElementChild} = root;
|
|
439
|
-
if (length !== 1 || firstElementChild?.type !== 'template' || firstElementChild.
|
|
439
|
+
if (length !== 1 || firstElementChild?.type !== 'template' || firstElementChild.childNodes.length !== 1) {
|
|
440
440
|
throw new SyntaxError(`非法的模板名称:${title}`);
|
|
441
441
|
}
|
|
442
442
|
this.firstElementChild.replaceChildren(...firstElementChild.firstElementChild.childNodes);
|
|
@@ -447,15 +447,15 @@ class TranscludeToken extends Token {
|
|
|
447
447
|
if (this.type !== 'magic-word' || this.name !== 'invoke') {
|
|
448
448
|
throw new Error(`${this.constructor.name}.replaceModule 方法仅用于更换模块!`);
|
|
449
449
|
} else if (typeof title !== 'string') {
|
|
450
|
-
typeError(
|
|
450
|
+
this.typeError('replaceModule', 'String');
|
|
451
451
|
}
|
|
452
452
|
const root = Parser.parse(`{{#invoke:${title}}}`, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
453
453
|
{childNodes: {length}, firstElementChild} = root;
|
|
454
454
|
if (length !== 1 || !firstElementChild?.matches('magic-word#invoke')
|
|
455
|
-
|| firstElementChild.
|
|
455
|
+
|| firstElementChild.childNodes.length !== 2
|
|
456
456
|
) {
|
|
457
457
|
throw new SyntaxError(`非法的模块名称:${title}`);
|
|
458
|
-
} else if (this.
|
|
458
|
+
} else if (this.childNodes.length > 1) {
|
|
459
459
|
this.children[1].replaceChildren(...firstElementChild.lastElementChild.childNodes);
|
|
460
460
|
} else {
|
|
461
461
|
const {lastChild} = firstElementChild;
|
|
@@ -470,17 +470,17 @@ class TranscludeToken extends Token {
|
|
|
470
470
|
if (this.type !== 'magic-word' || this.name !== 'invoke') {
|
|
471
471
|
throw new Error(`${this.constructor.name}.replaceModule 方法仅用于更换模块!`);
|
|
472
472
|
} else if (typeof func !== 'string') {
|
|
473
|
-
typeError(
|
|
474
|
-
} else if (this.
|
|
473
|
+
this.typeError('replaceFunction', 'String');
|
|
474
|
+
} else if (this.childNodes.length < 2) {
|
|
475
475
|
throw new Error('尚未指定模块名称!');
|
|
476
476
|
}
|
|
477
477
|
const root = Parser.parse(`{{#invoke:M|${func}}}`, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
478
478
|
{childNodes: {length}, firstElementChild} = root;
|
|
479
479
|
if (length !== 1 || !firstElementChild?.matches('magic-word#invoke')
|
|
480
|
-
|| firstElementChild.
|
|
480
|
+
|| firstElementChild.childNodes.length !== 3
|
|
481
481
|
) {
|
|
482
482
|
throw new SyntaxError(`非法的模块函数名:${func}`);
|
|
483
|
-
} else if (this.
|
|
483
|
+
} else if (this.childNodes.length > 2) {
|
|
484
484
|
this.children[2].replaceChildren(...firstElementChild.lastElementChild.childNodes);
|
|
485
485
|
} else {
|
|
486
486
|
const {lastChild} = firstElementChild;
|
|
@@ -582,7 +582,10 @@ class TranscludeToken extends Token {
|
|
|
582
582
|
Parser.error(`${this.type === 'template'
|
|
583
583
|
? this.name
|
|
584
584
|
: this.normalizeTitle(this.children[1]?.text() ?? '', 828).title
|
|
585
|
-
} 还留有 ${remaining} 个重复的 ${key}
|
|
585
|
+
} 还留有 ${remaining} 个重复的 ${key} 参数:${[...this.getArgs(key)].map(arg => {
|
|
586
|
+
const {top, left} = arg.getBoundingClientRect();
|
|
587
|
+
return `第 ${top} 行第 ${left} 列`;
|
|
588
|
+
}).join('、')}`);
|
|
586
589
|
duplicatedKeys.push(key);
|
|
587
590
|
continue;
|
|
588
591
|
}
|
package/tool/index.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {typeError, externalUse} = require('../util/debug'),
|
|
4
|
-
{text} = require('../util/string'),
|
|
4
|
+
{text, noWrap} = require('../util/string'),
|
|
5
5
|
Token = require('../src'),
|
|
6
6
|
assert = require('assert/strict');
|
|
7
7
|
|
|
8
8
|
const /** @type {WeakMap<Token, Record<string, any>>} */ dataStore = new WeakMap();
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
+
* @param {string} method
|
|
11
12
|
* @param {string|Token|Token[]} selector
|
|
12
13
|
* @returns {(token: Token) => boolean}
|
|
13
14
|
*/
|
|
14
|
-
const matchesGenerator = selector => {
|
|
15
|
+
const matchesGenerator = (method, selector) => {
|
|
15
16
|
if (typeof selector === 'string') {
|
|
16
17
|
return token => token instanceof Token && token.matches(selector);
|
|
17
18
|
} else if (Array.isArray(selector)) {
|
|
@@ -19,7 +20,7 @@ const matchesGenerator = selector => {
|
|
|
19
20
|
} else if (selector instanceof Token) {
|
|
20
21
|
return token => token === selector;
|
|
21
22
|
}
|
|
22
|
-
typeError('String', 'Token', 'Array');
|
|
23
|
+
typeError(TokenCollection, method, 'String', 'Token', 'Array');
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
/** @extends {Array<Token>} */
|
|
@@ -39,7 +40,7 @@ class TokenCollection extends Array {
|
|
|
39
40
|
} else if (typeof token === 'string') {
|
|
40
41
|
this.push(token);
|
|
41
42
|
} else if (!(token instanceof Token)) {
|
|
42
|
-
typeError('String', 'Token');
|
|
43
|
+
this.typeError('constructor', 'String', 'Token');
|
|
43
44
|
} else if (!this.includes(token)) {
|
|
44
45
|
this.#roots.add(token.getRootNode());
|
|
45
46
|
this.push(token);
|
|
@@ -49,6 +50,14 @@ class TokenCollection extends Array {
|
|
|
49
50
|
this.#sort();
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} method
|
|
55
|
+
* @param {...string} types
|
|
56
|
+
*/
|
|
57
|
+
typeError(method, ...types) {
|
|
58
|
+
return typeError(this.constructor, method, ...types);
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
#sort() {
|
|
53
62
|
if (this.some(token => typeof token === 'string')) {
|
|
54
63
|
return;
|
|
@@ -171,7 +180,7 @@ class TokenCollection extends Array {
|
|
|
171
180
|
if (typeof selector === 'function') {
|
|
172
181
|
return this.some((ele, i) => selector.call(ele, i, ele));
|
|
173
182
|
}
|
|
174
|
-
const matches = matchesGenerator(selector);
|
|
183
|
+
const matches = matchesGenerator('is', selector);
|
|
175
184
|
return this.some(matches);
|
|
176
185
|
}
|
|
177
186
|
|
|
@@ -182,7 +191,7 @@ class TokenCollection extends Array {
|
|
|
182
191
|
if (typeof selector === 'function') {
|
|
183
192
|
$arr = $(arr.filter((ele, i) => selector.call(ele, i, ele)));
|
|
184
193
|
} else {
|
|
185
|
-
const matches = matchesGenerator(selector);
|
|
194
|
+
const matches = matchesGenerator('filter', selector);
|
|
186
195
|
$arr = $(arr.filter(matches));
|
|
187
196
|
}
|
|
188
197
|
$arr.prevObject = this;
|
|
@@ -198,7 +207,7 @@ class TokenCollection extends Array {
|
|
|
198
207
|
} else if (typeof selector === 'string') {
|
|
199
208
|
$arr = $(arr.filter(ele => ele instanceof Token && !ele.matches(selector)));
|
|
200
209
|
} else {
|
|
201
|
-
const matches = matchesGenerator(selector);
|
|
210
|
+
const matches = matchesGenerator('not', selector);
|
|
202
211
|
$arr = $(arr.filter(ele => !matches(ele)));
|
|
203
212
|
}
|
|
204
213
|
$arr.prevObject = this;
|
|
@@ -215,7 +224,7 @@ class TokenCollection extends Array {
|
|
|
215
224
|
} else if (selector instanceof Token) {
|
|
216
225
|
map = arr => arr.some(token => token.contains(selector)) ? [selector] : [];
|
|
217
226
|
} else {
|
|
218
|
-
typeError('String', 'Token', 'Array');
|
|
227
|
+
this.typeError('find', 'String', 'Token', 'Array');
|
|
219
228
|
}
|
|
220
229
|
return this._create(map);
|
|
221
230
|
}
|
|
@@ -228,13 +237,13 @@ class TokenCollection extends Array {
|
|
|
228
237
|
} else if (selector instanceof Token) {
|
|
229
238
|
return arr.some(ele => ele.contains(selector));
|
|
230
239
|
}
|
|
231
|
-
typeError('String', 'Token');
|
|
240
|
+
this.typeError('has', 'String', 'Token');
|
|
232
241
|
}
|
|
233
242
|
|
|
234
243
|
/** @param {string} selector */
|
|
235
244
|
closest(selector) {
|
|
236
245
|
if (typeof selector !== 'string') {
|
|
237
|
-
typeError('String');
|
|
246
|
+
this.typeError('closest', 'String');
|
|
238
247
|
}
|
|
239
248
|
return this._create(arr => arr.map(ele => ele.closest(selector)));
|
|
240
249
|
}
|
|
@@ -314,7 +323,7 @@ class TokenCollection extends Array {
|
|
|
314
323
|
* @param {string|Token|Token[]} selector
|
|
315
324
|
*/
|
|
316
325
|
_until(method, selector, filter = '') {
|
|
317
|
-
const matches = matchesGenerator(selector);
|
|
326
|
+
const matches = matchesGenerator(`${method.replace(/All$/, '')}Until`, selector);
|
|
318
327
|
return this._create(arr => arr.flatMap(ele => {
|
|
319
328
|
const tokens = $(ele)[method]().toArray(),
|
|
320
329
|
tokenArray = method === 'nextAll' ? tokens : tokens.reverse(),
|
|
@@ -349,7 +358,7 @@ class TokenCollection extends Array {
|
|
|
349
358
|
/** @param {[string|Record<string, any>]} key */
|
|
350
359
|
data(key, value) {
|
|
351
360
|
if (value !== undefined && typeof key !== 'string') {
|
|
352
|
-
typeError('String');
|
|
361
|
+
this.typeError('data', 'String');
|
|
353
362
|
} else if (value === undefined && typeof key !== 'object') {
|
|
354
363
|
const data = $.dataStore.get(this._find());
|
|
355
364
|
return key === undefined ? data : data?.[key];
|
|
@@ -371,7 +380,7 @@ class TokenCollection extends Array {
|
|
|
371
380
|
/** @param {string|string[]} name */
|
|
372
381
|
removeData(name) {
|
|
373
382
|
if (name !== undefined && typeof name !== 'string' && !Array.isArray(name)) {
|
|
374
|
-
typeError('String', 'Array');
|
|
383
|
+
this.typeError('removeData', 'String', 'Array');
|
|
375
384
|
}
|
|
376
385
|
name = typeof name === 'string' ? name.split(/\s/) : name;
|
|
377
386
|
for (const token of this._filter()) {
|
|
@@ -396,7 +405,7 @@ class TokenCollection extends Array {
|
|
|
396
405
|
*/
|
|
397
406
|
_addEventListener(events, selector, handler, once = false) {
|
|
398
407
|
if (!['string', 'object'].includes(typeof events)) {
|
|
399
|
-
typeError('String', 'Object');
|
|
408
|
+
this.typeError(once ? 'once' : 'on', 'String', 'Object');
|
|
400
409
|
} else if (typeof selector === 'function') {
|
|
401
410
|
handler = selector;
|
|
402
411
|
selector = undefined;
|
|
@@ -437,7 +446,7 @@ class TokenCollection extends Array {
|
|
|
437
446
|
*/
|
|
438
447
|
off(events, selector, handler) {
|
|
439
448
|
if (!['string', 'object', 'undefined'].includes(typeof events)) {
|
|
440
|
-
typeError('String', 'Object');
|
|
449
|
+
this.typeError('off', 'String', 'Object');
|
|
441
450
|
}
|
|
442
451
|
handler = typeof selector === 'function' ? selector : handler;
|
|
443
452
|
let eventPair;
|
|
@@ -452,7 +461,7 @@ class TokenCollection extends Array {
|
|
|
452
461
|
} else {
|
|
453
462
|
for (const [event, listener] of eventPair) {
|
|
454
463
|
if (typeof event !== 'string' || !['function', 'undefined'].includes(typeof listener)) {
|
|
455
|
-
typeError('String', 'Function');
|
|
464
|
+
this.typeError('off', 'String', 'Function');
|
|
456
465
|
} else if (listener) {
|
|
457
466
|
token.removeEventListener(event, listener);
|
|
458
467
|
} else {
|
|
@@ -503,7 +512,7 @@ class TokenCollection extends Array {
|
|
|
503
512
|
} else if (Array.isArray(result)) {
|
|
504
513
|
token[method](...result);
|
|
505
514
|
} else {
|
|
506
|
-
typeError('String', 'Token');
|
|
515
|
+
this.typeError(method, 'String', 'Token');
|
|
507
516
|
}
|
|
508
517
|
}
|
|
509
518
|
}
|
|
@@ -604,7 +613,7 @@ class TokenCollection extends Array {
|
|
|
604
613
|
}
|
|
605
614
|
}
|
|
606
615
|
} else {
|
|
607
|
-
typeError('Token', 'Array');
|
|
616
|
+
this.typeError(method, 'Token', 'Array');
|
|
608
617
|
}
|
|
609
618
|
return this;
|
|
610
619
|
}
|
|
@@ -648,7 +657,7 @@ class TokenCollection extends Array {
|
|
|
648
657
|
} else if (Array.isArray(value)) {
|
|
649
658
|
toValue = i => value[i];
|
|
650
659
|
} else {
|
|
651
|
-
typeError('String', 'Array', 'Function');
|
|
660
|
+
this.typeError('val', 'String', 'Array', 'Function');
|
|
652
661
|
}
|
|
653
662
|
for (const [i, token] of this.entries()) {
|
|
654
663
|
if (token instanceof Token && typeof token.setValue === 'function' && token.setValue.length === 1) {
|
|
@@ -730,7 +739,7 @@ class TokenCollection extends Array {
|
|
|
730
739
|
*/
|
|
731
740
|
wrapAll(wrapper) {
|
|
732
741
|
if (typeof wrapper !== 'function' && !Array.isArray(wrapper)) {
|
|
733
|
-
typeError('Array', 'Function');
|
|
742
|
+
this.typeError('wrapAll', 'Array', 'Function');
|
|
734
743
|
}
|
|
735
744
|
const firstToken = this._find(),
|
|
736
745
|
error = new Error('wrapAll 的主体应为同一个父节点下的连续子节点!');
|
|
@@ -757,7 +766,7 @@ class TokenCollection extends Array {
|
|
|
757
766
|
config = firstToken.getRootNode().getAttribute('config'),
|
|
758
767
|
token = new Token(`${pre}${this.toString()}${post}`, config).parse();
|
|
759
768
|
if (token.childNodes.length !== 1) {
|
|
760
|
-
throw new RangeError(`非法的 wrapper:\n${pre}\n${post}`);
|
|
769
|
+
throw new RangeError(`非法的 wrapper:\n${noWrap(pre)}\n${noWrap(post)}`);
|
|
761
770
|
}
|
|
762
771
|
for (let j = i + this.length - 1; j >= i; j--) {
|
|
763
772
|
parentNode.removeAt(j);
|
|
@@ -772,7 +781,7 @@ class TokenCollection extends Array {
|
|
|
772
781
|
*/
|
|
773
782
|
_wrap(method, wrapper) {
|
|
774
783
|
if (typeof wrapper !== 'function' && !Array.isArray(wrapper)) {
|
|
775
|
-
typeError('Array', 'Function');
|
|
784
|
+
this.typeError(method, 'Array', 'Function');
|
|
776
785
|
}
|
|
777
786
|
return this[method](
|
|
778
787
|
/**
|
|
@@ -788,7 +797,7 @@ class TokenCollection extends Array {
|
|
|
788
797
|
config = this.getRootNode().getAttribute('config'),
|
|
789
798
|
token = new Token(`${pre}${string}${post}`, config).parse();
|
|
790
799
|
if (token.childNodes.length !== 1) {
|
|
791
|
-
throw new RangeError(`非法的 wrapper:\n${pre}\n${post}`);
|
|
800
|
+
throw new RangeError(`非法的 wrapper:\n${noWrap(pre)}\n${noWrap(post)}`);
|
|
792
801
|
}
|
|
793
802
|
return token.firstChild;
|
|
794
803
|
},
|
|
@@ -852,36 +861,37 @@ const $ = tokens => {
|
|
|
852
861
|
},
|
|
853
862
|
});
|
|
854
863
|
};
|
|
855
|
-
|
|
864
|
+
/* eslint-disable func-names */
|
|
865
|
+
$.hasData = /** @param {Token} element */ function hasData(element) {
|
|
856
866
|
if (!(element instanceof Token)) {
|
|
857
|
-
typeError('Token');
|
|
867
|
+
typeError(this, 'hasData', 'Token');
|
|
858
868
|
}
|
|
859
|
-
return
|
|
869
|
+
return this.dataStore.has(element);
|
|
860
870
|
};
|
|
861
|
-
$.data = /** @type {(
|
|
871
|
+
$.data = /** @type {function(Token, string, any): any} */ function data(element, key, value) {
|
|
862
872
|
if (!(element instanceof Token)) {
|
|
863
|
-
typeError('Token');
|
|
873
|
+
typeError(this, 'data', 'Token');
|
|
864
874
|
} else if (key === undefined) {
|
|
865
|
-
return
|
|
875
|
+
return this.dataStore.get(element);
|
|
866
876
|
} else if (typeof key !== 'string') {
|
|
867
|
-
typeError('String');
|
|
877
|
+
typeError(this, 'data', 'String');
|
|
868
878
|
} else if (value === undefined) {
|
|
869
|
-
return
|
|
870
|
-
} else if (
|
|
871
|
-
|
|
879
|
+
return this.dataStore.get(element)?.[key];
|
|
880
|
+
} else if (!this.dataStore.has(element)) {
|
|
881
|
+
this.dataStore.set(element, {});
|
|
872
882
|
}
|
|
873
|
-
|
|
883
|
+
this.dataStore.get(element)[key] = value;
|
|
874
884
|
return value;
|
|
875
885
|
};
|
|
876
|
-
$.removeData = /** @type {(
|
|
886
|
+
$.removeData = /** @type {function(Token, string): void} */ function removeData(element, name) {
|
|
877
887
|
if (!(element instanceof Token)) {
|
|
878
|
-
typeError('Token');
|
|
888
|
+
typeError(this, 'removeData', 'Token');
|
|
879
889
|
} else if (name === undefined) {
|
|
880
|
-
|
|
890
|
+
this.dataStore.delete(element);
|
|
881
891
|
} else if (typeof name !== 'string') {
|
|
882
|
-
typeError('String');
|
|
883
|
-
} else if (
|
|
884
|
-
const data =
|
|
892
|
+
typeError(this, 'removeData', 'String');
|
|
893
|
+
} else if (this.dataStore.has(element)) {
|
|
894
|
+
const data = this.dataStore.get(element);
|
|
885
895
|
delete data[name];
|
|
886
896
|
}
|
|
887
897
|
};
|
package/typings/index.d.ts
CHANGED
|
@@ -41,8 +41,11 @@ declare global {
|
|
|
41
41
|
|
|
42
42
|
readonly MAX_STAGE: number;
|
|
43
43
|
parse(wikitext: string|Token, include?: boolean, maxStage?: number, config?: ParserConfig): Token;
|
|
44
|
+
reparse(date: string): Token;
|
|
44
45
|
|
|
45
46
|
getTool(): typeof $;
|
|
47
|
+
|
|
48
|
+
typeAliases: Record<string, string[]>;
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
|
package/typings/node.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ declare global {
|
|
|
6
6
|
type TokenAttribute<T> =
|
|
7
7
|
T extends 'childNodes' ? (string|Token)[] :
|
|
8
8
|
T extends 'parentNode' ? Token|undefined :
|
|
9
|
-
T extends 'optional'|'tags' ? string[] :
|
|
10
|
-
T extends 'stage' ? number :
|
|
9
|
+
T extends 'optional'|'tags'|'flags' ? string[] :
|
|
10
|
+
T extends 'stage'|'indent' ? number :
|
|
11
11
|
T extends 'config' ? ParserConfig :
|
|
12
12
|
T extends 'accum' ? accum :
|
|
13
13
|
T extends 'acceptable' ? Record<string, Ranges> :
|
|
@@ -15,7 +15,7 @@ declare global {
|
|
|
15
15
|
T extends 'keys' ? Set<string> :
|
|
16
16
|
T extends 'args' ? Record<string, Set<ParameterToken>> :
|
|
17
17
|
T extends 'attr' ? Map<string, string|true> :
|
|
18
|
-
T extends 'include'|'selfLink' ? boolean :
|
|
18
|
+
T extends 'include'|'selfLink'|'ul'|'ol'|'dt'|'unidirectional'|'bidirectional' ? boolean :
|
|
19
19
|
T extends 'pattern' ? RegExp :
|
|
20
20
|
string;
|
|
21
21
|
}
|
package/typings/token.d.ts
CHANGED
package/util/debug.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @param {
|
|
4
|
+
* @param {function}
|
|
5
5
|
* @param {string} method
|
|
6
6
|
* @param {...string} args
|
|
7
7
|
*/
|
|
8
|
-
const typeError = ({
|
|
9
|
-
throw new TypeError(`${
|
|
8
|
+
const typeError = ({name}, method, ...args) => {
|
|
9
|
+
throw new TypeError(`${name}.${method} 方法仅接受 ${args.join('、')} 作为输入参数!`);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
/**
|
package/util/string.js
CHANGED
|
@@ -54,7 +54,22 @@ const explode = (start, end, separator, str) => {
|
|
|
54
54
|
return exploded;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
+
/** @param {string} str */
|
|
58
|
+
const noWrap = str => str.replaceAll('\n', '\\n');
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string|Token} token
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
64
|
+
const normalizeSpace = (token = '', separator = '') => {
|
|
65
|
+
const Token = require('../src'); // eslint-disable-line no-unused-vars
|
|
66
|
+
return typeof token === 'string'
|
|
67
|
+
? token.replaceAll('\n', ' ')
|
|
68
|
+
: token.childNodes.map(child => typeof child === 'string' ? normalizeSpace(child) : child.toString())
|
|
69
|
+
.join(separator);
|
|
70
|
+
};
|
|
71
|
+
|
|
57
72
|
const extUrlChar = '(?:[\\d.]+|\\[[\\da-f:.]+\\]|[^[\\]<>"\\x00-\\x20\\x7f\\p{Zs}\\ufffd])'
|
|
58
73
|
+ '[^[\\]<>"\\x00-\\x20\\x7f\\p{Zs}\\ufffd]*';
|
|
59
74
|
|
|
60
|
-
module.exports = {toCase, removeComment, ucfirst, escapeRegExp, text, explode, extUrlChar};
|
|
75
|
+
module.exports = {toCase, removeComment, ucfirst, escapeRegExp, text, explode, noWrap, normalizeSpace, extUrlChar};
|
package/src/listToken.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const Token = require('.'),
|
|
3
|
-
AtomToken = require('./atom'),
|
|
4
|
-
{fixToken} = require('./util');
|
|
5
|
-
|
|
6
|
-
class ListToken extends fixToken(Token) {
|
|
7
|
-
type = 'list';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @param {string} syntax
|
|
11
|
-
* @param {?string|number|Token|(string|Token)[]} content
|
|
12
|
-
* @param {Object<string, any>} config
|
|
13
|
-
* @param {Token} parent
|
|
14
|
-
* @param {Token[]} accum
|
|
15
|
-
*/
|
|
16
|
-
constructor(syntax, content, config = require(Token.config), parent = null, accum = [], isTable = false) {
|
|
17
|
-
if (/[^:;#*]/.test(syntax)) {
|
|
18
|
-
throw new RangeError('List语法只接受":"、";"、"#"或"*"!');
|
|
19
|
-
}
|
|
20
|
-
super(new AtomToken(syntax, 'list-syntax'), config, true, parent, accum, ['AtomToken', 'Token']);
|
|
21
|
-
const inner = new Token(content, config, true, this, accum);
|
|
22
|
-
inner.type = 'list-inner';
|
|
23
|
-
inner.set('stage', isTable ? 4 : 10);
|
|
24
|
-
this.lists = new Set(syntax.split(''));
|
|
25
|
-
this.seal();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
isDt() {
|
|
29
|
-
return this.$children[0].contains(';');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
idDd() {
|
|
33
|
-
return this.$children[0].contains(':');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
isOl() {
|
|
37
|
-
return this.$children[0].contains('#');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
isUl() {
|
|
41
|
-
return this.$children[0].contains('*');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
Token.classes.ListToken = ListToken;
|
|
46
|
-
|
|
47
|
-
module.exports = ListToken;
|