wikiparser-node 0.3.1 → 0.5.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 +1 -1
- package/config/default.json +13 -17
- package/config/llwiki.json +11 -79
- package/config/moegirl.json +7 -1
- package/config/zhwiki.json +1269 -0
- package/index.js +130 -97
- package/lib/element.js +410 -518
- package/lib/node.js +493 -115
- package/lib/ranges.js +27 -19
- package/lib/text.js +175 -0
- package/lib/title.js +14 -6
- package/mixin/attributeParent.js +70 -24
- package/mixin/fixedToken.js +18 -10
- package/mixin/hidden.js +6 -4
- package/mixin/sol.js +39 -12
- package/package.json +17 -4
- package/parser/brackets.js +18 -18
- package/parser/commentAndExt.js +16 -14
- package/parser/converter.js +14 -13
- package/parser/externalLinks.js +12 -11
- package/parser/hrAndDoubleUnderscore.js +24 -14
- package/parser/html.js +8 -7
- package/parser/links.js +13 -13
- package/parser/list.js +12 -11
- package/parser/magicLinks.js +11 -10
- package/parser/quotes.js +6 -5
- package/parser/selector.js +175 -0
- package/parser/table.js +31 -24
- package/src/arg.js +91 -43
- package/src/atom/hidden.js +5 -2
- package/src/atom/index.js +17 -9
- package/src/attribute.js +210 -101
- package/src/converter.js +78 -43
- package/src/converterFlags.js +104 -45
- package/src/converterRule.js +136 -78
- package/src/extLink.js +81 -27
- package/src/gallery.js +63 -20
- package/src/heading.js +58 -20
- package/src/html.js +138 -48
- package/src/imageParameter.js +93 -58
- package/src/index.js +314 -186
- package/src/link/category.js +22 -54
- package/src/link/file.js +83 -32
- package/src/link/galleryImage.js +21 -7
- package/src/link/index.js +170 -81
- package/src/magicLink.js +64 -14
- package/src/nowiki/comment.js +36 -10
- package/src/nowiki/dd.js +37 -22
- package/src/nowiki/doubleUnderscore.js +21 -7
- package/src/nowiki/hr.js +11 -7
- package/src/nowiki/index.js +16 -9
- package/src/nowiki/list.js +2 -2
- package/src/nowiki/noinclude.js +8 -4
- package/src/nowiki/quote.js +38 -7
- package/src/onlyinclude.js +24 -7
- package/src/parameter.js +102 -62
- package/src/syntax.js +23 -20
- package/src/table/index.js +282 -174
- package/src/table/td.js +112 -61
- package/src/table/tr.js +135 -74
- package/src/tagPair/ext.js +30 -23
- package/src/tagPair/include.js +26 -11
- package/src/tagPair/index.js +72 -29
- package/src/transclude.js +235 -127
- package/tool/index.js +42 -32
- package/util/debug.js +21 -18
- package/util/diff.js +76 -0
- package/util/lint.js +40 -0
- package/util/string.js +56 -26
- package/.eslintrc.json +0 -319
- package/errors/README +0 -1
- package/jsconfig.json +0 -7
- package/printed/README +0 -1
- package/typings/element.d.ts +0 -28
- package/typings/index.d.ts +0 -52
- package/typings/node.d.ts +0 -23
- package/typings/parser.d.ts +0 -9
- package/typings/table.d.ts +0 -14
- package/typings/token.d.ts +0 -22
- package/typings/tool.d.ts +0 -10
package/src/nowiki/dd.js
CHANGED
|
@@ -1,41 +1,56 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const Parser = require('../..'),
|
|
4
4
|
NowikiToken = require('.');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* :
|
|
8
|
-
* @classdesc `{childNodes: [
|
|
8
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
9
9
|
*/
|
|
10
10
|
class DdToken extends NowikiToken {
|
|
11
11
|
type = 'dd';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/** @param {string} str */
|
|
18
|
-
#update(str) {
|
|
19
|
-
this.setAttribute('ul', str.includes('*')).setAttribute('ol', str.includes('#'))
|
|
20
|
-
.setAttribute('dt', str.includes(';')).setAttribute('indent', str.split(':').length - 1);
|
|
12
|
+
|
|
13
|
+
/** 是否包含<dt> */
|
|
14
|
+
get dt() {
|
|
15
|
+
return String(this).includes(';');
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
/** 是否包含<ul> */
|
|
19
|
+
get ul() {
|
|
20
|
+
return String(this).includes('*');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 是否包含<ol> */
|
|
24
|
+
get ol() {
|
|
25
|
+
return String(this).includes('#');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 缩进数 */
|
|
29
|
+
get indent() {
|
|
30
|
+
return String(this).split(':').length - 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
set indent(indent) {
|
|
34
|
+
if (this.type === 'dd') {
|
|
35
|
+
if (typeof indent !== 'number') {
|
|
36
|
+
this.typeError('set indent', 'Number');
|
|
37
|
+
} else if (!Number.isInteger(indent) || indent < 0) {
|
|
38
|
+
throw new RangeError(`indent 应为自然数!${indent}`);
|
|
39
|
+
}
|
|
40
|
+
this.setText(':'.repeat(indent));
|
|
41
|
+
}
|
|
30
42
|
}
|
|
31
43
|
|
|
32
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* @override
|
|
46
|
+
* @param {string} str 新文本
|
|
47
|
+
* @throws `RangeError` 错误的列表语法
|
|
48
|
+
*/
|
|
33
49
|
setText(str) {
|
|
34
50
|
const src = this.type === 'dd' ? ':' : ';:*#';
|
|
35
|
-
if (RegExp(`[^${src}]
|
|
36
|
-
throw new RangeError(`${this.constructor.name} 仅能包含${src.
|
|
51
|
+
if (new RegExp(`[^${src}]`, 'u').test(str)) {
|
|
52
|
+
throw new RangeError(`${this.constructor.name} 仅能包含${[...src].map(c => `"${c}"`).join('、')}!`);
|
|
37
53
|
}
|
|
38
|
-
this.#update(str);
|
|
39
54
|
return super.setText(str);
|
|
40
55
|
}
|
|
41
56
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const hidden = require('../../mixin/hidden'),
|
|
4
|
-
|
|
4
|
+
Parser = require('../..'),
|
|
5
5
|
NowikiToken = require('.');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 状态开关
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
9
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
10
10
|
*/
|
|
11
11
|
class DoubleUnderscoreToken extends hidden(NowikiToken) {
|
|
12
12
|
type = 'double-underscore';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @param {string} word
|
|
15
|
+
* @param {string} word 状态开关名
|
|
16
16
|
* @param {accum} accum
|
|
17
17
|
*/
|
|
18
18
|
constructor(word, config = Parser.getConfig(), accum = []) {
|
|
@@ -20,19 +20,33 @@ class DoubleUnderscoreToken extends hidden(NowikiToken) {
|
|
|
20
20
|
this.setAttribute('name', word.toLowerCase());
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/** @override */
|
|
23
24
|
cloneNode() {
|
|
24
|
-
return Parser.run(() => new DoubleUnderscoreToken(this.firstChild, this.getAttribute('config')));
|
|
25
|
+
return Parser.run(() => new DoubleUnderscoreToken(String(this.firstChild), this.getAttribute('config')));
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @override
|
|
30
|
+
* @param {string} selector
|
|
31
|
+
*/
|
|
32
|
+
toString(selector) {
|
|
33
|
+
return selector && this.matches(selector) ? '' : `__${String(this.firstChild)}__`;
|
|
30
34
|
}
|
|
31
35
|
|
|
36
|
+
/** @override */
|
|
32
37
|
getPadding() {
|
|
33
38
|
return 2;
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
/** @override */
|
|
42
|
+
print() {
|
|
43
|
+
return super.print({pre: '__', post: '__'});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @override
|
|
48
|
+
* @throws `Error` 禁止修改
|
|
49
|
+
*/
|
|
36
50
|
setText() {
|
|
37
51
|
throw new Error(`禁止修改 ${this.constructor.name}!`);
|
|
38
52
|
}
|
package/src/nowiki/hr.js
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const sol = require('../../mixin/sol'),
|
|
4
|
-
|
|
4
|
+
Parser = require('../..'),
|
|
5
5
|
NowikiToken = require('.');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* `<hr>`
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
9
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
10
10
|
*/
|
|
11
11
|
class HrToken extends sol(NowikiToken) {
|
|
12
12
|
type = 'hr';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @param {number} n
|
|
15
|
+
* @param {number} n 字符串长度
|
|
16
16
|
* @param {accum} accum
|
|
17
17
|
*/
|
|
18
18
|
constructor(n, config = Parser.getConfig(), accum = []) {
|
|
19
19
|
super('-'.repeat(n), config, accum);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/** @
|
|
22
|
+
/** @override */
|
|
23
23
|
cloneNode() {
|
|
24
|
-
return Parser.run(() => new HrToken(this.
|
|
24
|
+
return Parser.run(() => new HrToken(String(this).length, this.getAttribute('config')));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* @override
|
|
29
|
+
* @param {string} str 新文本
|
|
30
|
+
* @throws `RangeError` 错误的\<hr\>语法
|
|
31
|
+
*/
|
|
28
32
|
setText(str) {
|
|
29
|
-
if (
|
|
33
|
+
if (str.length < 4 || /[^-]/u.test(str)) {
|
|
30
34
|
throw new RangeError('<hr>总是写作不少于4个的连续"-"!');
|
|
31
35
|
}
|
|
32
36
|
return super.setText(str);
|
package/src/nowiki/index.js
CHANGED
|
@@ -1,33 +1,40 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fixedToken = require('../../mixin/fixedToken'),
|
|
4
|
-
|
|
5
|
-
Token = require('..')
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
Token = require('..'),
|
|
6
|
+
AstText = require('../../lib/text');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* 纯文字Token,不会被解析
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
10
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
10
11
|
*/
|
|
11
12
|
class NowikiToken extends fixedToken(Token) {
|
|
12
13
|
type = 'ext-inner';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
* @param {string} wikitext
|
|
16
|
+
* @param {string} wikitext wikitext
|
|
16
17
|
* @param {accum} accum
|
|
17
18
|
*/
|
|
18
19
|
constructor(wikitext, config = Parser.getConfig(), accum = []) {
|
|
19
20
|
super(wikitext, config, true, accum);
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* @override
|
|
25
|
+
* @this {NowikiToken & {firstChild: AstText, constructor: typeof NowikiToken}}
|
|
26
|
+
*/
|
|
23
27
|
cloneNode() {
|
|
24
|
-
const
|
|
25
|
-
token = Parser.run(() => new
|
|
26
|
-
token.type =
|
|
28
|
+
const {constructor, firstChild: {data}, type} = this,
|
|
29
|
+
token = Parser.run(() => new constructor(data, this.getAttribute('config')));
|
|
30
|
+
token.type = type;
|
|
27
31
|
return token;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* @override
|
|
36
|
+
* @param {string} str 新文本
|
|
37
|
+
*/
|
|
31
38
|
setText(str) {
|
|
32
39
|
return super.setText(str, 0);
|
|
33
40
|
}
|
package/src/nowiki/list.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const sol = require('../../mixin/sol'),
|
|
4
|
-
|
|
4
|
+
Parser = require('../..'),
|
|
5
5
|
DdToken = require('./dd');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* ;:*#
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
9
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
10
10
|
*/
|
|
11
11
|
class ListToken extends sol(DdToken) {
|
|
12
12
|
type = 'list';
|
package/src/nowiki/noinclude.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const hidden = require('../../mixin/hidden'),
|
|
4
|
-
|
|
4
|
+
Parser = require('../..'),
|
|
5
5
|
NowikiToken = require('.');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* `<noinclude>`和`</noinclude>`,不可进行任何更改
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
9
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
10
10
|
*/
|
|
11
11
|
class NoincludeToken extends hidden(NowikiToken) {
|
|
12
12
|
type = 'noinclude';
|
|
13
13
|
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* @override
|
|
16
|
+
* @param {string} str 新文本
|
|
17
|
+
* @throws `Error` 不可更改
|
|
18
|
+
*/
|
|
15
19
|
setText(str) {
|
|
16
|
-
if (/^<\/?(?:(?:no|only)include|includeonly)(?:\s.*)?\/?>$/
|
|
20
|
+
if (/^<\/?(?:(?:no|only)include|includeonly)(?:\s.*)?\/?>$/isu.test(String(this))) {
|
|
17
21
|
throw new Error(`${this.constructor.name} 不可更改文字内容!`);
|
|
18
22
|
}
|
|
19
23
|
return super.setText(str);
|
package/src/nowiki/quote.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const {generateForSelf} = require('../../util/lint'),
|
|
4
|
+
Parser = require('../..'),
|
|
5
|
+
AstText = require('../../lib/text'),
|
|
4
6
|
NowikiToken = require('.');
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* `<hr>`
|
|
8
|
-
* @classdesc `{childNodes: [
|
|
10
|
+
* @classdesc `{childNodes: [AstText]}`
|
|
9
11
|
*/
|
|
10
12
|
class QuoteToken extends NowikiToken {
|
|
11
13
|
type = 'quote';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
|
-
* @param {number} n
|
|
16
|
+
* @param {number} n 字符串长度
|
|
15
17
|
* @param {accum} accum
|
|
16
18
|
*/
|
|
17
19
|
constructor(n, config = Parser.getConfig(), accum = []) {
|
|
@@ -19,12 +21,41 @@ class QuoteToken extends NowikiToken {
|
|
|
19
21
|
this.setAttribute('name', String(n));
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* @override
|
|
26
|
+
* @this {AstText}
|
|
27
|
+
* @param {number} start 起始位置
|
|
28
|
+
*/
|
|
29
|
+
lint(start = 0) {
|
|
30
|
+
const {previousSibling, nextSibling} = this,
|
|
31
|
+
message = `孤立的"'"`,
|
|
32
|
+
/** @type {LintError[]} */ errors = [];
|
|
33
|
+
let /** @type {LintError} */ refError;
|
|
34
|
+
if (previousSibling?.type === 'text' && previousSibling.data.at(-1) === "'") {
|
|
35
|
+
refError = generateForSelf(this, this.getRootNode().posFromIndex(start), '');
|
|
36
|
+
const {startLine, startCol} = refError,
|
|
37
|
+
[{length}] = previousSibling.data.match(/(?<!')'+$/u);
|
|
38
|
+
errors.push({message, startLine, startCol: startCol - length, endLine: startLine, endCol: startCol});
|
|
39
|
+
}
|
|
40
|
+
if (nextSibling?.type === 'text' && nextSibling.data[0] === "'") {
|
|
41
|
+
refError ||= generateForSelf(this, this.getRootNode().posFromIndex(start), '');
|
|
42
|
+
const {endLine, endCol} = refError,
|
|
43
|
+
[{length}] = nextSibling.data.match(/^'+/u);
|
|
44
|
+
errors.push({message, startLine: endLine, startCol: endCol, endLine, endCol: endCol + length});
|
|
45
|
+
}
|
|
46
|
+
return errors;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @override
|
|
51
|
+
* @param {string} str 新文本
|
|
52
|
+
* @throws `RangeError` 错误的单引号语法
|
|
53
|
+
*/
|
|
23
54
|
setText(str) {
|
|
24
|
-
if (
|
|
25
|
-
|
|
55
|
+
if (str === "''" || str === "'''" || str === "'''''") {
|
|
56
|
+
return super.setText(str);
|
|
26
57
|
}
|
|
27
|
-
|
|
58
|
+
throw new RangeError(`${this.constructor.name} 的内部文本只能为连续 2/3/5 个"'"!`);
|
|
28
59
|
}
|
|
29
60
|
}
|
|
30
61
|
|
package/src/onlyinclude.js
CHANGED
|
@@ -1,40 +1,57 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const Parser = require('..'),
|
|
4
4
|
Token = require('.');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* 嵌入时的`<onlyinclude>`
|
|
8
|
-
* @classdesc `{childNodes: ...
|
|
8
|
+
* @classdesc `{childNodes: ...AstText|Token}`
|
|
9
9
|
*/
|
|
10
10
|
class OnlyincludeToken extends Token {
|
|
11
11
|
type = 'onlyinclude';
|
|
12
12
|
|
|
13
|
+
/** 内部wikitext */
|
|
14
|
+
get innerText() {
|
|
15
|
+
return this.text();
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
/**
|
|
14
|
-
* @param {string} inner
|
|
19
|
+
* @param {string} inner 标签内部wikitext
|
|
15
20
|
* @param {accum} accum
|
|
16
21
|
*/
|
|
17
22
|
constructor(inner, config = Parser.getConfig(), accum = []) {
|
|
18
23
|
super(inner, config, true, accum);
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
/** @override */
|
|
21
27
|
cloneNode() {
|
|
22
|
-
const cloned = this.
|
|
28
|
+
const cloned = this.cloneChildNodes(),
|
|
23
29
|
token = Parser.run(() => new OnlyincludeToken(undefined, this.getAttribute('config')));
|
|
24
30
|
token.append(...cloned);
|
|
25
31
|
return token;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @override
|
|
36
|
+
* @param {string} selector
|
|
37
|
+
*/
|
|
38
|
+
toString(selector) {
|
|
39
|
+
return selector && this.matches(selector) ? '' : `<onlyinclude>${super.toString(selector)}</onlyinclude>`;
|
|
30
40
|
}
|
|
31
41
|
|
|
42
|
+
/** @override */
|
|
32
43
|
getPadding() {
|
|
33
44
|
return 13;
|
|
34
45
|
}
|
|
35
46
|
|
|
47
|
+
/** @override */
|
|
48
|
+
print() {
|
|
49
|
+
return super.print({pre: '<onlyinclude>', post: '</onlyinclude>'});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** @override */
|
|
36
53
|
isPlain() {
|
|
37
|
-
return
|
|
54
|
+
return true;
|
|
38
55
|
}
|
|
39
56
|
}
|
|
40
57
|
|
package/src/parameter.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const {noWrap} = require('../util/string'),
|
|
4
4
|
fixedToken = require('../mixin/fixedToken'),
|
|
5
|
-
|
|
5
|
+
Parser = require('..'),
|
|
6
6
|
Token = require('.');
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -11,18 +11,30 @@ const {noWrap} = require('../util/string'),
|
|
|
11
11
|
*/
|
|
12
12
|
class ParameterToken extends fixedToken(Token) {
|
|
13
13
|
type = 'parameter';
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
/** 是否是匿名参数 */
|
|
16
|
+
get anon() {
|
|
17
|
+
return this.firstChild.childNodes.length === 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** getValue()的getter */
|
|
21
|
+
get value() {
|
|
22
|
+
return this.getValue();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
set value(value) {
|
|
26
|
+
this.setValue(value);
|
|
27
|
+
}
|
|
15
28
|
|
|
16
29
|
/**
|
|
17
|
-
* @param {string|number} key
|
|
18
|
-
* @param {string} value
|
|
30
|
+
* @param {string|number} key 参数名
|
|
31
|
+
* @param {string} value 参数值
|
|
19
32
|
* @param {accum} accum
|
|
20
33
|
*/
|
|
21
34
|
constructor(key, value, config = Parser.getConfig(), accum = []) {
|
|
22
35
|
super(undefined, config, true, accum);
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
keyToken = new AtomToken(this.anon ? undefined : key, 'parameter-key', config, accum, {
|
|
36
|
+
const AtomToken = require('./atom');
|
|
37
|
+
const keyToken = new AtomToken(typeof key === 'number' ? undefined : key, 'parameter-key', config, accum, {
|
|
26
38
|
'Stage-2': ':', '!HeadingToken': '',
|
|
27
39
|
}),
|
|
28
40
|
token = new Token(value, config, true, accum);
|
|
@@ -30,20 +42,22 @@ class ParameterToken extends fixedToken(Token) {
|
|
|
30
42
|
this.append(keyToken, token.setAttribute('stage', 2));
|
|
31
43
|
}
|
|
32
44
|
|
|
45
|
+
/** @override */
|
|
33
46
|
cloneNode() {
|
|
34
|
-
const [key, value] = this.
|
|
47
|
+
const [key, value] = this.cloneChildNodes(),
|
|
35
48
|
config = this.getAttribute('config');
|
|
36
49
|
return Parser.run(() => {
|
|
37
50
|
const token = new ParameterToken(this.anon ? Number(this.name) : undefined, undefined, config);
|
|
38
|
-
token.
|
|
39
|
-
token.
|
|
51
|
+
token.firstChild.safeReplaceWith(key);
|
|
52
|
+
token.lastChild.safeReplaceWith(value);
|
|
40
53
|
return token.afterBuild();
|
|
41
54
|
});
|
|
42
55
|
}
|
|
43
56
|
|
|
57
|
+
/** @override */
|
|
44
58
|
afterBuild() {
|
|
45
59
|
if (!this.anon) {
|
|
46
|
-
const name = this.
|
|
60
|
+
const name = this.firstChild.text().trim(),
|
|
47
61
|
{parentNode} = this;
|
|
48
62
|
this.setAttribute('name', name);
|
|
49
63
|
if (parentNode && parentNode instanceof require('./transclude')) {
|
|
@@ -51,19 +65,14 @@ class ParameterToken extends fixedToken(Token) {
|
|
|
51
65
|
parentNode.getArgs(name, false, false).add(this);
|
|
52
66
|
}
|
|
53
67
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!that.anon) { // 匿名参数不管怎么变动还是匿名
|
|
61
|
-
const {firstElementChild} = that;
|
|
62
|
-
if (prevTarget === firstElementChild) {
|
|
63
|
-
const newKey = firstElementChild.text().trim();
|
|
64
|
-
data.oldKey = that.name;
|
|
68
|
+
const /** @type {AstListener} */ parameterListener = ({prevTarget}, data) => {
|
|
69
|
+
if (!this.anon) { // 匿名参数不管怎么变动还是匿名
|
|
70
|
+
const {firstChild, name} = this;
|
|
71
|
+
if (prevTarget === firstChild) {
|
|
72
|
+
const newKey = firstChild.text().trim();
|
|
73
|
+
data.oldKey = name;
|
|
65
74
|
data.newKey = newKey;
|
|
66
|
-
|
|
75
|
+
this.setAttribute('name', newKey);
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
};
|
|
@@ -71,22 +80,38 @@ class ParameterToken extends fixedToken(Token) {
|
|
|
71
80
|
return this;
|
|
72
81
|
}
|
|
73
82
|
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
/**
|
|
84
|
+
* @override
|
|
85
|
+
* @param {string} selector
|
|
86
|
+
* @returns {string}
|
|
87
|
+
*/
|
|
88
|
+
toString(selector) {
|
|
89
|
+
return this.anon && !(selector && this.matches(selector))
|
|
90
|
+
? this.lastChild.toString(selector)
|
|
91
|
+
: super.toString(selector, '=');
|
|
77
92
|
}
|
|
78
93
|
|
|
94
|
+
/** @override */
|
|
79
95
|
getGaps() {
|
|
80
96
|
return this.anon ? 0 : 1;
|
|
81
97
|
}
|
|
82
98
|
|
|
83
|
-
/** @
|
|
99
|
+
/** @override */
|
|
100
|
+
print() {
|
|
101
|
+
return super.print({sep: this.anon ? '' : '='});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @override
|
|
106
|
+
* @returns {string}
|
|
107
|
+
*/
|
|
84
108
|
text() {
|
|
85
|
-
return this.anon ? this.
|
|
109
|
+
return this.anon ? this.lastChild.text() : super.text('=');
|
|
86
110
|
}
|
|
87
111
|
|
|
88
112
|
/**
|
|
89
|
-
* @
|
|
113
|
+
* @override
|
|
114
|
+
* @param {ParameterToken} token 待替换的节点
|
|
90
115
|
* @complexity `n`
|
|
91
116
|
*/
|
|
92
117
|
safeReplaceWith(token) {
|
|
@@ -94,65 +119,80 @@ class ParameterToken extends fixedToken(Token) {
|
|
|
94
119
|
return this.replaceWith(token);
|
|
95
120
|
}
|
|
96
121
|
|
|
122
|
+
/**
|
|
123
|
+
* 获取参数值
|
|
124
|
+
* @this {ParameterToken & {parentNode: TranscludeToken}}
|
|
125
|
+
*/
|
|
97
126
|
getValue() {
|
|
98
|
-
const
|
|
99
|
-
|
|
127
|
+
const TranscludeToken = require('./transclude');
|
|
128
|
+
const value = this.lastChild.text();
|
|
129
|
+
return this.anon && this.parentNode?.isTemplate() ? value : value.trim();
|
|
100
130
|
}
|
|
101
131
|
|
|
102
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* 设置参数值
|
|
134
|
+
* @this {ParameterToken & {parentNode: TranscludeToken}}
|
|
135
|
+
* @param {string} value 参数值
|
|
136
|
+
* @throws `SyntaxError` 非法的模板参数
|
|
137
|
+
*/
|
|
103
138
|
setValue(value) {
|
|
104
139
|
value = String(value);
|
|
105
|
-
const
|
|
140
|
+
const TranscludeToken = require('./transclude');
|
|
141
|
+
const templateLike = this.parentNode?.isTemplate(),
|
|
106
142
|
wikitext = `{{${templateLike ? ':T|' : 'lc:'}${this.anon ? '' : '1='}${value}}}`,
|
|
107
143
|
root = Parser.parse(wikitext, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
108
|
-
{childNodes: {length},
|
|
109
|
-
/** @type {ParameterToken} */
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
144
|
+
{childNodes: {length}, firstChild: transclude} = root,
|
|
145
|
+
/** @type {Token & {lastChild: ParameterToken}} */
|
|
146
|
+
{lastChild: parameter, type, name, childNodes: {length: transcludeLength}} = transclude,
|
|
147
|
+
targetType = templateLike ? 'template' : 'magic-word',
|
|
148
|
+
targetName = templateLike ? 'T' : 'lc';
|
|
149
|
+
if (length !== 1 || type !== targetType || name !== targetName || transcludeLength !== 2
|
|
150
|
+
|| parameter.anon !== this.anon || parameter.name !== '1'
|
|
113
151
|
) {
|
|
114
152
|
throw new SyntaxError(`非法的模板参数:${noWrap(value)}`);
|
|
115
153
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
lastElementChild.destroy();
|
|
120
|
-
this.lastElementChild.safeReplaceWith(newValue);
|
|
154
|
+
const {lastChild} = parameter;
|
|
155
|
+
parameter.destroy(true);
|
|
156
|
+
this.lastChild.safeReplaceWith(lastChild);
|
|
121
157
|
}
|
|
122
158
|
|
|
123
|
-
/**
|
|
124
|
-
|
|
159
|
+
/**
|
|
160
|
+
* 修改参数名
|
|
161
|
+
* @this {ParameterToken & {parentNode: TranscludeToken}}
|
|
162
|
+
* @param {string} key 新参数名
|
|
163
|
+
* @param {boolean} force 是否无视冲突命名
|
|
164
|
+
* @throws `Error` 仅用于模板参数
|
|
165
|
+
* @throws `SyntaxError` 非法的模板参数名
|
|
166
|
+
* @throws `RangeError` 更名造成重复参数
|
|
167
|
+
*/
|
|
168
|
+
rename(key, force) {
|
|
125
169
|
if (typeof key !== 'string') {
|
|
126
170
|
this.typeError('rename', 'String');
|
|
127
171
|
}
|
|
172
|
+
const TranscludeToken = require('./transclude');
|
|
128
173
|
const {parentNode} = this;
|
|
129
174
|
// 必须检测是否是TranscludeToken
|
|
130
|
-
if (!parentNode || !parentNode
|
|
131
|
-
|| !(parentNode instanceof require('./transclude'))
|
|
132
|
-
) {
|
|
175
|
+
if (!parentNode?.isTemplate() || !(parentNode instanceof require('./transclude'))) {
|
|
133
176
|
throw new Error(`${this.constructor.name}.rename 方法仅用于模板参数!`);
|
|
134
177
|
}
|
|
135
178
|
const root = Parser.parse(`{{:T|${key}=}}`, this.getAttribute('include'), 2, this.getAttribute('config')),
|
|
136
|
-
{childNodes: {length},
|
|
137
|
-
|
|
179
|
+
{childNodes: {length}, firstChild: template} = root,
|
|
180
|
+
{type, name, lastChild: parameter, childNodes: {length: templateLength}} = template;
|
|
181
|
+
if (length !== 1 || type !== 'template' || name !== 'T' || templateLength !== 2) {
|
|
138
182
|
throw new SyntaxError(`非法的模板参数名:${key}`);
|
|
139
183
|
}
|
|
140
|
-
const {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
Parser.warn('未改变实际参数名', name);
|
|
145
|
-
} else if (parentNode.hasArg(name)) {
|
|
184
|
+
const {name: parameterName, firstChild} = parameter;
|
|
185
|
+
if (this.name === parameterName) {
|
|
186
|
+
Parser.warn('未改变实际参数名', parameterName);
|
|
187
|
+
} else if (parentNode.hasArg(parameterName)) {
|
|
146
188
|
if (force) {
|
|
147
|
-
Parser.warn('参数更名造成重复参数',
|
|
189
|
+
Parser.warn('参数更名造成重复参数', parameterName);
|
|
148
190
|
} else {
|
|
149
|
-
throw new RangeError(`参数更名造成重复参数:${
|
|
191
|
+
throw new RangeError(`参数更名造成重复参数:${parameterName}`);
|
|
150
192
|
}
|
|
151
193
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
lastElementChild.destroy();
|
|
155
|
-
this.firstElementChild.safeReplaceWith(keyToken);
|
|
194
|
+
parameter.destroy(true);
|
|
195
|
+
this.firstChild.safeReplaceWith(firstChild);
|
|
156
196
|
}
|
|
157
197
|
}
|
|
158
198
|
|