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/table/tr.js
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const {generateForChild} = require('../../util/lint'),
|
|
4
|
+
attributeParent = require('../../mixin/attributeParent'),
|
|
5
|
+
Parser = require('../..'),
|
|
6
|
+
AstText = require('../../lib/text'),
|
|
5
7
|
Token = require('..'),
|
|
6
8
|
SyntaxToken = require('../syntax'),
|
|
7
9
|
AttributeToken = require('../attribute');
|
|
8
10
|
|
|
11
|
+
const openingPattern = /^\n[^\S\n]*(?:\|-+|\{\{\s*!\s*\}\}-+|\{\{\s*!-\s*\}\}-*)$/u;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 转义表格语法
|
|
15
|
+
* @param {SyntaxToken} syntax 表格语法节点
|
|
16
|
+
*/
|
|
17
|
+
const escapeTable = syntax => {
|
|
18
|
+
const templates = {'{|': '(!', '|}': '!)', '||': '!!', '|': '!'},
|
|
19
|
+
wikitext = syntax.childNodes.map(
|
|
20
|
+
child => child.type === 'text'
|
|
21
|
+
? String(child).replaceAll(/\{\||\|\}|\|{2}|\|/gu, p => `{{${templates[p]}}}`)
|
|
22
|
+
: String(child),
|
|
23
|
+
).join(''),
|
|
24
|
+
token = Parser.parse(wikitext, syntax.getAttribute('include'), 2, syntax.getAttribute('config'));
|
|
25
|
+
syntax.replaceChildren(...token.childNodes);
|
|
26
|
+
};
|
|
27
|
+
|
|
9
28
|
/**
|
|
10
29
|
* 表格行,含开头的换行,不含结尾的换行
|
|
11
30
|
* @classdesc `{childNodes: [SyntaxToken, AttributeToken, ?Token, ...TdToken]}`
|
|
@@ -13,13 +32,13 @@ const attributeParent = require('../../mixin/attributeParent'),
|
|
|
13
32
|
class TrToken extends attributeParent(Token, 1) {
|
|
14
33
|
type = 'tr';
|
|
15
34
|
|
|
16
|
-
static openingPattern = /^\n[^\S\n]*(?:\|-+|\{\{\s*!\s*\}\}-+|\{\{\s*!-\s*\}\}-*)$/;
|
|
17
|
-
|
|
18
35
|
/**
|
|
19
|
-
* @param {string} syntax
|
|
36
|
+
* @param {string} syntax 表格语法
|
|
37
|
+
* @param {string} attr 表格属性
|
|
20
38
|
* @param {accum} accum
|
|
39
|
+
* @param {RegExp} pattern 表格语法正则
|
|
21
40
|
*/
|
|
22
|
-
constructor(syntax, attr = '', config = Parser.getConfig(), accum = [], pattern =
|
|
41
|
+
constructor(syntax, attr = '', config = Parser.getConfig(), accum = [], pattern = openingPattern) {
|
|
23
42
|
super(undefined, config, true, accum, {Token: 2, SyntaxToken: 0, AttributeToken: 1, TdToken: '2:'});
|
|
24
43
|
this.append(
|
|
25
44
|
new SyntaxToken(syntax, pattern, 'table-syntax', config, accum, {
|
|
@@ -27,18 +46,38 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
27
46
|
}),
|
|
28
47
|
new AttributeToken(attr, 'table-attr', 'tr', config, accum),
|
|
29
48
|
);
|
|
30
|
-
this.protectChildren(0, 1);
|
|
49
|
+
this.getAttribute('protectChildren')(0, 1);
|
|
31
50
|
}
|
|
32
51
|
|
|
52
|
+
/**
|
|
53
|
+
* @override
|
|
54
|
+
* @param {number} start 起始位置
|
|
55
|
+
*/
|
|
56
|
+
lint(start = 0) {
|
|
57
|
+
const errors = super.lint(start),
|
|
58
|
+
inter = this.childNodes.find(({type}) => type === 'table-inter'),
|
|
59
|
+
str = String(inter).trim();
|
|
60
|
+
if (inter && str && !/^<!--.*-->$/u.test(str)) {
|
|
61
|
+
const error = generateForChild(inter, this.getRootNode().posFromIndex(start), '将被移出表格的内容');
|
|
62
|
+
error.startLine++;
|
|
63
|
+
error.startCol = 0;
|
|
64
|
+
errors.push(error);
|
|
65
|
+
}
|
|
66
|
+
return errors;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @override
|
|
71
|
+
* @this {TrToken & {constructor: typeof TrToken}}
|
|
72
|
+
*/
|
|
33
73
|
cloneNode() {
|
|
34
|
-
const [syntax, attr, inner, ...cloned] = this.
|
|
35
|
-
/** @type {typeof TrToken} */ Constructor = this.constructor;
|
|
74
|
+
const [syntax, attr, inner, ...cloned] = this.cloneChildNodes();
|
|
36
75
|
return Parser.run(() => {
|
|
37
|
-
const token = new
|
|
38
|
-
token.
|
|
39
|
-
token.
|
|
76
|
+
const token = new this.constructor(undefined, undefined, this.getAttribute('config'));
|
|
77
|
+
token.firstChild.safeReplaceWith(syntax);
|
|
78
|
+
token.childNodes[1].safeReplaceWith(attr);
|
|
40
79
|
if (token.type === 'td') { // TdToken
|
|
41
|
-
token.
|
|
80
|
+
token.childNodes[2].safeReplaceWith(inner);
|
|
42
81
|
} else if (inner !== undefined) {
|
|
43
82
|
token.appendChild(inner);
|
|
44
83
|
}
|
|
@@ -47,79 +86,84 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
47
86
|
});
|
|
48
87
|
}
|
|
49
88
|
|
|
89
|
+
/** 修复简单的表格语法错误 */
|
|
50
90
|
#correct() {
|
|
51
|
-
const [,, child] = this
|
|
91
|
+
const {childNodes: [,, child]} = this;
|
|
52
92
|
if (child?.isPlain()) {
|
|
53
|
-
const {firstChild} = child;
|
|
54
|
-
if (
|
|
93
|
+
const /** @type {{firstChild: AstText}} */ {firstChild} = child;
|
|
94
|
+
if (firstChild.type !== 'text') {
|
|
55
95
|
child.prepend('\n');
|
|
56
|
-
} else if (
|
|
57
|
-
|
|
96
|
+
} else if (firstChild.data[0] !== '\n') {
|
|
97
|
+
firstChild.insertData(0, '\n');
|
|
58
98
|
}
|
|
59
99
|
}
|
|
60
100
|
}
|
|
61
101
|
|
|
62
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @override
|
|
104
|
+
* @param {string} selector
|
|
105
|
+
*/
|
|
106
|
+
toString(selector) {
|
|
63
107
|
this.#correct();
|
|
64
|
-
return super.toString();
|
|
108
|
+
return super.toString(selector);
|
|
65
109
|
}
|
|
66
110
|
|
|
111
|
+
/** @override */
|
|
67
112
|
text() {
|
|
68
113
|
this.#correct();
|
|
69
114
|
const str = super.text();
|
|
70
115
|
return this.type === 'tr' && !str.trim().includes('\n') ? '' : str;
|
|
71
116
|
}
|
|
72
117
|
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.replaceAll('|', '{{!}}')
|
|
78
|
-
: child.toString(),
|
|
79
|
-
).join(''),
|
|
80
|
-
token = Parser.parse(wikitext, syntax.getAttribute('include'), 2, syntax.getAttribute('config'));
|
|
81
|
-
syntax.replaceChildren(...token.childNodes);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** @complexity `n` */
|
|
118
|
+
/**
|
|
119
|
+
* 转义表格语法
|
|
120
|
+
* @complexity `n`
|
|
121
|
+
*/
|
|
85
122
|
escape() {
|
|
86
|
-
for (const child of this.
|
|
123
|
+
for (const child of this.childNodes) {
|
|
87
124
|
if (child instanceof SyntaxToken) {
|
|
88
|
-
|
|
125
|
+
escapeTable(child);
|
|
89
126
|
} else if (child instanceof TrToken) {
|
|
90
127
|
child.escape();
|
|
91
128
|
}
|
|
92
129
|
}
|
|
93
130
|
}
|
|
94
131
|
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
132
|
+
/**
|
|
133
|
+
* 设置表格语法
|
|
134
|
+
* @param {string} syntax 表格语法
|
|
135
|
+
* @param {boolean} esc 是否需要转义
|
|
136
|
+
*/
|
|
137
|
+
setSyntax(syntax, esc) {
|
|
138
|
+
const {firstChild} = this;
|
|
139
|
+
firstChild.replaceChildren(syntax);
|
|
99
140
|
if (esc) {
|
|
100
|
-
|
|
141
|
+
escapeTable(firstChild);
|
|
101
142
|
}
|
|
102
143
|
}
|
|
103
144
|
|
|
104
145
|
/**
|
|
105
|
-
* @
|
|
146
|
+
* @override
|
|
147
|
+
* @param {number} i 移除位置
|
|
106
148
|
* @complexity `n`
|
|
107
149
|
*/
|
|
108
150
|
removeAt(i) {
|
|
109
|
-
const TdToken = require('./td')
|
|
110
|
-
|
|
151
|
+
const TdToken = require('./td');
|
|
152
|
+
const child = this.childNodes.at(i);
|
|
111
153
|
if (child instanceof TdToken && child.isIndependent()) {
|
|
112
|
-
const {
|
|
113
|
-
if (
|
|
114
|
-
|
|
154
|
+
const {nextSibling} = child;
|
|
155
|
+
if (nextSibling?.type === 'td') {
|
|
156
|
+
nextSibling.independence();
|
|
115
157
|
}
|
|
116
158
|
}
|
|
117
159
|
return super.removeAt(i);
|
|
118
160
|
}
|
|
119
161
|
|
|
120
162
|
/**
|
|
121
|
-
* @
|
|
122
|
-
* @
|
|
163
|
+
* @override
|
|
164
|
+
* @template {AstText|Token} T
|
|
165
|
+
* @param {T} token 待插入的子节点
|
|
166
|
+
* @param {number} i 插入位置
|
|
123
167
|
* @returns {T}
|
|
124
168
|
* @complexity `n`
|
|
125
169
|
*/
|
|
@@ -127,8 +171,8 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
127
171
|
if (!Parser.running && !(token instanceof TrToken)) {
|
|
128
172
|
this.typeError('insertAt', 'TrToken');
|
|
129
173
|
}
|
|
130
|
-
const TdToken = require('./td')
|
|
131
|
-
|
|
174
|
+
const TdToken = require('./td');
|
|
175
|
+
const child = this.childNodes.at(i);
|
|
132
176
|
if (token instanceof TdToken && token.isIndependent() && child instanceof TdToken) {
|
|
133
177
|
child.independence();
|
|
134
178
|
}
|
|
@@ -136,50 +180,62 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
136
180
|
}
|
|
137
181
|
|
|
138
182
|
/**
|
|
183
|
+
* 获取行数
|
|
139
184
|
* @returns {0|1}
|
|
140
185
|
* @complexity `n`
|
|
141
186
|
*/
|
|
142
187
|
getRowCount() {
|
|
143
188
|
const TdToken = require('./td');
|
|
144
|
-
return Number(this.
|
|
145
|
-
child instanceof TdToken && child.isIndependent() &&
|
|
189
|
+
return Number(this.childNodes.some(
|
|
190
|
+
child => child instanceof TdToken && child.isIndependent() && child.firstChild.text().at(-1) !== '+',
|
|
146
191
|
));
|
|
147
192
|
}
|
|
148
193
|
|
|
149
194
|
/**
|
|
150
|
-
*
|
|
195
|
+
* 获取相邻行
|
|
196
|
+
* @param {(childNodes: Token[], index: number) => Token[]} subset 筛选兄弟节点的方法
|
|
151
197
|
* @complexity `n`
|
|
152
198
|
*/
|
|
153
199
|
#getSiblingRow(subset) {
|
|
154
|
-
const {
|
|
155
|
-
if (!
|
|
156
|
-
return;
|
|
200
|
+
const {parentNode} = this;
|
|
201
|
+
if (!parentNode) {
|
|
202
|
+
return undefined;
|
|
157
203
|
}
|
|
158
|
-
const {
|
|
159
|
-
index =
|
|
160
|
-
for (const child of subset(
|
|
204
|
+
const {childNodes} = parentNode,
|
|
205
|
+
index = childNodes.indexOf(this);
|
|
206
|
+
for (const child of subset(childNodes, index)) {
|
|
161
207
|
if (child instanceof TrToken && child.getRowCount()) {
|
|
162
208
|
return child;
|
|
163
209
|
}
|
|
164
210
|
}
|
|
211
|
+
return undefined;
|
|
165
212
|
}
|
|
166
213
|
|
|
167
|
-
/**
|
|
214
|
+
/**
|
|
215
|
+
* 获取下一行
|
|
216
|
+
* @complexity `n`
|
|
217
|
+
*/
|
|
168
218
|
getNextRow() {
|
|
169
|
-
return this.#getSiblingRow((
|
|
219
|
+
return this.#getSiblingRow((childNodes, index) => childNodes.slice(index + 1));
|
|
170
220
|
}
|
|
171
221
|
|
|
172
|
-
/**
|
|
222
|
+
/**
|
|
223
|
+
* 获取前一行
|
|
224
|
+
* @complexity `n`
|
|
225
|
+
*/
|
|
173
226
|
getPreviousRow() {
|
|
174
|
-
return this.#getSiblingRow((
|
|
227
|
+
return this.#getSiblingRow((childNodes, index) => childNodes.slice(0, index).reverse());
|
|
175
228
|
}
|
|
176
229
|
|
|
177
|
-
/**
|
|
230
|
+
/**
|
|
231
|
+
* 获取列数
|
|
232
|
+
* @complexity `n`
|
|
233
|
+
*/
|
|
178
234
|
getColCount() {
|
|
179
235
|
const TdToken = require('./td');
|
|
180
236
|
let count = 0,
|
|
181
237
|
last = 0;
|
|
182
|
-
for (const child of this.
|
|
238
|
+
for (const child of this.childNodes) {
|
|
183
239
|
if (child instanceof TdToken) {
|
|
184
240
|
last = child.isIndependent() ? Number(child.subtype !== 'caption') : last;
|
|
185
241
|
count += last;
|
|
@@ -189,11 +245,14 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
189
245
|
}
|
|
190
246
|
|
|
191
247
|
/**
|
|
192
|
-
*
|
|
248
|
+
* 获取第n列
|
|
249
|
+
* @param {number} n 列号
|
|
250
|
+
* @param {boolean} insert 是否用于判断插入新列的位置
|
|
193
251
|
* @returns {TdToken}
|
|
194
252
|
* @complexity `n`
|
|
253
|
+
* @throws `RangeError` 不存在对应单元格
|
|
195
254
|
*/
|
|
196
|
-
getNthCol(n, insert
|
|
255
|
+
getNthCol(n, insert) {
|
|
197
256
|
if (typeof n !== 'number') {
|
|
198
257
|
this.typeError('getNthCol', 'Number');
|
|
199
258
|
}
|
|
@@ -204,7 +263,7 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
204
263
|
}
|
|
205
264
|
const TdToken = require('./td');
|
|
206
265
|
let last = 0;
|
|
207
|
-
for (const child of this.
|
|
266
|
+
for (const child of this.childNodes.slice(2)) {
|
|
208
267
|
if (child instanceof TdToken) {
|
|
209
268
|
if (child.isIndependent()) {
|
|
210
269
|
last = Number(child.subtype !== 'caption');
|
|
@@ -213,23 +272,25 @@ class TrToken extends attributeParent(Token, 1) {
|
|
|
213
272
|
if (n < 0) {
|
|
214
273
|
return child;
|
|
215
274
|
}
|
|
216
|
-
} else if (
|
|
275
|
+
} else if (child.type === 'tr' || child.type === 'table-syntax') {
|
|
217
276
|
return child;
|
|
218
277
|
}
|
|
219
278
|
}
|
|
279
|
+
return undefined;
|
|
220
280
|
}
|
|
221
281
|
|
|
222
282
|
/**
|
|
223
|
-
*
|
|
224
|
-
* @param {
|
|
225
|
-
* @param {
|
|
226
|
-
* @param {
|
|
283
|
+
* 插入新的单元格
|
|
284
|
+
* @param {string|Token} inner 单元格内部wikitext
|
|
285
|
+
* @param {TableCoords} coord 单元格坐标
|
|
286
|
+
* @param {'td'|'th'|'caption'} subtype 单元格类型
|
|
287
|
+
* @param {Record<string, string|boolean>} attr 单元格属性
|
|
227
288
|
* @returns {TdToken}
|
|
228
289
|
* @complexity `n`
|
|
229
290
|
*/
|
|
230
291
|
insertTableCell(inner, {column}, subtype = 'td', attr = {}) {
|
|
231
|
-
const TdToken = require('./td')
|
|
232
|
-
|
|
292
|
+
const TdToken = require('./td');
|
|
293
|
+
const token = TdToken.create(inner, subtype, attr, this.getAttribute('include'), this.getAttribute('config'));
|
|
233
294
|
return this.insertBefore(token, this.getNthCol(column, true));
|
|
234
295
|
}
|
|
235
296
|
}
|
package/src/tagPair/ext.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const attributeParent = require('../../mixin/attributeParent'),
|
|
4
|
-
|
|
4
|
+
Parser = require('../..'),
|
|
5
5
|
TagPairToken = require('.');
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -11,35 +11,46 @@ const attributeParent = require('../../mixin/attributeParent'),
|
|
|
11
11
|
class ExtToken extends attributeParent(TagPairToken) {
|
|
12
12
|
type = 'ext';
|
|
13
13
|
|
|
14
|
+
/** @override */
|
|
15
|
+
get closed() {
|
|
16
|
+
return super.closed;
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
/**
|
|
15
|
-
* @param {string} name
|
|
16
|
-
* @param {string
|
|
20
|
+
* @param {string} name 标签名
|
|
21
|
+
* @param {string} attr 标签属性
|
|
22
|
+
* @param {string} inner 内部wikitext
|
|
23
|
+
* @param {string|undefined} closed 是否封闭
|
|
17
24
|
* @param {accum} accum
|
|
18
25
|
*/
|
|
19
|
-
constructor(name, attr = '', inner = '',
|
|
20
|
-
attr = !attr ||
|
|
26
|
+
constructor(name, attr = '', inner = '', closed = undefined, config = Parser.getConfig(), accum = []) {
|
|
27
|
+
attr = !attr || attr.trimStart() !== attr ? attr : ` ${attr}`;
|
|
28
|
+
const AttributeToken = require('../attribute');
|
|
21
29
|
const lcName = name.toLowerCase(),
|
|
22
|
-
AttributeToken = require('../attribute'),
|
|
23
30
|
attrToken = new AttributeToken(attr, 'ext-attr', lcName, config, accum),
|
|
24
31
|
newConfig = structuredClone(config),
|
|
25
32
|
ext = new Set(newConfig.ext);
|
|
26
33
|
let /** @type {acceptable} */ acceptable, /** @type {Token} */ innerToken;
|
|
27
34
|
switch (lcName) {
|
|
28
35
|
case 'choose':
|
|
29
|
-
ext.add('option');
|
|
30
|
-
// fall through
|
|
31
|
-
case 'ref':
|
|
32
36
|
case 'option':
|
|
37
|
+
case 'ref':
|
|
33
38
|
case 'poem':
|
|
34
39
|
case 'indicator':
|
|
35
40
|
case 'tab':
|
|
36
41
|
case 'tabs':
|
|
37
|
-
case 'pre':
|
|
42
|
+
case 'pre':
|
|
43
|
+
case 'combobox':
|
|
44
|
+
case 'combooption': {
|
|
38
45
|
ext.delete(lcName);
|
|
39
|
-
newConfig.ext = [
|
|
46
|
+
newConfig.ext = [
|
|
47
|
+
...ext,
|
|
48
|
+
...lcName === 'choose' ? ['option'] : [],
|
|
49
|
+
...lcName === 'combobox' ? ['combooption'] : [],
|
|
50
|
+
];
|
|
40
51
|
const Token = require('..');
|
|
41
52
|
acceptable = {AttributeToken: 0, Token: 1};
|
|
42
|
-
innerToken = new Token(inner, newConfig,
|
|
53
|
+
innerToken = new Token(inner, newConfig, true, accum);
|
|
43
54
|
break;
|
|
44
55
|
}
|
|
45
56
|
case 'gallery': {
|
|
@@ -50,6 +61,7 @@ class ExtToken extends attributeParent(TagPairToken) {
|
|
|
50
61
|
innerToken = new GalleryToken(inner, newConfig, accum);
|
|
51
62
|
break;
|
|
52
63
|
}
|
|
64
|
+
|
|
53
65
|
/*
|
|
54
66
|
* 更多定制扩展的代码示例:
|
|
55
67
|
* ```
|
|
@@ -69,28 +81,23 @@ class ExtToken extends attributeParent(TagPairToken) {
|
|
|
69
81
|
innerToken = new NowikiToken(inner, config);
|
|
70
82
|
}
|
|
71
83
|
}
|
|
72
|
-
innerToken.type = 'ext-inner';
|
|
73
|
-
innerToken.setAttribute('name', lcName);
|
|
84
|
+
innerToken.setAttribute('name', lcName).type = 'ext-inner';
|
|
74
85
|
if (lcName === 'pre') {
|
|
75
86
|
innerToken.setAttribute('stage', Parser.MAX_STAGE - 1);
|
|
76
87
|
}
|
|
77
|
-
super(name, attrToken, innerToken,
|
|
78
|
-
Object.defineProperty(this, 'closed', {value: true, enumerable: false, writable: false, configurable: false});
|
|
88
|
+
super(name, attrToken, innerToken, closed, config, accum, acceptable);
|
|
79
89
|
}
|
|
80
90
|
|
|
91
|
+
/** @override */
|
|
81
92
|
cloneNode() {
|
|
82
|
-
const inner = this.
|
|
93
|
+
const inner = this.lastChild.cloneNode(),
|
|
83
94
|
tags = this.getAttribute('tags'),
|
|
84
95
|
config = this.getAttribute('config'),
|
|
85
|
-
attr = this.
|
|
96
|
+
attr = String(this.firstChild),
|
|
86
97
|
token = Parser.run(() => new ExtToken(tags[0], attr, '', this.selfClosing ? undefined : tags[1], config));
|
|
87
|
-
token.
|
|
98
|
+
token.lastChild.safeReplaceWith(inner);
|
|
88
99
|
return token;
|
|
89
100
|
}
|
|
90
|
-
|
|
91
|
-
get innerText() {
|
|
92
|
-
return this.selfClosing ? '' : this.lastElementChild.text();
|
|
93
|
-
}
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
Parser.classes.ExtToken = __filename;
|
package/src/tagPair/include.js
CHANGED
|
@@ -1,41 +1,56 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const hidden = require('../../mixin/hidden'),
|
|
4
|
-
|
|
4
|
+
{generateForSelf} = require('../../util/lint'),
|
|
5
|
+
Parser = require('../..'),
|
|
5
6
|
TagPairToken = require('.');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* `<includeonly>`或`<noinclude>`
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
10
|
+
* @classdesc `{childNodes: [AstText, AstText]}`
|
|
10
11
|
*/
|
|
11
12
|
class IncludeToken extends hidden(TagPairToken) {
|
|
12
13
|
type = 'include';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
* @param {string} name
|
|
16
|
-
* @param {string
|
|
17
|
-
* @param {string|undefined}
|
|
16
|
+
* @param {string} name 标签名
|
|
17
|
+
* @param {string} attr 标签属性
|
|
18
|
+
* @param {string|undefined} inner 内部wikitext
|
|
19
|
+
* @param {string|undefined} closed 是否封闭
|
|
18
20
|
* @param {accum} accum
|
|
19
21
|
*/
|
|
20
|
-
constructor(name, attr = '', inner = undefined,
|
|
21
|
-
super(name, attr, inner ?? '', inner
|
|
22
|
+
constructor(name, attr = '', inner = undefined, closed = undefined, config = Parser.getConfig(), accum = []) {
|
|
23
|
+
super(name, attr, inner ?? '', inner === undefined ? closed : closed ?? '', config, accum, {AstText: [0, 1]});
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* @override
|
|
28
|
+
* @param {number} start 起始位置
|
|
29
|
+
* @returns {LintError[]}
|
|
30
|
+
*/
|
|
31
|
+
lint(start = 0) {
|
|
32
|
+
return this.closed ? [] : [generateForSelf(this, this.getRootNode().posFromIndex(start), '未闭合的标签')];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @override */
|
|
25
36
|
cloneNode() {
|
|
26
37
|
const tags = this.getAttribute('tags'),
|
|
27
38
|
config = this.getAttribute('config'),
|
|
28
|
-
inner = this.selfClosing ? undefined : this.lastChild,
|
|
39
|
+
inner = this.selfClosing ? undefined : String(this.lastChild),
|
|
29
40
|
closing = this.selfClosing || !this.closed ? undefined : tags[1],
|
|
30
|
-
token = Parser.run(() => new IncludeToken(tags[0], this.firstChild, inner, closing, config));
|
|
41
|
+
token = Parser.run(() => new IncludeToken(tags[0], String(this.firstChild), inner, closing, config));
|
|
31
42
|
return token;
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* @override
|
|
47
|
+
* @param {string} str 新文本
|
|
48
|
+
*/
|
|
35
49
|
setText(str) {
|
|
36
50
|
return super.setText(str, 1);
|
|
37
51
|
}
|
|
38
52
|
|
|
53
|
+
/** 清除标签属性 */
|
|
39
54
|
removeAttr() {
|
|
40
55
|
super.setText('', 0);
|
|
41
56
|
}
|
package/src/tagPair/index.js
CHANGED
|
@@ -1,30 +1,57 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fixedToken = require('../../mixin/fixedToken'),
|
|
4
|
-
|
|
4
|
+
Parser = require('../..'),
|
|
5
5
|
Token = require('..');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 成对标签
|
|
9
|
-
* @classdesc `{childNodes: [
|
|
9
|
+
* @classdesc `{childNodes: [AstText|AttributeToken, AstText|Token]}`
|
|
10
10
|
*/
|
|
11
11
|
class TagPairToken extends fixedToken(Token) {
|
|
12
|
-
selfClosing;
|
|
13
|
-
closed;
|
|
12
|
+
#selfClosing;
|
|
13
|
+
#closed;
|
|
14
14
|
#tags;
|
|
15
15
|
|
|
16
|
+
/** getter */
|
|
17
|
+
get selfClosing() {
|
|
18
|
+
return this.#selfClosing;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
set selfClosing(value) {
|
|
22
|
+
value = Boolean(value);
|
|
23
|
+
if (value !== this.#selfClosing && this.lastChild.text()) {
|
|
24
|
+
Parser.warn(`<${this.name}>标签内部的${value ? '文本将被隐藏' : '原有文本将再次可见'}!`);
|
|
25
|
+
}
|
|
26
|
+
this.#selfClosing = value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** getter */
|
|
30
|
+
get closed() {
|
|
31
|
+
return this.#closed;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
set closed(value) {
|
|
35
|
+
this.#closed ||= Boolean(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** 内部wikitext */
|
|
39
|
+
get innerText() {
|
|
40
|
+
return this.#selfClosing ? undefined : this.lastChild.text();
|
|
41
|
+
}
|
|
42
|
+
|
|
16
43
|
/**
|
|
17
|
-
* @param {string} name
|
|
18
|
-
* @param {string|Token} attr
|
|
19
|
-
* @param {string|Token} inner
|
|
20
|
-
* @param {string|undefined}
|
|
44
|
+
* @param {string} name 标签名
|
|
45
|
+
* @param {string|Token} attr 标签属性
|
|
46
|
+
* @param {string|Token} inner 内部wikitext
|
|
47
|
+
* @param {string|undefined} closed 是否封闭;约定`undefined`表示自闭合,`''`表示未闭合
|
|
21
48
|
* @param {accum} accum
|
|
22
49
|
*/
|
|
23
|
-
constructor(name, attr, inner,
|
|
50
|
+
constructor(name, attr, inner, closed, config = Parser.getConfig(), accum = []) {
|
|
24
51
|
super(undefined, config, true);
|
|
25
|
-
this.setAttribute('name', name.toLowerCase()).#tags = [name,
|
|
26
|
-
this
|
|
27
|
-
this
|
|
52
|
+
this.setAttribute('name', name.toLowerCase()).#tags = [name, closed || name];
|
|
53
|
+
this.#selfClosing = closed === undefined;
|
|
54
|
+
this.#closed = closed !== '';
|
|
28
55
|
this.append(attr, inner);
|
|
29
56
|
let index = accum.indexOf(attr);
|
|
30
57
|
if (index === -1) {
|
|
@@ -37,44 +64,60 @@ class TagPairToken extends fixedToken(Token) {
|
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
/**
|
|
67
|
+
* @override
|
|
40
68
|
* @template {string} T
|
|
41
|
-
* @param {T} key
|
|
69
|
+
* @param {T} key 属性键
|
|
42
70
|
* @returns {TokenAttribute<T>}
|
|
43
71
|
*/
|
|
44
72
|
getAttribute(key) {
|
|
45
|
-
|
|
46
|
-
return [...this.#tags];
|
|
47
|
-
}
|
|
48
|
-
return super.getAttribute(key);
|
|
73
|
+
return key === 'tags' ? [...this.#tags] : super.getAttribute(key);
|
|
49
74
|
}
|
|
50
75
|
|
|
51
|
-
|
|
52
|
-
|
|
76
|
+
/**
|
|
77
|
+
* @override
|
|
78
|
+
* @param {string} selector
|
|
79
|
+
*/
|
|
80
|
+
toString(selector) {
|
|
81
|
+
const {firstChild, lastChild, nextSibling, name} = this,
|
|
53
82
|
[opening, closing] = this.#tags;
|
|
54
|
-
if (
|
|
83
|
+
if (selector && this.matches(selector)) {
|
|
84
|
+
return '';
|
|
85
|
+
} else if (!this.#closed && nextSibling) {
|
|
55
86
|
Parser.error(`自动闭合 <${name}>`, lastChild);
|
|
56
|
-
this
|
|
87
|
+
this.#closed = true;
|
|
57
88
|
}
|
|
58
|
-
return selfClosing
|
|
89
|
+
return this.#selfClosing
|
|
59
90
|
? `<${opening}${String(firstChild)}/>`
|
|
60
|
-
: `<${opening}${String(firstChild)}>${String(lastChild)}${this
|
|
91
|
+
: `<${opening}${String(firstChild)}>${String(lastChild)}${this.#closed ? `</${closing}>` : ''}`;
|
|
61
92
|
}
|
|
62
93
|
|
|
94
|
+
/** @override */
|
|
63
95
|
getPadding() {
|
|
64
96
|
return this.#tags[0].length + 1;
|
|
65
97
|
}
|
|
66
98
|
|
|
99
|
+
/** @override */
|
|
67
100
|
getGaps() {
|
|
68
101
|
return 1;
|
|
69
102
|
}
|
|
70
103
|
|
|
71
|
-
/** @
|
|
104
|
+
/** @override */
|
|
105
|
+
print() {
|
|
106
|
+
const [opening, closing] = this.#tags;
|
|
107
|
+
return super.print(this.#selfClosing
|
|
108
|
+
? {pre: `<${opening}`, post: '/>'}
|
|
109
|
+
: {pre: `<${opening}`, sep: '>', post: this.#closed ? `</${closing}>` : ''});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @override
|
|
114
|
+
* @returns {string}
|
|
115
|
+
*/
|
|
72
116
|
text() {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
: `<${opening}${super.text('>')}${closed ? `</${closing}>` : ''}`;
|
|
117
|
+
const [opening, closing] = this.#tags;
|
|
118
|
+
return this.#selfClosing
|
|
119
|
+
? `<${opening}${this.firstChild.text()}/>`
|
|
120
|
+
: `<${opening}${super.text('>')}${this.#closed ? `</${closing}>` : ''}`;
|
|
78
121
|
}
|
|
79
122
|
}
|
|
80
123
|
|