wikiparser-node 0.4.0 → 0.6.2-b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/bundle.min.js +34 -0
- package/package.json +12 -5
- package/.eslintrc.json +0 -714
- package/README.md +0 -39
- package/config/default.json +0 -769
- package/config/llwiki.json +0 -630
- package/config/moegirl.json +0 -727
- package/config/zhwiki.json +0 -1269
- package/errors/README +0 -1
- package/index.js +0 -245
- package/jsconfig.json +0 -7
- package/lib/element.js +0 -755
- package/lib/node.js +0 -585
- package/lib/ranges.js +0 -131
- package/lib/text.js +0 -146
- package/lib/title.js +0 -69
- package/mixin/attributeParent.js +0 -113
- package/mixin/fixedToken.js +0 -40
- package/mixin/hidden.js +0 -19
- package/mixin/sol.js +0 -59
- package/parser/brackets.js +0 -112
- package/parser/commentAndExt.js +0 -63
- package/parser/converter.js +0 -45
- package/parser/externalLinks.js +0 -31
- package/parser/hrAndDoubleUnderscore.js +0 -35
- package/parser/html.js +0 -42
- package/parser/links.js +0 -98
- package/parser/list.js +0 -59
- package/parser/magicLinks.js +0 -41
- package/parser/quotes.js +0 -64
- package/parser/selector.js +0 -175
- package/parser/table.js +0 -112
- package/printed/README +0 -1
- package/printed/example.json +0 -120
- package/src/arg.js +0 -169
- package/src/atom/hidden.js +0 -13
- package/src/atom/index.js +0 -41
- package/src/attribute.js +0 -422
- package/src/converter.js +0 -157
- package/src/converterFlags.js +0 -232
- package/src/converterRule.js +0 -253
- package/src/extLink.js +0 -167
- package/src/gallery.js +0 -91
- package/src/heading.js +0 -100
- package/src/html.js +0 -202
- package/src/imageParameter.js +0 -254
- package/src/index.js +0 -737
- package/src/link/category.js +0 -53
- package/src/link/file.js +0 -265
- package/src/link/galleryImage.js +0 -61
- package/src/link/index.js +0 -322
- package/src/magicLink.js +0 -108
- package/src/nowiki/comment.js +0 -57
- package/src/nowiki/dd.js +0 -59
- package/src/nowiki/doubleUnderscore.js +0 -51
- package/src/nowiki/hr.js +0 -41
- package/src/nowiki/index.js +0 -44
- package/src/nowiki/list.js +0 -16
- package/src/nowiki/noinclude.js +0 -28
- package/src/nowiki/quote.js +0 -36
- package/src/onlyinclude.js +0 -54
- package/src/parameter.js +0 -187
- package/src/syntax.js +0 -83
- package/src/table/index.js +0 -967
- package/src/table/td.js +0 -308
- package/src/table/tr.js +0 -282
- package/src/tagPair/ext.js +0 -105
- package/src/tagPair/include.js +0 -50
- package/src/tagPair/index.js +0 -117
- package/src/transclude.js +0 -703
- package/test/api.js +0 -83
- package/test/real.js +0 -133
- package/test/test.js +0 -28
- package/test/util.js +0 -80
- package/tool/index.js +0 -918
- package/typings/api.d.ts +0 -13
- package/typings/array.d.ts +0 -28
- package/typings/event.d.ts +0 -24
- package/typings/index.d.ts +0 -94
- package/typings/node.d.ts +0 -29
- package/typings/parser.d.ts +0 -16
- package/typings/table.d.ts +0 -14
- package/typings/token.d.ts +0 -22
- package/typings/tool.d.ts +0 -11
- package/util/debug.js +0 -73
- package/util/string.js +0 -88
package/lib/text.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const AstNode = require('./node'),
|
|
4
|
-
Parser = require('..');
|
|
5
|
-
|
|
6
|
-
/** 文本节点 */
|
|
7
|
-
class AstText extends AstNode {
|
|
8
|
-
type = 'text';
|
|
9
|
-
/** @type {string} */ data;
|
|
10
|
-
|
|
11
|
-
/** 文本长度 */
|
|
12
|
-
get length() {
|
|
13
|
-
return this.data.length;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** @param {string} text 包含文本 */
|
|
17
|
-
constructor(text = '') {
|
|
18
|
-
super();
|
|
19
|
-
Object.defineProperties(this, {
|
|
20
|
-
data: {value: text, writable: false},
|
|
21
|
-
childNodes: {enumerable: false, configurable: false},
|
|
22
|
-
type: {enumerable: false, writable: false, configurable: false},
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** 复制 */
|
|
27
|
-
cloneNode() {
|
|
28
|
-
return new AstText(this.data);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @override
|
|
33
|
-
* @template {string} T
|
|
34
|
-
* @param {T} key 属性键
|
|
35
|
-
* @returns {TokenAttribute<T>}
|
|
36
|
-
*/
|
|
37
|
-
getAttribute(key) {
|
|
38
|
-
return key === 'verifyChild'
|
|
39
|
-
? () => {
|
|
40
|
-
throw new Error('文本节点没有子节点!');
|
|
41
|
-
}
|
|
42
|
-
: super.getAttribute(key);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** 输出字符串 */
|
|
46
|
-
toString() {
|
|
47
|
-
return this.data;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** @override */
|
|
51
|
-
text() {
|
|
52
|
-
return this.data;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* 修改内容
|
|
57
|
-
* @param {string} text 新内容
|
|
58
|
-
*/
|
|
59
|
-
#setData(text) {
|
|
60
|
-
text = String(text);
|
|
61
|
-
const {data} = this,
|
|
62
|
-
e = new Event('text', {bubbles: true});
|
|
63
|
-
this.setAttribute('data', text);
|
|
64
|
-
if (data !== text) {
|
|
65
|
-
this.dispatchEvent(e, {oldText: data, newText: text});
|
|
66
|
-
}
|
|
67
|
-
return this;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* 在后方添加字符串
|
|
72
|
-
* @param {string} text 添加的字符串
|
|
73
|
-
* @throws `Error` 禁止外部调用
|
|
74
|
-
*/
|
|
75
|
-
appendData(text) {
|
|
76
|
-
this.#setData(this.data + text);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 删减字符串
|
|
81
|
-
* @param {number} offset 起始位置
|
|
82
|
-
* @param {number} count 删减字符数
|
|
83
|
-
* @throws `RangeError` 错误的删减位置
|
|
84
|
-
* @throws `Error` 禁止外部调用
|
|
85
|
-
*/
|
|
86
|
-
deleteData(offset, count) {
|
|
87
|
-
this.#setData(this.data.slice(0, offset) + this.data.slice(offset + count));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 插入字符串
|
|
92
|
-
* @param {number} offset 插入位置
|
|
93
|
-
* @param {string} text 待插入的字符串
|
|
94
|
-
* @throws `RangeError` 错误的插入位置
|
|
95
|
-
* @throws `Error` 禁止外部调用
|
|
96
|
-
*/
|
|
97
|
-
insertData(offset, text) {
|
|
98
|
-
this.#setData(this.data.slice(0, offset) + text + this.data.slice(offset));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* 替换字符串
|
|
103
|
-
* @param {string} text 替换的字符串
|
|
104
|
-
* @throws `Error` 禁止外部调用
|
|
105
|
-
*/
|
|
106
|
-
replaceData(text = '') {
|
|
107
|
-
this.#setData(text);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* 提取子串
|
|
112
|
-
* @param {number} offset 起始位置
|
|
113
|
-
* @param {number} count 字符数
|
|
114
|
-
*/
|
|
115
|
-
substringData(offset, count) {
|
|
116
|
-
return this.data.slice(offset, offset + count);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* 将文本子节点分裂为两部分
|
|
121
|
-
* @param {number} offset 分裂位置
|
|
122
|
-
* @throws `RangeError` 错误的断开位置
|
|
123
|
-
* @throws `Error` 没有父节点
|
|
124
|
-
*/
|
|
125
|
-
splitText(offset) {
|
|
126
|
-
if (typeof offset !== 'number') {
|
|
127
|
-
this.typeError('splitText', 'Number');
|
|
128
|
-
} else if (offset > this.length || offset < -this.length || !Number.isInteger(offset)) {
|
|
129
|
-
throw new RangeError(`错误的断开位置!${offset}`);
|
|
130
|
-
}
|
|
131
|
-
const {parentNode, data} = this;
|
|
132
|
-
if (!parentNode) {
|
|
133
|
-
throw new Error('待分裂的文本节点没有父节点!');
|
|
134
|
-
}
|
|
135
|
-
const newText = new AstText(data.slice(offset)),
|
|
136
|
-
childNodes = [...parentNode.childNodes];
|
|
137
|
-
this.setAttribute('data', data.slice(0, offset));
|
|
138
|
-
childNodes.splice(childNodes.indexOf(this) + 1, 0, newText);
|
|
139
|
-
newText.setAttribute('parentNode', parentNode);
|
|
140
|
-
parentNode.setAttribute('childNodes', childNodes);
|
|
141
|
-
return newText;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
Parser.classes.AstText = __filename;
|
|
146
|
-
module.exports = AstText;
|
package/lib/title.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..');
|
|
4
|
-
|
|
5
|
-
/** MediaWiki页面标题对象 */
|
|
6
|
-
class Title {
|
|
7
|
-
title = '';
|
|
8
|
-
main = '';
|
|
9
|
-
prefix = '';
|
|
10
|
-
ns = 0;
|
|
11
|
-
interwiki = '';
|
|
12
|
-
fragment = '';
|
|
13
|
-
valid = true;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {string} title 标题(含或不含命名空间前缀)
|
|
17
|
-
* @param {number} defaultNs 命名空间
|
|
18
|
-
*/
|
|
19
|
-
constructor(title, defaultNs = 0, config = Parser.getConfig()) {
|
|
20
|
-
const {namespaces, nsid} = config;
|
|
21
|
-
let namespace = namespaces[defaultNs];
|
|
22
|
-
title = title.replaceAll('_', ' ').trim();
|
|
23
|
-
if (title[0] === ':') {
|
|
24
|
-
namespace = '';
|
|
25
|
-
title = title.slice(1).trim();
|
|
26
|
-
}
|
|
27
|
-
const iw = defaultNs ? null : Parser.isInterwiki(title, config);
|
|
28
|
-
if (iw) {
|
|
29
|
-
this.interwiki = iw[1].toLowerCase();
|
|
30
|
-
title = title.slice(iw[0].length);
|
|
31
|
-
}
|
|
32
|
-
const m = title.split(':');
|
|
33
|
-
if (m.length > 1) {
|
|
34
|
-
const id = namespaces[nsid[m[0].trim().toLowerCase()]];
|
|
35
|
-
if (id !== undefined) {
|
|
36
|
-
namespace = id;
|
|
37
|
-
title = m.slice(1).join(':').trim();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
this.ns = nsid[namespace.toLowerCase()];
|
|
41
|
-
const i = title.indexOf('#');
|
|
42
|
-
if (i !== -1) {
|
|
43
|
-
const fragment = title.slice(i + 1).trimEnd();
|
|
44
|
-
if (fragment.includes('%')) {
|
|
45
|
-
try {
|
|
46
|
-
this.fragment = decodeURIComponent(fragment);
|
|
47
|
-
} catch {}
|
|
48
|
-
} else if (fragment.includes('.')) {
|
|
49
|
-
try {
|
|
50
|
-
this.fragment = decodeURIComponent(fragment.replaceAll('.', '%'));
|
|
51
|
-
} catch {}
|
|
52
|
-
}
|
|
53
|
-
this.fragment ||= fragment;
|
|
54
|
-
title = title.slice(0, i).trim();
|
|
55
|
-
}
|
|
56
|
-
this.main = title && `${title[0].toUpperCase()}${title.slice(1)}`;
|
|
57
|
-
this.prefix = `${namespace}${namespace && ':'}`;
|
|
58
|
-
this.title = `${iw ? `${this.interwiki}:` : ''}${this.prefix}${this.main}`;
|
|
59
|
-
this.valid = Boolean(this.main || this.fragment) && !/\0\d+[eh!+-]\x7F|[<>[\]{}|]/u.test(this.title);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** @override */
|
|
63
|
-
toString() {
|
|
64
|
-
return `${this.title}${this.fragment && '#'}${this.fragment}`;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
Parser.classes.Title = __filename;
|
|
69
|
-
module.exports = Title;
|
package/mixin/attributeParent.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..'),
|
|
4
|
-
AttributeToken = require('../src/attribute');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 子节点含有AttributeToken的类
|
|
8
|
-
* @template T
|
|
9
|
-
* @param {T} Constructor 基类
|
|
10
|
-
* @param {number} i AttributeToken子节点的位置
|
|
11
|
-
* @returns {T}
|
|
12
|
-
*/
|
|
13
|
-
const attributeParent = (Constructor, i = 0) => class extends Constructor {
|
|
14
|
-
/**
|
|
15
|
-
* getAttr()方法的getter写法
|
|
16
|
-
* @returns {Record<string, string|true>}
|
|
17
|
-
*/
|
|
18
|
-
get attributes() {
|
|
19
|
-
return this.getAttr();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** 以字符串表示的class属性 */
|
|
23
|
-
get className() {
|
|
24
|
-
const attr = this.getAttr('class');
|
|
25
|
-
return typeof attr === 'string' ? attr : '';
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
set className(className) {
|
|
29
|
-
this.setAttr('class', className);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** 以Set表示的class属性 */
|
|
33
|
-
get classList() {
|
|
34
|
-
return new Set(this.className.split(/\s/u));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** id属性 */
|
|
38
|
-
get id() {
|
|
39
|
-
const attr = this.getAttr('id');
|
|
40
|
-
return typeof attr === 'string' ? attr : '';
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
set id(id) {
|
|
44
|
-
this.setAttr('id', id);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* AttributeToken子节点是否具有某属性
|
|
49
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
50
|
-
* @param {string} key 属性键
|
|
51
|
-
*/
|
|
52
|
-
hasAttr(key) {
|
|
53
|
-
return this.childNodes.at(i).hasAttr(key);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 获取AttributeToken子节点的属性
|
|
58
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
59
|
-
* @template {string|undefined} T
|
|
60
|
-
* @param {T} key 属性键
|
|
61
|
-
*/
|
|
62
|
-
getAttr(key) {
|
|
63
|
-
return this.childNodes.at(i).getAttr(key);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* 列举AttributeToken子节点的属性键
|
|
68
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
69
|
-
*/
|
|
70
|
-
getAttrNames() {
|
|
71
|
-
return this.childNodes.at(i).getAttrNames();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* AttributeToken子节点是否具有任意属性
|
|
76
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
77
|
-
*/
|
|
78
|
-
hasAttrs() {
|
|
79
|
-
return this.childNodes.at(i).hasAttrs();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 对AttributeToken子节点设置属性
|
|
84
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
85
|
-
* @param {string} key 属性键
|
|
86
|
-
* @param {string|boolean} value 属性值
|
|
87
|
-
*/
|
|
88
|
-
setAttr(key, value) {
|
|
89
|
-
return this.childNodes.at(i).setAttr(key, value);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 移除AttributeToken子节点的某属性
|
|
94
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
95
|
-
* @param {string} key 属性键
|
|
96
|
-
*/
|
|
97
|
-
removeAttr(key) {
|
|
98
|
-
this.childNodes.at(i).removeAttr(key);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* 开关AttributeToken子节点的某属性
|
|
103
|
-
* @this {{childNodes: AttributeToken[]}}
|
|
104
|
-
* @param {string} key 属性键
|
|
105
|
-
* @param {boolean|undefined} force 强制开启或关闭
|
|
106
|
-
*/
|
|
107
|
-
toggleAttr(key, force) {
|
|
108
|
-
this.childNodes.at(i).toggleAttr(key, force);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
Parser.mixins.attributeParent = __filename;
|
|
113
|
-
module.exports = attributeParent;
|
package/mixin/fixedToken.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..'),
|
|
4
|
-
Token = require('../src');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 不可增删子节点的类
|
|
8
|
-
* @template T
|
|
9
|
-
* @param {T} Constructor 基类
|
|
10
|
-
* @returns {T}
|
|
11
|
-
*/
|
|
12
|
-
const fixedToken = Constructor => class extends Constructor {
|
|
13
|
-
static fixed = true;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 移除子节点
|
|
17
|
-
* @throws `Error`
|
|
18
|
-
*/
|
|
19
|
-
removeAt() {
|
|
20
|
-
throw new Error(`${this.constructor.name} 不可删除元素!`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 插入子节点
|
|
25
|
-
* @template {Token} T
|
|
26
|
-
* @param {T} token 待插入的子节点
|
|
27
|
-
* @param {number} i 插入位置
|
|
28
|
-
* @throws `Error`
|
|
29
|
-
*/
|
|
30
|
-
insertAt(token, i = this.childNodes.length) {
|
|
31
|
-
if (!Parser.running) {
|
|
32
|
-
throw new Error(`${this.constructor.name} 不可插入元素!`);
|
|
33
|
-
}
|
|
34
|
-
super.insertAt(token, i);
|
|
35
|
-
return token;
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
Parser.mixins.fixedToken = __filename;
|
|
40
|
-
module.exports = fixedToken;
|
package/mixin/hidden.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 解析后不可见的类
|
|
7
|
-
* @template T
|
|
8
|
-
* @param {T} Constructor 基类
|
|
9
|
-
* @returns {T}
|
|
10
|
-
*/
|
|
11
|
-
const hidden = Constructor => class extends Constructor {
|
|
12
|
-
/** 没有可见部分 */
|
|
13
|
-
text() { // eslint-disable-line class-methods-use-this
|
|
14
|
-
return '';
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
Parser.mixins.hidden = __filename;
|
|
19
|
-
module.exports = hidden;
|
package/mixin/sol.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..'),
|
|
4
|
-
Token = require('../src');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 只能位于行首的类
|
|
8
|
-
* @template T
|
|
9
|
-
* @param {T} Constructor 基类
|
|
10
|
-
* @returns {T}
|
|
11
|
-
*/
|
|
12
|
-
const sol = Constructor => class extends Constructor {
|
|
13
|
-
/**
|
|
14
|
-
* 在前方插入newline
|
|
15
|
-
* @this {Token}
|
|
16
|
-
*/
|
|
17
|
-
prependNewLine() {
|
|
18
|
-
const {previousVisibleSibling = '', parentNode} = this;
|
|
19
|
-
return (previousVisibleSibling || parentNode?.type !== 'root') && String(previousVisibleSibling).at(-1) !== '\n'
|
|
20
|
-
? '\n'
|
|
21
|
-
: '';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 在后方插入newline
|
|
26
|
-
* @this {Token}
|
|
27
|
-
*/
|
|
28
|
-
appendNewLine() {
|
|
29
|
-
const {nextVisibleSibling = '', parentNode} = this;
|
|
30
|
-
return (nextVisibleSibling || parentNode?.type !== 'root') && String(nextVisibleSibling ?? '')[0] !== '\n'
|
|
31
|
-
? '\n'
|
|
32
|
-
: '';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 还原为wikitext
|
|
37
|
-
* @param {string} selector
|
|
38
|
-
* @param {boolean} ownLine 是否独占一行
|
|
39
|
-
*/
|
|
40
|
-
toString(selector, ownLine) {
|
|
41
|
-
return `${this.prependNewLine()}${super.toString(selector)}${ownLine ? this.appendNewLine() : ''}`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** 获取padding */
|
|
45
|
-
getPadding() {
|
|
46
|
-
return this.prependNewLine().length;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 可见部分
|
|
51
|
-
* @param {booean} ownLine 是否独占一行
|
|
52
|
-
*/
|
|
53
|
-
text(ownLine) {
|
|
54
|
-
return `${this.prependNewLine()}${super.text()}${ownLine ? this.appendNewLine() : ''}`;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
Parser.mixins.sol = __filename;
|
|
59
|
-
module.exports = sol;
|
package/parser/brackets.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const {removeComment} = require('../util/string'),
|
|
4
|
-
Parser = require('..');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 解析花括号
|
|
8
|
-
* @param {string} text wikitext
|
|
9
|
-
* @param {accum} accum
|
|
10
|
-
* @throws TranscludeToken.constructor()
|
|
11
|
-
*/
|
|
12
|
-
const parseBrackets = (text, config = Parser.getConfig(), accum = []) => {
|
|
13
|
-
const source = '^(\0\\d+c\x7F)*={1,6}|\\[\\[|\\{{2,}|-\\{(?!\\{)',
|
|
14
|
-
/** @type {BracketExecArray[]} */ stack = [],
|
|
15
|
-
closes = {'=': '\n', '{': '\\}{2,}|\\|', '-': '\\}-', '[': '\\]\\]'},
|
|
16
|
-
/** @type {Record<string, string>} */ marks = {'!': '!', '!!': '+', '(!': '{', '!)': '}', '!-': '-', '=': '~'};
|
|
17
|
-
let regex = new RegExp(source, 'gmu'),
|
|
18
|
-
/** @type {BracketExecArray} */ mt = regex.exec(text),
|
|
19
|
-
moreBraces = text.includes('}}'),
|
|
20
|
-
lastIndex;
|
|
21
|
-
while (mt || lastIndex <= text.length && stack.at(-1)?.[0]?.[0] === '=') {
|
|
22
|
-
if (mt?.[1]) {
|
|
23
|
-
const [, {length}] = mt;
|
|
24
|
-
mt[0] = mt[0].slice(length);
|
|
25
|
-
mt.index += length;
|
|
26
|
-
}
|
|
27
|
-
const {0: syntax, index: curIndex} = mt ?? {0: '\n', index: text.length},
|
|
28
|
-
/** @type {BracketExecArray} */ top = stack.pop() ?? {},
|
|
29
|
-
{0: open, index, parts, findEqual: topFindEqual, pos: topPos} = top,
|
|
30
|
-
innerEqual = syntax === '=' && topFindEqual;
|
|
31
|
-
if (syntax === ']]' || syntax === '}-') { // 情形1:闭合内链或转换
|
|
32
|
-
lastIndex = curIndex + 2;
|
|
33
|
-
} else if (syntax === '\n') { // 情形2:闭合标题
|
|
34
|
-
lastIndex = curIndex + 1;
|
|
35
|
-
const {pos, findEqual} = stack.at(-1) ?? {};
|
|
36
|
-
if (!pos || findEqual || removeComment(text.slice(pos, index)) !== '') {
|
|
37
|
-
const rmt = /^(={1,6})(.+)\1((?:\s|\0\d+c\x7F)*)$/u.exec(text.slice(index, curIndex));
|
|
38
|
-
if (rmt) {
|
|
39
|
-
text = `${text.slice(0, index)}\0${accum.length}h\x7F${text.slice(curIndex)}`;
|
|
40
|
-
lastIndex = index + 4 + String(accum.length).length;
|
|
41
|
-
const HeadingToken = require('../src/heading');
|
|
42
|
-
new HeadingToken(rmt[1].length, rmt.slice(2), config, accum);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
} else if (syntax === '|' || innerEqual) { // 情形3:模板内部,含行首单个'='
|
|
46
|
-
lastIndex = curIndex + 1;
|
|
47
|
-
parts.at(-1).push(text.slice(topPos, curIndex));
|
|
48
|
-
if (syntax === '|') {
|
|
49
|
-
parts.push([]);
|
|
50
|
-
}
|
|
51
|
-
top.pos = lastIndex;
|
|
52
|
-
top.findEqual = syntax === '|';
|
|
53
|
-
stack.push(top);
|
|
54
|
-
} else if (syntax.startsWith('}}')) { // 情形4:闭合模板
|
|
55
|
-
const close = syntax.slice(0, Math.min(open.length, 3)),
|
|
56
|
-
rest = open.length - close.length,
|
|
57
|
-
{length} = accum;
|
|
58
|
-
lastIndex = curIndex + close.length; // 这不是最终的lastIndex
|
|
59
|
-
parts.at(-1).push(text.slice(topPos, curIndex));
|
|
60
|
-
const ch = close.length === 2 ? marks[removeComment(parts[0][0])] ?? 't' : 't'; // 标记{{!}}等
|
|
61
|
-
let skip = false;
|
|
62
|
-
if (close.length === 3) {
|
|
63
|
-
const ArgToken = require('../src/arg');
|
|
64
|
-
new ArgToken(parts.map(part => part.join('=')), config, accum);
|
|
65
|
-
} else {
|
|
66
|
-
try {
|
|
67
|
-
const TranscludeToken = require('../src/transclude');
|
|
68
|
-
new TranscludeToken(parts[0][0], parts.slice(1), config, accum);
|
|
69
|
-
} catch (e) {
|
|
70
|
-
if (e instanceof Error && e.message.startsWith('非法的模板名称:')) {
|
|
71
|
-
lastIndex = index + open.length;
|
|
72
|
-
skip = true;
|
|
73
|
-
} else {
|
|
74
|
-
throw e;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (!skip) {
|
|
79
|
-
text = `${text.slice(0, index + rest)}\0${length}${ch}\x7F${text.slice(lastIndex)}`;
|
|
80
|
-
lastIndex = index + rest + 3 + String(length).length;
|
|
81
|
-
if (rest > 1) {
|
|
82
|
-
stack.push({0: open.slice(0, rest), index, pos: index + rest, parts: [[]]});
|
|
83
|
-
} else if (rest === 1 && text[index - 1] === '-') {
|
|
84
|
-
stack.push({0: '-{', index: index - 1, pos: index + 1, parts: [[]]});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
} else { // 情形5:开启
|
|
88
|
-
lastIndex = curIndex + syntax.length;
|
|
89
|
-
if (syntax[0] === '{') {
|
|
90
|
-
mt.pos = lastIndex;
|
|
91
|
-
mt.parts = [[]];
|
|
92
|
-
}
|
|
93
|
-
stack.push(...'0' in top ? [top] : [], mt);
|
|
94
|
-
}
|
|
95
|
-
moreBraces &&= text.slice(lastIndex).includes('}}');
|
|
96
|
-
let curTop = stack.at(-1);
|
|
97
|
-
if (!moreBraces && curTop?.[0]?.[0] === '{') {
|
|
98
|
-
stack.pop();
|
|
99
|
-
curTop = stack.at(-1);
|
|
100
|
-
}
|
|
101
|
-
regex = new RegExp(source + (curTop
|
|
102
|
-
? `|${closes[curTop[0][0]]}${curTop.findEqual ? '|=' : ''}`
|
|
103
|
-
: ''
|
|
104
|
-
), 'gmu');
|
|
105
|
-
regex.lastIndex = lastIndex;
|
|
106
|
-
mt = regex.exec(text);
|
|
107
|
-
}
|
|
108
|
-
return text;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
Parser.parsers.parseBrackets = __filename;
|
|
112
|
-
module.exports = parseBrackets;
|
package/parser/commentAndExt.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 解析HTML注释和扩展标签
|
|
7
|
-
* @param {string} text wikitext
|
|
8
|
-
* @param {accum} accum
|
|
9
|
-
* @param {boolean} includeOnly 是否嵌入
|
|
10
|
-
*/
|
|
11
|
-
const parseCommentAndExt = (text, config = Parser.getConfig(), accum = [], includeOnly = false) => {
|
|
12
|
-
const onlyinclude = /<onlyinclude>(.*?)<\/onlyinclude>/gsu;
|
|
13
|
-
if (includeOnly && text.search(onlyinclude) !== -1) { // `<onlyinclude>`拥有最高优先级
|
|
14
|
-
return text.replaceAll(onlyinclude, /** @param {string} inner */ (_, inner) => {
|
|
15
|
-
const str = `\0${accum.length}e\x7F`;
|
|
16
|
-
const OnlyincludeToken = require('../src/onlyinclude');
|
|
17
|
-
new OnlyincludeToken(inner, config, accum);
|
|
18
|
-
return str;
|
|
19
|
-
}).replaceAll(/(?<=^|\0\d+e\x7F).*?(?=$|\0\d+e\x7F)/gsu, substr => {
|
|
20
|
-
if (substr === '') {
|
|
21
|
-
return '';
|
|
22
|
-
}
|
|
23
|
-
const NoincludeToken = require('../src/nowiki/noinclude');
|
|
24
|
-
new NoincludeToken(substr, config, accum);
|
|
25
|
-
return `\0${accum.length - 1}c\x7F`;
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
const ext = config.ext.join('|'),
|
|
29
|
-
includeRegex = includeOnly ? 'includeonly' : '(?:no|only)include',
|
|
30
|
-
noincludeRegex = includeOnly ? 'noinclude' : 'includeonly',
|
|
31
|
-
regex = new RegExp(
|
|
32
|
-
'<!--.*?(?:-->|$)|' // comment
|
|
33
|
-
+ `<${includeRegex}(?:\\s[^>]*?)?>|</${includeRegex}\\s*>|` // <includeonly>
|
|
34
|
-
+ `<(${ext})(\\s[^>]*?)?(?:/>|>(.*?)</(\\1\\s*)>)|` // 扩展标签
|
|
35
|
-
+ `<(${noincludeRegex})(\\s[^>]*?)?(?:/>|>(.*?)(?:</(\\5\\s*)>|$))`, // <noinclude>
|
|
36
|
-
'gisu',
|
|
37
|
-
);
|
|
38
|
-
return text.replace(
|
|
39
|
-
regex,
|
|
40
|
-
/** @type {function(...string): string} */
|
|
41
|
-
(substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
|
|
42
|
-
const str = `\0${accum.length}${name ? 'e' : 'c'}\x7F`;
|
|
43
|
-
if (name) {
|
|
44
|
-
const ExtToken = require('../src/tagPair/ext');
|
|
45
|
-
new ExtToken(name, attr, inner, closing, config, accum);
|
|
46
|
-
} else if (substr.startsWith('<!--')) {
|
|
47
|
-
const CommentToken = require('../src/nowiki/comment');
|
|
48
|
-
const closed = substr.endsWith('-->');
|
|
49
|
-
new CommentToken(substr.slice(4, closed ? -3 : undefined), closed, config, accum);
|
|
50
|
-
} else if (include) {
|
|
51
|
-
const IncludeToken = require('../src/tagPair/include');
|
|
52
|
-
new IncludeToken(include, includeAttr, includeInner, includeClosing, config, accum);
|
|
53
|
-
} else {
|
|
54
|
-
const NoincludeToken = require('../src/nowiki/noinclude');
|
|
55
|
-
new NoincludeToken(substr, config, accum);
|
|
56
|
-
}
|
|
57
|
-
return str;
|
|
58
|
-
},
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
Parser.parsers.parseCommentAndExt = __filename;
|
|
63
|
-
module.exports = parseCommentAndExt;
|
package/parser/converter.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Parser = require('..');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 解析语言变体转换
|
|
7
|
-
* @param {string} wikitext wikitext
|
|
8
|
-
* @param {accum} accum
|
|
9
|
-
*/
|
|
10
|
-
const parseConverter = (wikitext, config = Parser.getConfig(), accum = []) => {
|
|
11
|
-
const ConverterToken = require('../src/converter');
|
|
12
|
-
const regex1 = /-\{/gu,
|
|
13
|
-
regex2 = /-\{|\}-/gu,
|
|
14
|
-
/** @type {RegExpExecArray[]} */ stack = [];
|
|
15
|
-
let regex = regex1,
|
|
16
|
-
mt = regex.exec(wikitext);
|
|
17
|
-
while (mt) {
|
|
18
|
-
const {0: syntax, index} = mt;
|
|
19
|
-
if (syntax === '}-') {
|
|
20
|
-
const top = stack.pop(),
|
|
21
|
-
{length} = accum,
|
|
22
|
-
str = wikitext.slice(top.index + 2, index),
|
|
23
|
-
i = str.indexOf('|'),
|
|
24
|
-
[flags, text] = i === -1 ? [[], str] : [str.slice(0, i).split(';'), str.slice(i + 1)],
|
|
25
|
-
temp = text.replace(/(&[#a-z\d]+);/iu, '$1\x01'),
|
|
26
|
-
variants = `(?:${config.variants.join('|')})`,
|
|
27
|
-
rules = temp.split(new RegExp(`;(?=\\s*(?:${variants}|[^;]*?=>\\s*${variants})\\s*:)`, 'u'))
|
|
28
|
-
.map(rule => rule.replaceAll('\x01', ';'));
|
|
29
|
-
new ConverterToken(flags, rules, config, accum);
|
|
30
|
-
wikitext = `${wikitext.slice(0, top.index)}\0${length}v\x7F${wikitext.slice(index + 2)}`;
|
|
31
|
-
if (stack.length === 0) {
|
|
32
|
-
regex = regex1;
|
|
33
|
-
}
|
|
34
|
-
regex.lastIndex = top.index + 3 + String(length).length;
|
|
35
|
-
} else {
|
|
36
|
-
stack.push(mt);
|
|
37
|
-
regex = regex2;
|
|
38
|
-
}
|
|
39
|
-
mt = regex.exec(wikitext);
|
|
40
|
-
}
|
|
41
|
-
return wikitext;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
Parser.parsers.parseConverter = __filename;
|
|
45
|
-
module.exports = parseConverter;
|
package/parser/externalLinks.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const {extUrlChar} = require('../util/string'),
|
|
4
|
-
Parser = require('..');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 解析外部链接
|
|
8
|
-
* @param {string} wikitext wikitext
|
|
9
|
-
* @param {accum} accum
|
|
10
|
-
*/
|
|
11
|
-
const parseExternalLinks = (wikitext, config = Parser.getConfig(), accum = []) => {
|
|
12
|
-
const ExtLinkToken = require('../src/extLink');
|
|
13
|
-
const regex = new RegExp(
|
|
14
|
-
`\\[((?:${config.protocol}|//)${extUrlChar})(\\p{Zs}*)([^\\]\x01-\x08\x0A-\x1F\uFFFD]*)\\]`,
|
|
15
|
-
'giu',
|
|
16
|
-
);
|
|
17
|
-
return wikitext.replace(regex, /** @type {function(...string): string} */ (_, url, space, text) => {
|
|
18
|
-
const {length} = accum,
|
|
19
|
-
mt = /&[lg]t;/u.exec(url);
|
|
20
|
-
if (mt) {
|
|
21
|
-
url = url.slice(0, mt.index);
|
|
22
|
-
space = '';
|
|
23
|
-
text = `${url.slice(mt.index)}${space}${text}`;
|
|
24
|
-
}
|
|
25
|
-
new ExtLinkToken(url, space, text, config, accum);
|
|
26
|
-
return `\0${length}w\x7F`;
|
|
27
|
-
});
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
Parser.parsers.parseExternalLinks = __filename;
|
|
31
|
-
module.exports = parseExternalLinks;
|