wikiparser-node 1.3.4 → 1.3.6
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/dist/addon/table.js +13 -19
- package/dist/index.d.ts +1 -0
- package/dist/lib/element.d.ts +0 -1
- package/dist/lib/element.js +4 -13
- package/dist/lib/node.js +4 -0
- package/dist/lib/ranges.js +2 -1
- package/dist/lib/text.js +4 -5
- package/dist/mixin/attributesParent.js +2 -7
- package/dist/mixin/fixed.js +3 -10
- package/dist/mixin/syntax.js +1 -3
- package/dist/parser/braces.js +9 -2
- package/dist/parser/commentAndExt.js +18 -10
- package/dist/parser/list.js +11 -4
- package/dist/parser/selector.js +19 -20
- package/dist/parser/table.js +28 -20
- package/dist/src/arg.d.ts +0 -2
- package/dist/src/arg.js +2 -4
- package/dist/src/attribute.d.ts +1 -0
- package/dist/src/attribute.js +3 -3
- package/dist/src/attributes.d.ts +3 -1
- package/dist/src/attributes.js +21 -18
- package/dist/src/converter.d.ts +1 -0
- package/dist/src/converterRule.d.ts +1 -5
- package/dist/src/converterRule.js +3 -7
- package/dist/src/extLink.d.ts +1 -0
- package/dist/src/gallery.d.ts +0 -1
- package/dist/src/gallery.js +1 -2
- package/dist/src/heading.d.ts +3 -1
- package/dist/src/heading.js +2 -2
- package/dist/src/hidden.d.ts +1 -0
- package/dist/src/html.d.ts +3 -0
- package/dist/src/html.js +0 -1
- package/dist/src/imageParameter.d.ts +0 -1
- package/dist/src/imageParameter.js +0 -2
- package/dist/src/imagemap.d.ts +0 -1
- package/dist/src/imagemap.js +2 -3
- package/dist/src/imagemapLink.d.ts +2 -0
- package/dist/src/index.d.ts +1 -8
- package/dist/src/index.js +17 -17
- package/dist/src/link/file.js +2 -1
- package/dist/src/link/galleryImage.d.ts +1 -0
- package/dist/src/link/index.js +1 -1
- package/dist/src/magicLink.d.ts +1 -2
- package/dist/src/magicLink.js +2 -3
- package/dist/src/nested.d.ts +0 -1
- package/dist/src/nested.js +1 -2
- package/dist/src/nowiki/base.d.ts +1 -0
- package/dist/src/nowiki/comment.d.ts +1 -0
- package/dist/src/nowiki/dd.js +1 -1
- package/dist/src/nowiki/doubleUnderscore.d.ts +2 -0
- package/dist/src/nowiki/hr.d.ts +2 -0
- package/dist/src/nowiki/list.d.ts +1 -0
- package/dist/src/nowiki/listBase.d.ts +1 -0
- package/dist/src/nowiki/noinclude.d.ts +1 -1
- package/dist/src/nowiki/noinclude.js +1 -2
- package/dist/src/nowiki/quote.d.ts +1 -0
- package/dist/src/parameter.d.ts +1 -0
- package/dist/src/parameter.js +1 -1
- package/dist/src/syntax.d.ts +2 -0
- package/dist/src/table/base.d.ts +2 -0
- package/dist/src/table/index.d.ts +0 -1
- package/dist/src/table/index.js +0 -1
- package/dist/src/table/td.d.ts +3 -0
- package/dist/src/table/td.js +9 -10
- package/dist/src/table/trBase.d.ts +0 -1
- package/dist/src/table/trBase.js +2 -10
- package/dist/src/tagPair/ext.d.ts +2 -0
- package/dist/src/tagPair/include.d.ts +1 -0
- package/dist/src/tagPair/index.d.ts +1 -0
- package/dist/src/transclude.js +9 -11
- package/dist/util/debug.js +39 -20
- package/dist/util/lint.js +12 -28
- package/dist/util/string.js +12 -22
- package/package.json +1 -1
package/dist/addon/table.js
CHANGED
|
@@ -39,6 +39,9 @@ const isStartCol = (rowLayout, i, oneCol = false) => {
|
|
|
39
39
|
const coords = rowLayout[i];
|
|
40
40
|
return rowLayout[i - 1] !== coords && (!oneCol || rowLayout[i + 1] !== coords);
|
|
41
41
|
};
|
|
42
|
+
function occupied(layout, i, oneRow = false, cells) {
|
|
43
|
+
return layout[i].map(({ row, column }, j) => row === i && (!oneRow || cells[column].rowspan === 1) ? j : undefined).filter((j) => j !== undefined);
|
|
44
|
+
}
|
|
42
45
|
/**
|
|
43
46
|
* 设置表格格式
|
|
44
47
|
* @param cells 单元格
|
|
@@ -52,9 +55,7 @@ const format = (cells, attr = {}, multi = false) => {
|
|
|
52
55
|
token.setSyntax(attr);
|
|
53
56
|
}
|
|
54
57
|
else {
|
|
55
|
-
|
|
56
|
-
token.setAttr(k, v);
|
|
57
|
-
}
|
|
58
|
+
token.setAttr(attr);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
}
|
|
@@ -81,11 +82,10 @@ const fill = (y, rowToken, layout, maxCol, token) => {
|
|
|
81
82
|
class Layout extends Array {
|
|
82
83
|
/** 打印表格布局 */
|
|
83
84
|
print() {
|
|
84
|
-
const hBorders =
|
|
85
|
+
const hBorders = (0, debug_1.emptyArray)(this.length + 1, i => {
|
|
85
86
|
const prev = this[i - 1] ?? [], next = this[i] ?? [];
|
|
86
|
-
return
|
|
87
|
-
|
|
88
|
-
}), vBorders = this.map(cur => new Array(cur.length + 1).fill(undefined).map((_, j) => cur[j - 1] !== cur[j]));
|
|
87
|
+
return (0, debug_1.emptyArray)(Math.max(prev.length, next.length), j => prev[j] !== next[j]);
|
|
88
|
+
}), vBorders = this.map(cur => (0, debug_1.emptyArray)(cur.length + 1, j => cur[j - 1] !== cur[j]));
|
|
89
89
|
let out = '';
|
|
90
90
|
for (let i = 0; i <= this.length; i++) {
|
|
91
91
|
const hBorder = hBorders[i].map(Number), vBorderTop = (vBorders[i - 1] ?? []).map(Number), vBorderBottom = (vBorders[i] ?? []).map(Number),
|
|
@@ -111,7 +111,7 @@ table_1.TableToken.prototype.getNthCell =
|
|
|
111
111
|
table_1.TableToken.prototype.getLayout =
|
|
112
112
|
/** @implements */
|
|
113
113
|
function (stop) {
|
|
114
|
-
const rows = this.getAllRows(), { length } = rows, layout = new Layout(...
|
|
114
|
+
const rows = this.getAllRows(), { length } = rows, layout = new Layout(...(0, debug_1.emptyArray)(length, () => []));
|
|
115
115
|
for (let i = 0; i < length; i++) {
|
|
116
116
|
if (i > (stop?.row ?? stop?.y ?? NaN)) {
|
|
117
117
|
break;
|
|
@@ -250,9 +250,7 @@ table_1.TableToken.prototype.insertTableRow =
|
|
|
250
250
|
function (y, attr = {}, inner, subtype = 'td', innerAttr = {}) {
|
|
251
251
|
let reference = this.getNthRow(y, false, true);
|
|
252
252
|
const token = debug_1.Shadow.run(() => new tr_1.TrToken('\n|-', undefined, this.getAttribute('config')));
|
|
253
|
-
|
|
254
|
-
token.setAttr(k, v);
|
|
255
|
-
}
|
|
253
|
+
token.setAttr(attr);
|
|
256
254
|
if (reference?.type === 'table') { // `row === 0`且表格自身是有效行
|
|
257
255
|
reference = this.prependTableRow();
|
|
258
256
|
}
|
|
@@ -455,11 +453,9 @@ table_1.TableToken.prototype.replicateTableCol =
|
|
|
455
453
|
table_1.TableToken.prototype.moveTableRowBefore =
|
|
456
454
|
/** @implements */
|
|
457
455
|
function (y, before) {
|
|
458
|
-
const layout = this.getLayout()
|
|
459
|
-
/** @ignore */
|
|
460
|
-
occupied = (i) => layout[i].map(({ row }, j) => row === i ? j : undefined).filter((j) => j !== undefined);
|
|
456
|
+
const layout = this.getLayout();
|
|
461
457
|
try {
|
|
462
|
-
assert.deepEqual(occupied(y), occupied(before));
|
|
458
|
+
assert.deepEqual(occupied(layout, y), occupied(layout, before));
|
|
463
459
|
}
|
|
464
460
|
catch (e) {
|
|
465
461
|
if (e instanceof assert.AssertionError) {
|
|
@@ -483,11 +479,9 @@ table_1.TableToken.prototype.moveTableRowBefore =
|
|
|
483
479
|
table_1.TableToken.prototype.moveTableRowAfter =
|
|
484
480
|
/** @implements */
|
|
485
481
|
function (y, after) {
|
|
486
|
-
const layout = this.getLayout(), afterToken = this.getNthRow(after), cells = afterToken.childNodes.filter(child => child.type === 'td' && child.subtype !== 'caption')
|
|
487
|
-
/** @ignore */
|
|
488
|
-
occupied = (i, oneRow = false) => layout[i].map(({ row, column }, j) => row === i && (!oneRow || cells[column].rowspan === 1) ? j : undefined).filter((j) => j !== undefined);
|
|
482
|
+
const layout = this.getLayout(), afterToken = this.getNthRow(after), cells = afterToken.childNodes.filter(child => child.type === 'td' && child.subtype !== 'caption');
|
|
489
483
|
try {
|
|
490
|
-
assert.deepEqual(occupied(y), occupied(after, true));
|
|
484
|
+
assert.deepEqual(occupied(layout, y), occupied(layout, after, true, cells));
|
|
491
485
|
}
|
|
492
486
|
catch (e) {
|
|
493
487
|
if (e instanceof assert.AssertionError) {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Shadow } from './util/debug';
|
|
|
2
2
|
import type { Config, LintError, Parser as ParserBase } from './base';
|
|
3
3
|
import type { Title } from './lib/title';
|
|
4
4
|
import type { Token } from './internal';
|
|
5
|
+
declare type log = (msg: string, ...args: unknown[]) => void;
|
|
5
6
|
declare interface Parser extends ParserBase {
|
|
6
7
|
readonly Shadow: typeof Shadow;
|
|
7
8
|
conversionTable: Map<string, string>;
|
package/dist/lib/element.d.ts
CHANGED
|
@@ -145,7 +145,6 @@ export declare abstract class AstElement extends AstNode {
|
|
|
145
145
|
* @param reference 指定位置处的子节点
|
|
146
146
|
*/
|
|
147
147
|
insertBefore(child: string, reference?: AstNodes): AstText;
|
|
148
|
-
/** @ignore */
|
|
149
148
|
insertBefore<T extends AstNodes>(child: T, reference?: AstNodes): T;
|
|
150
149
|
/**
|
|
151
150
|
* 输出AST
|
package/dist/lib/element.js
CHANGED
|
@@ -5,6 +5,7 @@ const fs = require("fs");
|
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const string_1 = require("../util/string");
|
|
7
7
|
const constants_1 = require("../util/constants");
|
|
8
|
+
const debug_1 = require("../util/debug");
|
|
8
9
|
const selector_1 = require("../parser/selector");
|
|
9
10
|
const ranges_1 = require("./ranges");
|
|
10
11
|
const title_1 = require("./title");
|
|
@@ -130,10 +131,7 @@ class AstElement extends node_1.AstNode {
|
|
|
130
131
|
*/
|
|
131
132
|
removeAt(i) {
|
|
132
133
|
this.verifyChild(i);
|
|
133
|
-
|
|
134
|
-
node.setAttribute('parentNode', undefined);
|
|
135
|
-
this.setAttribute('childNodes', childNodes);
|
|
136
|
-
return node;
|
|
134
|
+
return (0, debug_1.setChildNodes)(this, i, 1)[0];
|
|
137
135
|
}
|
|
138
136
|
/**
|
|
139
137
|
* 插入子节点
|
|
@@ -143,19 +141,14 @@ class AstElement extends node_1.AstNode {
|
|
|
143
141
|
*/
|
|
144
142
|
insertAt(node, i = this.length) {
|
|
145
143
|
if (node.contains(this)) {
|
|
146
|
-
Parser.error('不能插入祖先节点!', node);
|
|
147
144
|
throw new RangeError('不能插入祖先节点!');
|
|
148
145
|
}
|
|
149
|
-
|
|
150
|
-
if (childNodes.includes(node)) {
|
|
151
|
-
Parser.error('不能插入子节点!', node);
|
|
146
|
+
if (this.childNodes.includes(node)) {
|
|
152
147
|
throw new RangeError('不能插入子节点!');
|
|
153
148
|
}
|
|
154
149
|
this.verifyChild(i, 1);
|
|
155
150
|
node.parentNode?.removeChild(node);
|
|
156
|
-
|
|
157
|
-
childNodes.splice(i, 0, node);
|
|
158
|
-
this.setAttribute('childNodes', childNodes);
|
|
151
|
+
(0, debug_1.setChildNodes)(this, i, 0, [node]);
|
|
159
152
|
return node;
|
|
160
153
|
}
|
|
161
154
|
/**
|
|
@@ -573,7 +566,6 @@ class AstElement extends node_1.AstNode {
|
|
|
573
566
|
#getChildIndex(node) {
|
|
574
567
|
const i = this.childNodes.indexOf(node);
|
|
575
568
|
if (i === -1) {
|
|
576
|
-
Parser.error('找不到子节点!', node);
|
|
577
569
|
throw new RangeError('找不到子节点!');
|
|
578
570
|
}
|
|
579
571
|
return i;
|
|
@@ -586,7 +578,6 @@ class AstElement extends node_1.AstNode {
|
|
|
586
578
|
this.removeAt(this.#getChildIndex(node));
|
|
587
579
|
return node;
|
|
588
580
|
}
|
|
589
|
-
/** @ignore */
|
|
590
581
|
insertBefore(child, reference) {
|
|
591
582
|
return reference === undefined
|
|
592
583
|
? this.insertAt(child)
|
package/dist/lib/node.js
CHANGED
|
@@ -205,6 +205,10 @@ class AstNode {
|
|
|
205
205
|
return typeError(this.constructor, method, ...types);
|
|
206
206
|
}
|
|
207
207
|
/** @private */
|
|
208
|
+
constructorError(msg) {
|
|
209
|
+
throw new Error(`${this.constructor.name} ${msg}!`);
|
|
210
|
+
}
|
|
211
|
+
/** @private */
|
|
208
212
|
seal(key) {
|
|
209
213
|
this.#optional.add(key);
|
|
210
214
|
Object.defineProperty(this, key, {
|
package/dist/lib/ranges.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Ranges = exports.Range = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
+
const debug_1 = require("../util/debug");
|
|
5
6
|
/** 模拟Python的Range对象。除`step`至少为`1`外,允许负数、小数或`end < start`的情形。 */
|
|
6
7
|
class Range {
|
|
7
8
|
#start;
|
|
@@ -102,7 +103,7 @@ class Ranges extends Array {
|
|
|
102
103
|
* @param arr 参考数组
|
|
103
104
|
*/
|
|
104
105
|
applyTo(arr) {
|
|
105
|
-
const length = typeof arr === 'number' ? arr : arr.length, a =
|
|
106
|
+
const length = typeof arr === 'number' ? arr : arr.length, a = (0, debug_1.emptyArray)(length, i => i);
|
|
106
107
|
return [
|
|
107
108
|
...new Set([...this].flatMap(ele => {
|
|
108
109
|
if (typeof ele === 'number') {
|
package/dist/lib/text.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AstText = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
+
const debug_1 = require("../util/debug");
|
|
5
6
|
const Parser = require("../index");
|
|
6
7
|
const node_1 = require("./node");
|
|
7
8
|
const errorSyntax = /<\s*\/?([a-z]\w*)|\{+|\}+|\[{2,}|\[(?![^[]*\])|(?<=^|\])([^[]*?)\]+|\]{2,}|https?[:/]\/+/giu, errorSyntaxUrl = /<\s*\/?([a-z]\w*)|\{+|\}+|\[{2,}|\[(?![^[]*\])|(?<=^|\])([^[]*?)\]+|\]{2,}/giu, disallowedTags = [
|
|
@@ -215,11 +216,9 @@ class AstText extends node_1.AstNode {
|
|
|
215
216
|
if (!parentNode) {
|
|
216
217
|
throw new Error('待分裂的文本节点没有父节点!');
|
|
217
218
|
}
|
|
218
|
-
const newText = new AstText(data.slice(offset))
|
|
219
|
+
const newText = new AstText(data.slice(offset));
|
|
220
|
+
(0, debug_1.setChildNodes)(parentNode, parentNode.childNodes.indexOf(this) + 1, 0, [newText]);
|
|
219
221
|
this.setAttribute('data', data.slice(0, offset));
|
|
220
|
-
childNodes.splice(childNodes.indexOf(this) + 1, 0, newText);
|
|
221
|
-
newText.setAttribute('parentNode', parentNode);
|
|
222
|
-
parentNode.setAttribute('childNodes', childNodes);
|
|
223
222
|
return newText;
|
|
224
223
|
}
|
|
225
224
|
/** @private */
|
|
@@ -228,7 +227,7 @@ class AstText extends node_1.AstNode {
|
|
|
228
227
|
return super.getRelativeIndex();
|
|
229
228
|
}
|
|
230
229
|
else if (j < 0 || j > this.length) {
|
|
231
|
-
throw new RangeError(
|
|
230
|
+
throw new RangeError('超出文本长度范围!');
|
|
232
231
|
}
|
|
233
232
|
return j;
|
|
234
233
|
}
|
|
@@ -64,13 +64,8 @@ const attributesParent = (constructor, i = 0) => {
|
|
|
64
64
|
getAttrs() {
|
|
65
65
|
return this.#attributesChild.getAttrs();
|
|
66
66
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
* @param key 属性键
|
|
70
|
-
* @param value 属性值
|
|
71
|
-
*/
|
|
72
|
-
setAttr(key, value) {
|
|
73
|
-
this.#attributesChild.setAttr(key, value);
|
|
67
|
+
setAttr(keyOrProp, value) {
|
|
68
|
+
this.#attributesChild.setAttr(keyOrProp, value);
|
|
74
69
|
}
|
|
75
70
|
/**
|
|
76
71
|
* 移除AttributesToken子节点的某属性
|
package/dist/mixin/fixed.js
CHANGED
|
@@ -11,19 +11,12 @@ const fixed = (constructor) => {
|
|
|
11
11
|
/** 不可增删子节点的类 */
|
|
12
12
|
class FixedToken extends constructor {
|
|
13
13
|
static fixed = true;
|
|
14
|
-
/**
|
|
15
|
-
* @override
|
|
16
|
-
* @throws `Error` 不可用
|
|
17
|
-
*/
|
|
14
|
+
/** @override */
|
|
18
15
|
removeAt() {
|
|
19
|
-
|
|
16
|
+
this.constructorError('不可删除元素');
|
|
20
17
|
}
|
|
21
|
-
/** @ignore */
|
|
22
18
|
insertAt(token, i) {
|
|
23
|
-
|
|
24
|
-
return super.insertAt(token, i);
|
|
25
|
-
}
|
|
26
|
-
throw new Error(`${this.constructor.name} 不可插入元素!`);
|
|
19
|
+
return debug_1.Shadow.running ? super.insertAt(token, i) : this.constructorError('不可插入元素');
|
|
27
20
|
}
|
|
28
21
|
}
|
|
29
22
|
return FixedToken;
|
package/dist/mixin/syntax.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.syntax = void 0;
|
|
|
4
4
|
const debug_1 = require("../util/debug");
|
|
5
5
|
const constants_1 = require("../util/constants");
|
|
6
6
|
const string_1 = require("../util/string");
|
|
7
|
-
const Parser = require("../index");
|
|
8
7
|
/**
|
|
9
8
|
* 满足特定语法格式的Token
|
|
10
9
|
* @param constructor 基类
|
|
@@ -19,8 +18,7 @@ const syntax = (constructor, pattern) => {
|
|
|
19
18
|
const /** @implements */ syntaxListener = (e, data) => {
|
|
20
19
|
if (!debug_1.Shadow.running && !this.#pattern.test(this.text())) {
|
|
21
20
|
(0, debug_1.undo)(e, data);
|
|
22
|
-
|
|
23
|
-
throw new Error(`不可修改 ${this.constructor.name} 的语法!`);
|
|
21
|
+
this.constructorError('不可修改语法');
|
|
24
22
|
}
|
|
25
23
|
};
|
|
26
24
|
this.addEventListener(['remove', 'insert', 'replace', 'text'], syntaxListener);
|
package/dist/parser/braces.js
CHANGED
|
@@ -25,6 +25,13 @@ const parseBraces = (wikitext, config = Parser.getConfig(), accum = []) => {
|
|
|
25
25
|
mt.index += length;
|
|
26
26
|
}
|
|
27
27
|
const { 0: syntax, index: curIndex } = mt ?? { 0: '\n', index: wikitext.length }, top = stack.pop() ?? {}, { 0: open, index, parts, findEqual: topFindEqual, pos: topPos } = top, innerEqual = syntax === '=' && topFindEqual;
|
|
28
|
+
/**
|
|
29
|
+
* 填入模板内容
|
|
30
|
+
* @param text wikitext全文
|
|
31
|
+
*/
|
|
32
|
+
const push = (text) => {
|
|
33
|
+
parts.at(-1).push(text.slice(topPos, curIndex));
|
|
34
|
+
};
|
|
28
35
|
if (syntax === ']]' || syntax === '}-') { // 情形1:闭合内链或转换
|
|
29
36
|
lastIndex = curIndex + 2;
|
|
30
37
|
}
|
|
@@ -43,7 +50,7 @@ const parseBraces = (wikitext, config = Parser.getConfig(), accum = []) => {
|
|
|
43
50
|
}
|
|
44
51
|
else if (syntax === '|' || innerEqual) { // 情形3:模板内部,含行首单个'='
|
|
45
52
|
lastIndex = curIndex + 1;
|
|
46
|
-
|
|
53
|
+
push(wikitext);
|
|
47
54
|
if (syntax === '|') {
|
|
48
55
|
parts.push([]);
|
|
49
56
|
}
|
|
@@ -54,7 +61,7 @@ const parseBraces = (wikitext, config = Parser.getConfig(), accum = []) => {
|
|
|
54
61
|
else if (syntax.startsWith('}}')) { // 情形4:闭合模板
|
|
55
62
|
const close = syntax.slice(0, Math.min(open.length, 3)), rest = open.length - close.length, { length } = accum;
|
|
56
63
|
lastIndex = curIndex + close.length; // 这不是最终的lastIndex
|
|
57
|
-
|
|
64
|
+
push(wikitext);
|
|
58
65
|
let skip = false, ch = 't';
|
|
59
66
|
if (close.length === 3) {
|
|
60
67
|
const argParts = parts.map(part => part.join('=')), str = argParts.length > 1 && (0, string_1.removeComment)(argParts[1]).trim();
|
|
@@ -17,27 +17,35 @@ const comment_1 = require("../src/nowiki/comment");
|
|
|
17
17
|
*/
|
|
18
18
|
const parseCommentAndExt = (wikitext, config = Parser.getConfig(), accum = [], includeOnly = false) => {
|
|
19
19
|
const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft;
|
|
20
|
+
/** 更新`<onlyinclude>`和`</onlyinclude>`的位置 */
|
|
21
|
+
const update = () => {
|
|
22
|
+
const i = wikitext.indexOf(onlyincludeLeft);
|
|
23
|
+
return { i, j: wikitext.indexOf(onlyincludeRight, i + length) };
|
|
24
|
+
};
|
|
20
25
|
if (includeOnly) {
|
|
21
|
-
let i
|
|
26
|
+
let { i, j } = update();
|
|
22
27
|
if (i !== -1 && j !== -1) { // `<onlyinclude>`拥有最高优先级
|
|
23
28
|
let str = '';
|
|
29
|
+
/**
|
|
30
|
+
* 忽略未被`<onlyinclude>`和`</onlyinclude>`包裹的内容
|
|
31
|
+
* @param text 未被包裹的内容
|
|
32
|
+
*/
|
|
33
|
+
const noinclude = (text) => {
|
|
34
|
+
new noinclude_1.NoincludeToken(text, config, accum);
|
|
35
|
+
str += `\0${accum.length - 1}c\x7F`;
|
|
36
|
+
};
|
|
24
37
|
while (i !== -1 && j !== -1) {
|
|
25
38
|
const token = `\0${accum.length}e\x7F`;
|
|
26
39
|
new onlyinclude_1.OnlyincludeToken(wikitext.slice(i + length, j), config, accum);
|
|
27
40
|
if (i > 0) {
|
|
28
|
-
|
|
29
|
-
str += `\0${accum.length - 1}c\x7F${token}`;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
str += token;
|
|
41
|
+
noinclude(wikitext.slice(0, i));
|
|
33
42
|
}
|
|
43
|
+
str += token;
|
|
34
44
|
wikitext = wikitext.slice(j + length + 1);
|
|
35
|
-
i =
|
|
36
|
-
j = wikitext.indexOf(onlyincludeRight, i + length);
|
|
45
|
+
({ i, j } = update());
|
|
37
46
|
}
|
|
38
47
|
if (wikitext) {
|
|
39
|
-
|
|
40
|
-
str += `\0${accum.length - 1}c\x7F`;
|
|
48
|
+
noinclude(wikitext);
|
|
41
49
|
}
|
|
42
50
|
return str;
|
|
43
51
|
}
|
package/dist/parser/list.js
CHANGED
|
@@ -23,17 +23,24 @@ const parseList = (wikitext, config = Parser.getConfig(), accum = []) => {
|
|
|
23
23
|
return text;
|
|
24
24
|
}
|
|
25
25
|
let regex = /:+|-\{/gu, ex = regex.exec(text), lc = 0;
|
|
26
|
+
/**
|
|
27
|
+
* 创建`DdToken`
|
|
28
|
+
* @param syntax `:`
|
|
29
|
+
* @param index 起点
|
|
30
|
+
*/
|
|
31
|
+
const dd = (syntax, index) => {
|
|
32
|
+
new dd_1.DdToken(syntax, config, accum);
|
|
33
|
+
return `${text.slice(0, index)}\0${accum.length - 1}d\x7F${text.slice(index + syntax.length)}`;
|
|
34
|
+
};
|
|
26
35
|
while (ex && dt) {
|
|
27
36
|
const { 0: syntax, index } = ex;
|
|
28
37
|
if (syntax.startsWith(':')) {
|
|
29
38
|
if (syntax.length >= dt) {
|
|
30
|
-
|
|
31
|
-
return `${text.slice(0, index)}\0${accum.length - 1}d\x7F${text.slice(index + dt)}`;
|
|
39
|
+
return dd(syntax.slice(0, dt), index);
|
|
32
40
|
}
|
|
33
|
-
text = `${text.slice(0, index)}\0${accum.length}d\x7F${text.slice(regex.lastIndex)}`;
|
|
34
41
|
dt -= syntax.length;
|
|
35
42
|
regex.lastIndex = index + 4 + String(accum.length).length;
|
|
36
|
-
|
|
43
|
+
text = dd(syntax, index);
|
|
37
44
|
}
|
|
38
45
|
else if (syntax === '-{') {
|
|
39
46
|
if (!lc) {
|
package/dist/parser/selector.js
CHANGED
|
@@ -72,21 +72,6 @@ const desanitize = (selector) => {
|
|
|
72
72
|
* @param val 属性值或伪选择器函数的参数
|
|
73
73
|
*/
|
|
74
74
|
const deQuote = (val) => /^(["']).*\1$/u.test(val) ? val.slice(1, -1) : val.trim();
|
|
75
|
-
/**
|
|
76
|
-
* 解析简单伪选择器
|
|
77
|
-
* @param step 当前顶部
|
|
78
|
-
* @param str 不含属性和复杂伪选择器的语句
|
|
79
|
-
* @throws `SyntaxError` 非法的选择器
|
|
80
|
-
*/
|
|
81
|
-
const pushSimple = (step, str) => {
|
|
82
|
-
const pieces = str.trim().split(':'),
|
|
83
|
-
// eslint-disable-next-line unicorn/explicit-length-check
|
|
84
|
-
i = pieces.slice(1).findIndex(pseudo => simplePseudos.has(pseudo)) + 1 || pieces.length;
|
|
85
|
-
if (pieces.slice(i).some(pseudo => !simplePseudos.has(pseudo))) {
|
|
86
|
-
throw new SyntaxError(`非法的选择器!\n${str}\n可能需要将':'转义为'\\:'。`);
|
|
87
|
-
}
|
|
88
|
-
step.push(desanitize(pieces.slice(0, i).join(':')), ...pieces.slice(i).map(piece => `:${piece}`));
|
|
89
|
-
};
|
|
90
75
|
/**
|
|
91
76
|
* 解析选择器
|
|
92
77
|
* @param selector
|
|
@@ -96,6 +81,20 @@ const parseSelector = (selector) => {
|
|
|
96
81
|
selector = selector.trim();
|
|
97
82
|
const stack = [[[]]];
|
|
98
83
|
let sanitized = sanitize(selector), regex = regularRegex, mt = regex.exec(sanitized), [condition] = stack, [step] = condition;
|
|
84
|
+
/**
|
|
85
|
+
* 解析简单伪选择器
|
|
86
|
+
* @param index 伪选择器的终点位置
|
|
87
|
+
* @throws `SyntaxError` 非法的选择器
|
|
88
|
+
*/
|
|
89
|
+
const pushSimple = (index) => {
|
|
90
|
+
const str = sanitized.slice(0, index), pieces = str.trim().split(':'),
|
|
91
|
+
// eslint-disable-next-line unicorn/explicit-length-check
|
|
92
|
+
i = pieces.slice(1).findIndex(pseudo => simplePseudos.has(pseudo)) + 1 || pieces.length;
|
|
93
|
+
if (pieces.slice(i).some(pseudo => !simplePseudos.has(pseudo))) {
|
|
94
|
+
throw new SyntaxError(`非法的选择器!\n${str}\n可能需要将':'转义为'\\:'。`);
|
|
95
|
+
}
|
|
96
|
+
step.push(desanitize(pieces.slice(0, i).join(':')), ...pieces.slice(i).map(piece => `:${piece}`));
|
|
97
|
+
};
|
|
99
98
|
while (mt) {
|
|
100
99
|
let { 0: syntax, index } = mt;
|
|
101
100
|
if (syntax.trim() === '') {
|
|
@@ -104,13 +103,13 @@ const parseSelector = (selector) => {
|
|
|
104
103
|
syntax = grouping.has(char) ? char : '';
|
|
105
104
|
}
|
|
106
105
|
if (syntax === ',') { // 情形1:并列
|
|
107
|
-
pushSimple(
|
|
106
|
+
pushSimple(index);
|
|
108
107
|
condition = [[]];
|
|
109
108
|
[step] = condition;
|
|
110
109
|
stack.push(condition);
|
|
111
110
|
}
|
|
112
111
|
else if (combinator.has(syntax)) { // 情形2:关系
|
|
113
|
-
pushSimple(
|
|
112
|
+
pushSimple(index);
|
|
114
113
|
if (!step.some(Boolean)) {
|
|
115
114
|
throw new SyntaxError(`非法的选择器!\n${selector}\n可能需要通用选择器'*'。`);
|
|
116
115
|
}
|
|
@@ -119,7 +118,7 @@ const parseSelector = (selector) => {
|
|
|
119
118
|
condition.push(step);
|
|
120
119
|
}
|
|
121
120
|
else if (syntax === '[') { // 情形3:属性开启
|
|
122
|
-
pushSimple(
|
|
121
|
+
pushSimple(index);
|
|
123
122
|
regex = attributeRegex;
|
|
124
123
|
}
|
|
125
124
|
else if (syntax.endsWith(']')) { // 情形4:属性闭合
|
|
@@ -132,7 +131,7 @@ const parseSelector = (selector) => {
|
|
|
132
131
|
if (!pseudoExec) {
|
|
133
132
|
throw new SyntaxError(`非法的选择器!\n${desanitize(sanitized)}\n请检查伪选择器是否存在。`);
|
|
134
133
|
}
|
|
135
|
-
pushSimple(
|
|
134
|
+
pushSimple(pseudoExec.index);
|
|
136
135
|
step.push(pseudoExec[1]); // 临时存放复杂伪选择器
|
|
137
136
|
regex = functionRegex;
|
|
138
137
|
}
|
|
@@ -149,7 +148,7 @@ const parseSelector = (selector) => {
|
|
|
149
148
|
mt = regex.exec(sanitized);
|
|
150
149
|
}
|
|
151
150
|
if (regex === regularRegex) {
|
|
152
|
-
pushSimple(
|
|
151
|
+
pushSimple(Infinity);
|
|
153
152
|
const pseudos = new Set(stack.flat(2).filter((e) => typeof e === 'string' && e.startsWith(':')));
|
|
154
153
|
if (pseudos.size > 0) {
|
|
155
154
|
Parser.warn('检测到伪选择器,请确认是否需要将":"转义成"\\:"。', pseudos);
|
package/dist/parser/table.js
CHANGED
|
@@ -8,7 +8,10 @@ const index_2 = require("../src/table/index");
|
|
|
8
8
|
const tr_1 = require("../src/table/tr");
|
|
9
9
|
const td_1 = require("../src/table/td");
|
|
10
10
|
const dd_1 = require("../src/nowiki/dd");
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* 判断是否为表格行或表格
|
|
13
|
+
* @param token 表格节点
|
|
14
|
+
*/
|
|
12
15
|
const isTr = (token) => token.lastChild.constructor !== index_1.Token;
|
|
13
16
|
/**
|
|
14
17
|
* 解析表格,注意`tr`和`td`包含开头的换行
|
|
@@ -20,30 +23,32 @@ const parseTable = ({ firstChild: { data }, type, name }, config = Parser.getCon
|
|
|
20
23
|
const stack = [], lines = data.split('\n');
|
|
21
24
|
let out = type === 'root' || type === 'parameter-value' || type === 'ext-inner' && name === 'poem'
|
|
22
25
|
? ''
|
|
23
|
-
: `\n${lines.shift()}
|
|
26
|
+
: `\n${lines.shift()}`, top;
|
|
24
27
|
/**
|
|
25
28
|
* 向表格中插入纯文本
|
|
26
29
|
* @param str 待插入的文本
|
|
27
|
-
* @param
|
|
30
|
+
* @param topToken 当前解析的表格或表格行
|
|
28
31
|
*/
|
|
29
|
-
const push = (str,
|
|
30
|
-
if (!
|
|
32
|
+
const push = (str, topToken) => {
|
|
33
|
+
if (!topToken) {
|
|
31
34
|
out += str;
|
|
32
35
|
return;
|
|
33
36
|
}
|
|
34
|
-
const { lastChild } =
|
|
35
|
-
if (isTr(
|
|
37
|
+
const { lastChild } = topToken;
|
|
38
|
+
if (isTr(topToken)) {
|
|
36
39
|
const token = new index_1.Token(str, config, accum);
|
|
37
40
|
token.type = 'table-inter';
|
|
38
41
|
token.setAttribute('stage', 3);
|
|
39
|
-
|
|
42
|
+
topToken.insertAt(token);
|
|
40
43
|
}
|
|
41
44
|
else {
|
|
42
45
|
lastChild.setText(String(lastChild) + str);
|
|
43
46
|
}
|
|
44
|
-
}
|
|
47
|
+
},
|
|
48
|
+
/** 取出最近的表格行 */
|
|
49
|
+
pop = () => top.type === 'td' ? stack.pop() : top;
|
|
45
50
|
for (const outLine of lines) {
|
|
46
|
-
|
|
51
|
+
top = stack.pop();
|
|
47
52
|
const [spaces] = /^(?:\s|\0\d+c\x7F)*/u.exec(outLine), line = outLine.slice(spaces.length), matchesStart = /^(:*)((?:\s|\0\d+c\x7F)*)(\{\||\{(?:\0\d+c\x7F)*\0\d+!\x7F|\0\d+\{\x7F)(.*)$/u
|
|
48
53
|
.exec(line);
|
|
49
54
|
if (matchesStart) {
|
|
@@ -79,9 +84,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config = Parser.getCon
|
|
|
79
84
|
push(attr, stack.at(-1));
|
|
80
85
|
}
|
|
81
86
|
else if (row) {
|
|
82
|
-
|
|
83
|
-
top = stack.pop();
|
|
84
|
-
}
|
|
87
|
+
top = pop();
|
|
85
88
|
if (top.type === 'tr') {
|
|
86
89
|
top = stack.pop();
|
|
87
90
|
}
|
|
@@ -90,20 +93,25 @@ const parseTable = ({ firstChild: { data }, type, name }, config = Parser.getCon
|
|
|
90
93
|
top.insertAt(tr);
|
|
91
94
|
}
|
|
92
95
|
else {
|
|
93
|
-
|
|
94
|
-
top = stack.pop();
|
|
95
|
-
}
|
|
96
|
+
top = pop();
|
|
96
97
|
const regex = cell === '!' ? /!!|(?:\||\0\d+!\x7F){2}|\0\d+\+\x7F/gu : /(?:\||\0\d+!\x7F){2}|\0\d+\+\x7F/gu;
|
|
97
98
|
let mt = regex.exec(attr), lastIndex = 0, lastSyntax = `\n${spaces}${cell}`;
|
|
99
|
+
/**
|
|
100
|
+
* 创建表格单元格
|
|
101
|
+
* @param tr 当前表格行
|
|
102
|
+
*/
|
|
103
|
+
const createTd = (tr) => {
|
|
104
|
+
const td = new td_1.TdToken(lastSyntax, attr.slice(lastIndex, mt?.index), config, accum);
|
|
105
|
+
tr.insertAt(td);
|
|
106
|
+
return td;
|
|
107
|
+
};
|
|
98
108
|
while (mt) {
|
|
99
|
-
top
|
|
109
|
+
createTd(top);
|
|
100
110
|
({ lastIndex } = regex);
|
|
101
111
|
[lastSyntax] = mt;
|
|
102
112
|
mt = regex.exec(attr);
|
|
103
113
|
}
|
|
104
|
-
|
|
105
|
-
stack.push(top, td);
|
|
106
|
-
top.insertAt(td);
|
|
114
|
+
stack.push(top, createTd(top));
|
|
107
115
|
}
|
|
108
116
|
}
|
|
109
117
|
return out.slice(1);
|
package/dist/src/arg.d.ts
CHANGED
package/dist/src/arg.js
CHANGED
|
@@ -141,16 +141,14 @@ class ArgToken extends index_1.Token {
|
|
|
141
141
|
* @override
|
|
142
142
|
* @param token 待插入的子节点
|
|
143
143
|
* @param i 插入位置
|
|
144
|
-
* @throws `RangeError` 不可插入多余子节点
|
|
145
|
-
* @throws `TypeError` 不可插入文本节点
|
|
146
144
|
*/
|
|
147
145
|
insertAt(token, i = this.length) {
|
|
148
146
|
i += i < 0 ? this.length : 0;
|
|
149
147
|
if (i > 1) {
|
|
150
|
-
|
|
148
|
+
this.constructorError('不可插入多余的子节点');
|
|
151
149
|
}
|
|
152
150
|
else if (typeof token === 'string') {
|
|
153
|
-
|
|
151
|
+
this.constructorError('不可插入文本节点');
|
|
154
152
|
}
|
|
155
153
|
super.insertAt(token, i);
|
|
156
154
|
if (i === 1) {
|
package/dist/src/attribute.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ declare const AttributeToken_base: ((abstract new (...args: any[]) => {
|
|
|
17
17
|
setAttribute<T_2 extends string>(key: T_2, value: TokenAttributeSetter<T_2>): void;
|
|
18
18
|
addEventListener(events: string | string[], listener: AstListener): void;
|
|
19
19
|
replaceChildren(...elements: (string | Parser.AstNodes)[]): void;
|
|
20
|
+
constructorError(msg: string): never;
|
|
20
21
|
}) & {
|
|
21
22
|
readonly fixed: true;
|
|
22
23
|
}) & typeof Parser.Token;
|
package/dist/src/attribute.js
CHANGED
|
@@ -360,15 +360,15 @@ class AttributeToken extends (0, fixed_1.fixed)(index_1.Token) {
|
|
|
360
360
|
else if (this.type === 'ext-attr' && value.includes('>')) {
|
|
361
361
|
throw new RangeError('扩展标签属性不能包含 ">"!');
|
|
362
362
|
}
|
|
363
|
-
else if (value.includes('"') && value.includes(
|
|
363
|
+
else if (value.includes('"') && value.includes(`'`)) {
|
|
364
364
|
throw new RangeError('属性值不能同时包含单引号和双引号!');
|
|
365
365
|
}
|
|
366
366
|
const config = this.getAttribute('config'), { childNodes } = Parser.parse(value, this.getAttribute('include'), stages[this.type] + 1, config);
|
|
367
367
|
this.lastChild.replaceChildren(...childNodes);
|
|
368
368
|
if (value.includes('"')) {
|
|
369
|
-
this.#quotes = [
|
|
369
|
+
this.#quotes = [`'`, `'`];
|
|
370
370
|
}
|
|
371
|
-
else if (value.includes(
|
|
371
|
+
else if (value.includes(`'`) || !this.#quotes[0]) {
|
|
372
372
|
this.#quotes = ['"', '"'];
|
|
373
373
|
}
|
|
374
374
|
else {
|
package/dist/src/attributes.d.ts
CHANGED
|
@@ -70,16 +70,18 @@ export declare class AttributesToken extends Token {
|
|
|
70
70
|
* @override
|
|
71
71
|
* @param token 待插入的子节点
|
|
72
72
|
* @param i 插入位置
|
|
73
|
-
* @throws `RangeError`
|
|
73
|
+
* @throws `RangeError` 标签不匹配
|
|
74
74
|
*/
|
|
75
75
|
insertAt<T extends AttributeToken | AtomToken>(token: T, i?: number): T;
|
|
76
76
|
/**
|
|
77
77
|
* 设置指定属性
|
|
78
78
|
* @param key 属性键
|
|
79
79
|
* @param value 属性值
|
|
80
|
+
* @param prop 属性对象
|
|
80
81
|
* @throws `RangeError` 扩展标签属性不能包含">"
|
|
81
82
|
*/
|
|
82
83
|
setAttr(key: string, value: string | boolean): void;
|
|
84
|
+
setAttr(prop: Record<string, string | boolean>): void;
|
|
83
85
|
/**
|
|
84
86
|
* 标签是否具有某属性
|
|
85
87
|
* @param key 属性键
|