wikiparser-node 1.6.1 → 1.6.2
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 +37 -37
- package/dist/base.d.ts +0 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -14
- package/dist/lib/element.d.ts +5 -5
- package/dist/lib/element.js +25 -22
- package/dist/lib/range.js +1 -1
- package/dist/lib/ranges.d.ts +3 -1
- package/dist/lib/ranges.js +34 -29
- package/dist/lib/text.js +2 -2
- package/dist/lib/title.d.ts +8 -6
- package/dist/lib/title.js +62 -43
- package/dist/parser/braces.js +1 -2
- package/dist/parser/commentAndExt.js +1 -2
- package/dist/parser/converter.js +1 -2
- package/dist/parser/externalLinks.js +18 -5
- package/dist/parser/hrAndDoubleUnderscore.js +1 -2
- package/dist/parser/html.js +7 -8
- package/dist/parser/links.js +6 -4
- package/dist/parser/list.js +1 -2
- package/dist/parser/magicLinks.js +3 -4
- package/dist/parser/quotes.js +1 -2
- package/dist/parser/selector.js +51 -23
- package/dist/parser/table.js +6 -7
- package/dist/src/attribute.js +1 -1
- package/dist/src/extLink.js +5 -2
- package/dist/src/imageParameter.js +2 -2
- package/dist/src/imagemap.js +1 -1
- package/dist/src/index.js +3 -4
- package/dist/src/link/base.js +1 -1
- package/dist/src/link/galleryImage.js +2 -1
- package/dist/src/magicLink.js +1 -1
- package/dist/src/nowiki/quote.js +1 -1
- package/dist/src/paramTag/inputbox.js +2 -2
- package/dist/src/parameter.js +1 -1
- package/dist/src/table/base.js +1 -1
- package/dist/src/table/index.js +7 -5
- package/dist/src/table/td.js +3 -2
- package/dist/src/table/trBase.js +1 -1
- package/dist/src/transclude.js +8 -8
- package/dist/util/constants.js +1 -2
- package/dist/util/debug.js +2 -9
- package/dist/util/diff.js +2 -2
- package/dist/util/string.js +8 -2
- package/package.json +2 -1
package/dist/lib/title.js
CHANGED
|
@@ -4,17 +4,22 @@ exports.Title = void 0;
|
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
5
|
const constants_1 = require("../util/constants");
|
|
6
6
|
const index_1 = require("../index");
|
|
7
|
+
/**
|
|
8
|
+
* PHP的`rawurldecode`函数的JavaScript实现
|
|
9
|
+
* @param str 要解码的字符串
|
|
10
|
+
*/
|
|
11
|
+
const rawurldecode = (str) => decodeURIComponent(str.replace(/%(?![\da-f]{2})/giu, '%25'));
|
|
7
12
|
/** MediaWiki页面标题对象 */
|
|
8
13
|
class Title {
|
|
9
|
-
|
|
14
|
+
#main;
|
|
15
|
+
#namespaces;
|
|
10
16
|
ns;
|
|
11
17
|
fragment;
|
|
18
|
+
interwiki = '';
|
|
19
|
+
valid;
|
|
12
20
|
/** @private */
|
|
13
21
|
encoded = false;
|
|
14
|
-
#main;
|
|
15
22
|
/* NOT FOR BROWSER */
|
|
16
|
-
#namespaces;
|
|
17
|
-
interwiki = '';
|
|
18
23
|
/** @private */
|
|
19
24
|
conversionTable = new Map();
|
|
20
25
|
/** @private */
|
|
@@ -28,16 +33,6 @@ class Title {
|
|
|
28
33
|
title = title.replace(/_/gu, ' ').trim();
|
|
29
34
|
this.#main = title && `${title[0].toUpperCase()}${title.slice(1)}`;
|
|
30
35
|
}
|
|
31
|
-
/** 扩展名 */
|
|
32
|
-
get extension() {
|
|
33
|
-
const { main } = this, i = main.lastIndexOf('.');
|
|
34
|
-
return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
|
|
35
|
-
}
|
|
36
|
-
/* NOT FOR BROWSER */
|
|
37
|
-
set extension(extension) {
|
|
38
|
-
const { main } = this, i = main.lastIndexOf('.');
|
|
39
|
-
this.main = `${i === -1 ? main : main.slice(0, i)}.${extension}`;
|
|
40
|
-
}
|
|
41
36
|
/** 命名空间前缀 */
|
|
42
37
|
get prefix() {
|
|
43
38
|
const namespace = this.#namespaces[this.ns];
|
|
@@ -47,82 +42,106 @@ class Title {
|
|
|
47
42
|
get title() {
|
|
48
43
|
const prefix = `${this.interwiki}${this.interwiki && ':'}${this.prefix}`;
|
|
49
44
|
let title = `${prefix}${this.main}`.replace(/ /gu, '_');
|
|
50
|
-
|
|
45
|
+
/* NOT FOR BROWSER */
|
|
46
|
+
let redirected = this.redirects.get(title);
|
|
51
47
|
if (redirected) {
|
|
52
48
|
return redirected;
|
|
53
49
|
}
|
|
54
50
|
this.autoConvert();
|
|
55
51
|
title = `${prefix}${this.main}`.replace(/ /gu, '_');
|
|
56
|
-
|
|
52
|
+
redirected = this.redirects.get(title);
|
|
53
|
+
if (redirected) {
|
|
54
|
+
return redirected;
|
|
55
|
+
}
|
|
56
|
+
/* NOT FOR BROWSER END */
|
|
57
|
+
return title;
|
|
58
|
+
}
|
|
59
|
+
/** 扩展名 */
|
|
60
|
+
get extension() {
|
|
61
|
+
const { main } = this, i = main.lastIndexOf('.');
|
|
62
|
+
return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
|
|
63
|
+
}
|
|
64
|
+
/* NOT FOR BROWSER */
|
|
65
|
+
set extension(extension) {
|
|
66
|
+
const { main } = this, i = main.lastIndexOf('.');
|
|
67
|
+
this.main = `${i === -1 ? main : main.slice(0, i)}.${extension}`;
|
|
57
68
|
}
|
|
58
69
|
/* NOT FOR BROWSER END */
|
|
59
70
|
/**
|
|
71
|
+
* @see MediaWikiTitleCodec::splitTitleString
|
|
72
|
+
*
|
|
60
73
|
* @param title 标题(含或不含命名空间前缀)
|
|
61
74
|
* @param defaultNs 命名空间
|
|
62
75
|
* @param decode 是否需要解码
|
|
63
76
|
* @param selfLink 是否允许selfLink
|
|
64
77
|
*/
|
|
65
|
-
constructor(title, defaultNs
|
|
78
|
+
constructor(title, defaultNs, config, decode, selfLink) {
|
|
79
|
+
const subpage = title.trim().startsWith('../');
|
|
66
80
|
title = (0, string_1.decodeHtml)(title);
|
|
67
81
|
if (decode && title.includes('%')) {
|
|
68
82
|
try {
|
|
69
83
|
const encoded = /%(?!21|3[ce]|5[bd]|7[b-d])[\da-f]{2}/iu.test(title);
|
|
70
|
-
title =
|
|
84
|
+
title = rawurldecode(title);
|
|
71
85
|
this.encoded = encoded;
|
|
72
86
|
}
|
|
73
87
|
catch { }
|
|
74
88
|
}
|
|
75
89
|
title = title.replace(/_/gu, ' ').trim();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
ns = 0;
|
|
79
|
-
title = title.slice(1).trim();
|
|
80
|
-
}
|
|
81
|
-
/* NOT FOR BROWSER */
|
|
82
|
-
const iw = defaultNs ? null : index_1.default.isInterwiki(title, config);
|
|
83
|
-
if (iw) {
|
|
84
|
-
this.interwiki = iw[1].toLowerCase();
|
|
85
|
-
title = title.slice(iw.indices[0][1]);
|
|
90
|
+
if (subpage) {
|
|
91
|
+
this.ns = 0;
|
|
86
92
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
else {
|
|
94
|
+
let ns = defaultNs;
|
|
95
|
+
if (title.startsWith(':')) {
|
|
96
|
+
ns = 0;
|
|
97
|
+
title = title.slice(1).trim();
|
|
98
|
+
}
|
|
99
|
+
/* NOT FOR BROWSER */
|
|
100
|
+
const iw = defaultNs ? null : index_1.default.isInterwiki(title, config);
|
|
101
|
+
if (iw) {
|
|
102
|
+
this.interwiki = iw[1].toLowerCase();
|
|
103
|
+
title = title.slice(iw.indices[0][1]);
|
|
104
|
+
}
|
|
105
|
+
/* NOT FOR BROWSER END */
|
|
106
|
+
const m = title.split(':');
|
|
107
|
+
if (m.length > 1) {
|
|
108
|
+
const id = config.nsid[m[0].trim().toLowerCase()];
|
|
109
|
+
if (id) {
|
|
110
|
+
ns = id;
|
|
111
|
+
title = m.slice(1).join(':').trim();
|
|
112
|
+
}
|
|
94
113
|
}
|
|
114
|
+
this.ns = ns;
|
|
95
115
|
}
|
|
96
|
-
this.ns = ns;
|
|
97
116
|
const i = title.indexOf('#');
|
|
98
117
|
if (i !== -1) {
|
|
99
118
|
let fragment = title.slice(i + 1).trimEnd();
|
|
100
119
|
if (fragment.includes('%')) {
|
|
101
120
|
try {
|
|
102
|
-
fragment =
|
|
121
|
+
fragment = rawurldecode(fragment);
|
|
103
122
|
}
|
|
104
123
|
catch { }
|
|
105
124
|
}
|
|
106
125
|
this.fragment = fragment;
|
|
107
126
|
title = title.slice(0, i).trim();
|
|
108
127
|
}
|
|
109
|
-
this.valid = Boolean(title || this.interwiki || selfLink && this.fragment !== undefined)
|
|
110
|
-
&& !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}
|
|
128
|
+
this.valid = Boolean(title || this.interwiki || selfLink && this.ns === 0 && this.fragment !== undefined)
|
|
129
|
+
&& !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|\n]|%[\da-f]{2}|(?:^|\/)\.{1,2}(?:$|\/)/iu.test(subpage ? /^(?:\.\.\/)+(.*)/u.exec(title)[1] : title);
|
|
111
130
|
this.main = title;
|
|
112
|
-
/* NOT FOR BROWSER */
|
|
113
|
-
this.#namespaces = config.namespaces;
|
|
114
131
|
Object.defineProperties(this, {
|
|
115
|
-
valid: { writable: false },
|
|
116
132
|
encoded: { enumerable: false, writable: false },
|
|
133
|
+
/* NOT FOR BROWSER */
|
|
134
|
+
valid: { writable: false },
|
|
117
135
|
conversionTable: { enumerable: false },
|
|
118
136
|
redirects: { enumerable: false },
|
|
119
137
|
});
|
|
138
|
+
this.#namespaces = config.namespaces;
|
|
120
139
|
}
|
|
121
|
-
/* NOT FOR BROWSER */
|
|
122
140
|
/** @private */
|
|
123
141
|
toString() {
|
|
124
142
|
return `${this.title}${this.fragment === undefined ? '' : `#${this.fragment}`}`;
|
|
125
143
|
}
|
|
144
|
+
/* NOT FOR BROWSER */
|
|
126
145
|
/** 执行单向转换 */
|
|
127
146
|
autoConvert() {
|
|
128
147
|
const { conversionTable } = this;
|
package/dist/parser/braces.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseBraces = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
5
|
const constants_1 = require("../util/constants");
|
|
6
|
-
const index_1 = require("../index");
|
|
7
6
|
const heading_1 = require("../src/heading");
|
|
8
7
|
const transclude_1 = require("../src/transclude");
|
|
9
8
|
const arg_1 = require("../src/arg");
|
|
@@ -14,7 +13,7 @@ const arg_1 = require("../src/arg");
|
|
|
14
13
|
* @param accum
|
|
15
14
|
* @throws TranscludeToken.constructor()
|
|
16
15
|
*/
|
|
17
|
-
const parseBraces = (wikitext, config
|
|
16
|
+
const parseBraces = (wikitext, config, accum) => {
|
|
18
17
|
const source = `${config.excludes?.includes('heading') ? '' : '^(\0\\d+c\x7F)*={1,6}|'}\\[\\[|\\{{2,}|-\\{(?!\\{)`, { parserFunction: [, , , subst] } = config, stack = [], closes = { '=': '\n', '{': '\\}{2,}|\\|', '-': '\\}-', '[': '\\]\\]' }, marks = new Map([['!', '!'], ['!!', '+'], ['(!', '{'], ['!)', '}'], ['!-', '-'], ['=', '~']]);
|
|
19
18
|
let regex = new RegExp(source, 'gmu'), mt = regex.exec(wikitext), moreBraces = wikitext.includes('}}'), lastIndex;
|
|
20
19
|
while (mt
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseCommentAndExt = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const onlyinclude_1 = require("../src/onlyinclude");
|
|
7
6
|
const noinclude_1 = require("../src/nowiki/noinclude");
|
|
8
7
|
const include_1 = require("../src/tagPair/include");
|
|
@@ -15,7 +14,7 @@ const comment_1 = require("../src/nowiki/comment");
|
|
|
15
14
|
* @param accum
|
|
16
15
|
* @param includeOnly 是否嵌入
|
|
17
16
|
*/
|
|
18
|
-
const parseCommentAndExt = (wikitext, config
|
|
17
|
+
const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
|
|
19
18
|
const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft;
|
|
20
19
|
/** 更新`<onlyinclude>`和`</onlyinclude>`的位置 */
|
|
21
20
|
const update = () => {
|
package/dist/parser/converter.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseConverter = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const converter_1 = require("../src/converter");
|
|
7
6
|
/**
|
|
8
7
|
* 解析语言变体转换
|
|
@@ -10,7 +9,7 @@ const converter_1 = require("../src/converter");
|
|
|
10
9
|
* @param config
|
|
11
10
|
* @param accum
|
|
12
11
|
*/
|
|
13
|
-
const parseConverter = (text, config
|
|
12
|
+
const parseConverter = (text, config, accum) => {
|
|
14
13
|
const regex1 = /-\{/gu, regex2 = /-\{|\}-/gu, stack = [];
|
|
15
14
|
let regex = regex1, mt = regex.exec(text);
|
|
16
15
|
while (mt) {
|
|
@@ -3,26 +3,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseExternalLinks = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
5
|
const constants_1 = require("../util/constants");
|
|
6
|
-
const index_1 = require("../index");
|
|
7
6
|
const extLink_1 = require("../src/extLink");
|
|
7
|
+
const magicLink_1 = require("../src/magicLink");
|
|
8
8
|
/**
|
|
9
9
|
* 解析外部链接
|
|
10
10
|
* @param wikitext
|
|
11
11
|
* @param config
|
|
12
12
|
* @param accum
|
|
13
|
+
* @param inFile 是否在图链中
|
|
13
14
|
*/
|
|
14
|
-
const parseExternalLinks = (wikitext, config
|
|
15
|
+
const parseExternalLinks = (wikitext, config, accum, inFile) => {
|
|
15
16
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
16
17
|
/\[((?:\[[\da-f:.]+\]|[^[\]\t\n\p{Zs}])[^[\]\t\n\p{Zs}]*(?=[[\]\t\p{Zs}]|\0\d))(\p{Zs}*(?=\P{Zs}))([^\]\n]*)\]/giu;
|
|
17
|
-
const regex = new RegExp(
|
|
18
|
-
+
|
|
18
|
+
const regex = new RegExp('\\[' // 左括号
|
|
19
|
+
+ `(${'\0\\d+f\x7F' // 预先解析的MagicLinkToken
|
|
20
|
+
+ '|'
|
|
21
|
+
+ `(?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\\d+m\x7F)${string_1.extUrlChar}(?=[[\\]<>"\\t\\p{Zs}]|\0\\d)`})` // 链接网址
|
|
22
|
+
+ '(\\p{Zs}*(?=\\P{Zs}))' // 空格
|
|
23
|
+
+ '([^\\]\x01-\x08\x0A-\x1F\uFFFD]*)' // 链接文字
|
|
24
|
+
+ '\\]', // 右括号
|
|
25
|
+
'giu');
|
|
19
26
|
return wikitext.replace(regex, (_, url, space, text) => {
|
|
20
|
-
const { length } = accum
|
|
27
|
+
const { length } = accum;
|
|
28
|
+
const mt = /&[lg]t;/u.exec(url);
|
|
21
29
|
if (mt) {
|
|
22
30
|
url = url.slice(0, mt.index);
|
|
23
31
|
space = '';
|
|
24
32
|
text = `${url.slice(mt.index)}${space}${text}`;
|
|
25
33
|
}
|
|
34
|
+
if (inFile) {
|
|
35
|
+
// @ts-expect-error abstract class
|
|
36
|
+
new magicLink_1.MagicLinkToken(url, true, config, accum);
|
|
37
|
+
return `[\0${length}f\x7F${space}${text}]`;
|
|
38
|
+
}
|
|
26
39
|
// @ts-expect-error abstract class
|
|
27
40
|
new extLink_1.ExtLinkToken(url, space, text, config, accum);
|
|
28
41
|
return `\0${length}w\x7F`;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseHrAndDoubleUnderscore = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const hr_1 = require("../src/nowiki/hr");
|
|
7
6
|
const doubleUnderscore_1 = require("../src/nowiki/doubleUnderscore");
|
|
8
7
|
const heading_1 = require("../src/heading");
|
|
@@ -12,7 +11,7 @@ const heading_1 = require("../src/heading");
|
|
|
12
11
|
* @param config
|
|
13
12
|
* @param accum
|
|
14
13
|
*/
|
|
15
|
-
const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config
|
|
14
|
+
const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config, accum) => {
|
|
16
15
|
const { doubleUnderscore } = config, insensitive = new Set(doubleUnderscore[0]), sensitive = new Set(doubleUnderscore[1]);
|
|
17
16
|
if (type !== 'root' && (type !== 'ext-inner' || name !== 'poem')) {
|
|
18
17
|
data = `\0${data}`;
|
package/dist/parser/html.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseHtml = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const attributes_1 = require("../src/attributes");
|
|
7
6
|
const html_1 = require("../src/html");
|
|
8
7
|
/**
|
|
@@ -11,7 +10,7 @@ const html_1 = require("../src/html");
|
|
|
11
10
|
* @param config
|
|
12
11
|
* @param accum
|
|
13
12
|
*/
|
|
14
|
-
const parseHtml = (wikitext, config
|
|
13
|
+
const parseHtml = (wikitext, config, accum) => {
|
|
15
14
|
const regex = /^(\/?)([a-z][^\s/>]*)((?:\s|\/(?!>))[^>]*?)?(\/?>)([^<]*)$/iu, elements = new Set(config.html.flat()), bits = wikitext.split('<');
|
|
16
15
|
let text = bits.shift();
|
|
17
16
|
for (const x of bits) {
|
|
@@ -20,18 +19,18 @@ const parseHtml = (wikitext, config = index_1.default.getConfig(), accum = []) =
|
|
|
20
19
|
text += `<${x}`;
|
|
21
20
|
continue;
|
|
22
21
|
}
|
|
23
|
-
const [, slash, , params = '', brace, rest] = mt,
|
|
22
|
+
const [, slash, , params = '', brace, rest] = mt, { length } = accum,
|
|
24
23
|
// @ts-expect-error abstract class
|
|
25
|
-
|
|
26
|
-
if (name === 'meta' && (itemprop === undefined ||
|
|
27
|
-
|| name === 'link' && (itemprop === undefined ||
|
|
24
|
+
attrs = new attributes_1.AttributesToken(params, 'html-attrs', name, config, accum), itemprop = attrs.getAttr('itemprop');
|
|
25
|
+
if (name === 'meta' && (itemprop === undefined || attrs.getAttr('content') === undefined)
|
|
26
|
+
|| name === 'link' && (itemprop === undefined || attrs.getAttr('href') === undefined)) {
|
|
28
27
|
text += `<${x}`;
|
|
29
|
-
accum.
|
|
28
|
+
accum.length = length;
|
|
30
29
|
continue;
|
|
31
30
|
}
|
|
32
31
|
text += `\0${accum.length}x\x7F${rest}`;
|
|
33
32
|
// @ts-expect-error abstract class
|
|
34
|
-
new html_1.HtmlToken(t,
|
|
33
|
+
new html_1.HtmlToken(t, attrs, slash === '/', brace === '/>', config, accum);
|
|
35
34
|
}
|
|
36
35
|
return text;
|
|
37
36
|
};
|
package/dist/parser/links.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseLinks = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
5
|
const index_1 = require("../index");
|
|
6
|
+
const quotes_1 = require("./quotes");
|
|
7
|
+
const externalLinks_1 = require("./externalLinks");
|
|
6
8
|
const index_2 = require("../src/link/index");
|
|
7
9
|
const file_1 = require("../src/link/file");
|
|
8
10
|
const category_1 = require("../src/link/category");
|
|
@@ -12,8 +14,7 @@ const category_1 = require("../src/link/category");
|
|
|
12
14
|
* @param config
|
|
13
15
|
* @param accum
|
|
14
16
|
*/
|
|
15
|
-
const parseLinks = (wikitext, config
|
|
16
|
-
const { parseQuotes } = require('./quotes');
|
|
17
|
+
const parseLinks = (wikitext, config, accum) => {
|
|
17
18
|
const regex = /^((?:(?!\0\d+!\x7F)[^\n[\]{}|])+)(?:(\||\0\d+!\x7F)(.*?[^\]]))?\]\](.*)$/su, regexImg = /^((?:(?!\0\d+!\x7F)[^\n[\]{}|])+)(\||\0\d+!\x7F)(.*)$/su, regexExt = new RegExp(`^\\s*(?:${config.protocol}|//)`, 'iu'), bits = wikitext.split('[[');
|
|
18
19
|
let s = bits.shift();
|
|
19
20
|
for (let i = 0; i < bits.length; i++) {
|
|
@@ -75,17 +76,18 @@ const parseLinks = (wikitext, config = index_1.default.getConfig(), accum = [])
|
|
|
75
76
|
continue;
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
text &&= parseQuotes(text, config, accum);
|
|
79
|
-
s += `\0${accum.length}l\x7F${after}`;
|
|
79
|
+
text &&= (0, quotes_1.parseQuotes)(text, config, accum);
|
|
80
80
|
let SomeLinkToken = index_2.LinkToken;
|
|
81
81
|
if (!force) {
|
|
82
82
|
if (!interwiki && ns === 6) {
|
|
83
|
+
text &&= (0, externalLinks_1.parseExternalLinks)(text, config, accum, true);
|
|
83
84
|
SomeLinkToken = file_1.FileToken;
|
|
84
85
|
}
|
|
85
86
|
else if (!interwiki && ns === 14) {
|
|
86
87
|
SomeLinkToken = category_1.CategoryToken;
|
|
87
88
|
}
|
|
88
89
|
}
|
|
90
|
+
s += `\0${accum.length}l\x7F${after}`;
|
|
89
91
|
// @ts-expect-error abstract class
|
|
90
92
|
new SomeLinkToken(link, text, config, accum, delimiter);
|
|
91
93
|
}
|
package/dist/parser/list.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseList = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const list_1 = require("../src/nowiki/list");
|
|
7
6
|
const dd_1 = require("../src/nowiki/dd");
|
|
8
7
|
/**
|
|
@@ -11,7 +10,7 @@ const dd_1 = require("../src/nowiki/dd");
|
|
|
11
10
|
* @param config
|
|
12
11
|
* @param accum
|
|
13
12
|
*/
|
|
14
|
-
const parseList = (wikitext, config
|
|
13
|
+
const parseList = (wikitext, config, accum) => {
|
|
15
14
|
const mt = /^((?:\0\d+c\x7F)*)([;:*#]+)/u.exec(wikitext);
|
|
16
15
|
if (!mt) {
|
|
17
16
|
return wikitext;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseMagicLinks = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
5
|
const constants_1 = require("../util/constants");
|
|
6
|
-
const index_1 = require("../index");
|
|
7
6
|
const magicLink_1 = require("../src/magicLink");
|
|
8
7
|
/**
|
|
9
8
|
* 解析自由外链
|
|
@@ -11,18 +10,18 @@ const magicLink_1 = require("../src/magicLink");
|
|
|
11
10
|
* @param config
|
|
12
11
|
* @param accum
|
|
13
12
|
*/
|
|
14
|
-
const parseMagicLinks = (wikitext, config
|
|
13
|
+
const parseMagicLinks = (wikitext, config, accum) => {
|
|
15
14
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
16
15
|
/(^|[^\p{L}\d_])((?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])(?:[^[\]<>"\0\t\n\p{Zs}]|\0\d+c\x7F)*)/giu;
|
|
17
16
|
const regex = new RegExp(`(^|[^\\p{L}\\d_])(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})`, 'giu');
|
|
18
17
|
return wikitext.replace(regex, (m, lead, p1) => {
|
|
19
|
-
let trail = '', url = lead ? m.slice(
|
|
18
|
+
let trail = '', url = lead ? m.slice(lead.length) : m;
|
|
20
19
|
const m2 = /&(?:lt|gt|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu.exec(url);
|
|
21
20
|
if (m2) {
|
|
22
21
|
trail = url.slice(m2.index);
|
|
23
22
|
url = url.slice(0, m2.index);
|
|
24
23
|
}
|
|
25
|
-
const sep = new RegExp(`[
|
|
24
|
+
const sep = new RegExp(`[,;\\\\.:!?${url.includes('(') ? '' : ')'}]+$`, 'u'), sepChars = sep.exec(url);
|
|
26
25
|
if (sepChars) {
|
|
27
26
|
let correction = 0;
|
|
28
27
|
if (sepChars[0].startsWith(';') && /&(?:[a-z]+|#x[\da-f]+|#\d+)$/iu.test(url.slice(0, sepChars.index))) {
|
package/dist/parser/quotes.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseQuotes = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const quote_1 = require("../src/nowiki/quote");
|
|
7
6
|
/**
|
|
8
7
|
* 解析单引号
|
|
@@ -10,7 +9,7 @@ const quote_1 = require("../src/nowiki/quote");
|
|
|
10
9
|
* @param config
|
|
11
10
|
* @param accum
|
|
12
11
|
*/
|
|
13
|
-
const parseQuotes = (wikitext, config
|
|
12
|
+
const parseQuotes = (wikitext, config, accum) => {
|
|
14
13
|
const arr = wikitext.split(/('{2,})/u), { length } = arr;
|
|
15
14
|
if (length === 1) {
|
|
16
15
|
return wikitext;
|
package/dist/parser/selector.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseSelector = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
5
|
const string_1 = require("../util/string");
|
|
6
|
-
const index_1 = require("../index");
|
|
7
6
|
const simplePseudos = new Set([
|
|
8
7
|
'root',
|
|
9
8
|
'first-child',
|
|
@@ -24,7 +23,7 @@ const simplePseudos = new Set([
|
|
|
24
23
|
'required',
|
|
25
24
|
'optional',
|
|
26
25
|
]);
|
|
27
|
-
const complexPseudos = [
|
|
26
|
+
const complexPseudos = new Set([
|
|
28
27
|
'is',
|
|
29
28
|
'not',
|
|
30
29
|
'nth-child',
|
|
@@ -35,7 +34,7 @@ const complexPseudos = [
|
|
|
35
34
|
'has',
|
|
36
35
|
'lang',
|
|
37
36
|
'regex',
|
|
38
|
-
];
|
|
37
|
+
]);
|
|
39
38
|
const specialChars = [
|
|
40
39
|
['[', '['],
|
|
41
40
|
[']', ']'],
|
|
@@ -47,7 +46,7 @@ const specialChars = [
|
|
|
47
46
|
['\\', '\'],
|
|
48
47
|
['&', '&'],
|
|
49
48
|
];
|
|
50
|
-
const
|
|
49
|
+
const regularRegex = /[[(,>+~]|\s+/u, attributeRegex = /^\s*(\w+)\s*(?:([~|^$*!]?=)\s*("[^"]*"|'[^']*'|[^\s[\]]+)(?:\s+(i))?\s*)?\]/u, functionRegex = /^(\s*"[^"]*"\s*|\s*'[^']*'\s*|[^()]*)\)/u, grouping = new Set([',', '>', '+', '~']), combinator = new Set(['>', '+', '~', '']);
|
|
51
50
|
/**
|
|
52
51
|
* 清理转义符号
|
|
53
52
|
* @param selector
|
|
@@ -85,16 +84,49 @@ const parseSelector = (selector) => {
|
|
|
85
84
|
/**
|
|
86
85
|
* 解析简单伪选择器
|
|
87
86
|
* @param index 伪选择器的终点位置
|
|
87
|
+
* @throws `SyntaxError` 选择器排序
|
|
88
88
|
* @throws `SyntaxError` 非法的选择器
|
|
89
89
|
*/
|
|
90
90
|
const pushSimple = (index) => {
|
|
91
|
-
const str = sanitized.slice(0, index)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
const str = sanitized.slice(0, index).trim();
|
|
92
|
+
if (!str) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const pieces = str.split(/(?=[:#])/u);
|
|
96
|
+
for (let i = 0; i < pieces.length; i++) {
|
|
97
|
+
const piece = pieces[i];
|
|
98
|
+
if (!/^[:#]/u.test(piece)) {
|
|
99
|
+
if (step.length > 0) {
|
|
100
|
+
throw new SyntaxError(`Invalid selector!\n${selector}\nType selectors must come first.`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
step.push(piece);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (piece.startsWith(':')) {
|
|
107
|
+
if (simplePseudos.has(piece.slice(1))) {
|
|
108
|
+
step.push(piece);
|
|
109
|
+
}
|
|
110
|
+
else if (pieces[i - 1]?.startsWith('#')) {
|
|
111
|
+
pieces[i - 1] += piece;
|
|
112
|
+
pieces.splice(i, 1);
|
|
113
|
+
i--;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw new SyntaxError(`Non-existing pseudo selector!\n${desanitize(piece)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
step.push(...pieces.filter(piece => piece.startsWith('#')).map(piece => desanitize(piece)));
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* 检查是否需要通用选择器
|
|
124
|
+
* @throws `SyntaxError` 非法的选择器
|
|
125
|
+
*/
|
|
126
|
+
const needUniversal = () => {
|
|
127
|
+
if (step.length === 0) {
|
|
128
|
+
throw new SyntaxError(`Invalid selector!\n${selector}\nYou may need the universal selector '*'.`);
|
|
96
129
|
}
|
|
97
|
-
step.push(desanitize(pieces.slice(0, i).join(':')), ...pieces.slice(i).map(piece => `:${piece}`));
|
|
98
130
|
};
|
|
99
131
|
while (mt) {
|
|
100
132
|
let { 0: syntax, index } = mt;
|
|
@@ -105,15 +137,14 @@ const parseSelector = (selector) => {
|
|
|
105
137
|
}
|
|
106
138
|
if (syntax === ',') { // 情形1:并列
|
|
107
139
|
pushSimple(index);
|
|
140
|
+
needUniversal();
|
|
108
141
|
condition = [[]];
|
|
109
142
|
[step] = condition;
|
|
110
143
|
stack.push(condition);
|
|
111
144
|
}
|
|
112
145
|
else if (combinator.has(syntax)) { // 情形2:关系
|
|
113
146
|
pushSimple(index);
|
|
114
|
-
|
|
115
|
-
throw new SyntaxError(`非法的选择器!\n${selector}\n可能需要通用选择器'*'。`);
|
|
116
|
-
}
|
|
147
|
+
needUniversal();
|
|
117
148
|
step.relation = syntax;
|
|
118
149
|
step = [];
|
|
119
150
|
condition.push(step);
|
|
@@ -128,12 +159,12 @@ const parseSelector = (selector) => {
|
|
|
128
159
|
regex = regularRegex;
|
|
129
160
|
}
|
|
130
161
|
else if (syntax === '(') { // 情形5:伪选择器开启
|
|
131
|
-
const
|
|
132
|
-
if (!
|
|
133
|
-
throw new SyntaxError(
|
|
162
|
+
const i = sanitized.lastIndexOf(':', index), pseudo = sanitized.slice(i + 1, index);
|
|
163
|
+
if (i === -1 || !complexPseudos.has(pseudo)) {
|
|
164
|
+
throw new SyntaxError(`Non-existing pseudo selector!\n${desanitize(sanitized)}`);
|
|
134
165
|
}
|
|
135
|
-
pushSimple(
|
|
136
|
-
step.push(
|
|
166
|
+
pushSimple(i);
|
|
167
|
+
step.push(pseudo); // 临时存放复杂伪选择器
|
|
137
168
|
regex = functionRegex;
|
|
138
169
|
}
|
|
139
170
|
else { // 情形6:伪选择器闭合
|
|
@@ -150,13 +181,10 @@ const parseSelector = (selector) => {
|
|
|
150
181
|
}
|
|
151
182
|
if (regex === regularRegex) {
|
|
152
183
|
pushSimple(Infinity);
|
|
153
|
-
|
|
154
|
-
if (pseudos.size > 0) {
|
|
155
|
-
index_1.default.warn('检测到伪选择器,请确认是否需要将":"转义成"\\:"。', pseudos);
|
|
156
|
-
}
|
|
184
|
+
needUniversal();
|
|
157
185
|
return stack;
|
|
158
186
|
}
|
|
159
|
-
throw new SyntaxError(
|
|
187
|
+
throw new SyntaxError(`Unclosed '${regex === attributeRegex ? '[' : '('}' in the selector!\n${desanitize(sanitized)}`);
|
|
160
188
|
};
|
|
161
189
|
exports.parseSelector = parseSelector;
|
|
162
190
|
constants_1.parsers['parseSelector'] = __filename;
|
package/dist/parser/table.js
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseTable = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
|
-
const index_2 = require("../src/index");
|
|
7
|
-
const index_3 = require("../src/table/index");
|
|
5
|
+
const index_1 = require("../src/index");
|
|
6
|
+
const index_2 = require("../src/table/index");
|
|
8
7
|
const tr_1 = require("../src/table/tr");
|
|
9
8
|
const td_1 = require("../src/table/td");
|
|
10
9
|
const dd_1 = require("../src/nowiki/dd");
|
|
@@ -12,14 +11,14 @@ const dd_1 = require("../src/nowiki/dd");
|
|
|
12
11
|
* 判断是否为表格行或表格
|
|
13
12
|
* @param token 表格节点
|
|
14
13
|
*/
|
|
15
|
-
const isTr = (token) => token.lastChild.constructor !==
|
|
14
|
+
const isTr = (token) => token.lastChild.constructor !== index_1.Token;
|
|
16
15
|
/**
|
|
17
16
|
* 解析表格,注意`tr`和`td`包含开头的换行
|
|
18
17
|
* @param {Token & {firstChild: AstText}} root 根节点
|
|
19
18
|
* @param config
|
|
20
19
|
* @param accum
|
|
21
20
|
*/
|
|
22
|
-
const parseTable = ({ firstChild: { data }, type, name }, config
|
|
21
|
+
const parseTable = ({ firstChild: { data }, type, name }, config, accum) => {
|
|
23
22
|
const stack = [], lines = data.split('\n');
|
|
24
23
|
let out = type === 'root' || type === 'parameter-value' || type === 'ext-inner' && name === 'poem'
|
|
25
24
|
? ''
|
|
@@ -36,7 +35,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config = index_1.defau
|
|
|
36
35
|
}
|
|
37
36
|
const { lastChild } = topToken;
|
|
38
37
|
if (isTr(topToken)) {
|
|
39
|
-
const token = new
|
|
38
|
+
const token = new index_1.Token(str, config, accum);
|
|
40
39
|
token.type = 'table-inter';
|
|
41
40
|
token.setAttribute('stage', 3);
|
|
42
41
|
topToken.insertAt(token);
|
|
@@ -62,7 +61,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config = index_1.defau
|
|
|
62
61
|
}
|
|
63
62
|
push(`\n${spaces}${indent && `\0${accum.length - 1}d\x7F`}${moreSpaces}\0${accum.length}b\x7F`, top);
|
|
64
63
|
// @ts-expect-error abstract class
|
|
65
|
-
stack.push(...top ? [top] : [], new
|
|
64
|
+
stack.push(...top ? [top] : [], new index_2.TableToken(tableSyntax, attr, config, accum));
|
|
66
65
|
continue;
|
|
67
66
|
}
|
|
68
67
|
else if (!top) {
|
package/dist/src/attribute.js
CHANGED
|
@@ -417,7 +417,7 @@ let AttributeToken = (() => {
|
|
|
417
417
|
/** @override */
|
|
418
418
|
print() {
|
|
419
419
|
const [quoteStart = '', quoteEnd = ''] = this.#quotes;
|
|
420
|
-
return this.#equal ? super.print({ sep: `${this.#equal}${quoteStart}`, post: quoteEnd }) : super.print();
|
|
420
|
+
return this.#equal ? super.print({ sep: `${(0, string_1.escape)(this.#equal)}${quoteStart}`, post: quoteEnd }) : super.print();
|
|
421
421
|
}
|
|
422
422
|
/* NOT FOR BROWSER */
|
|
423
423
|
/** @private */
|