wikilint 2.6.0 → 2.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/base.d.ts +0 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10 -4
- package/dist/lib/element.d.ts +5 -0
- package/dist/lib/element.js +25 -0
- package/dist/lib/title.d.ts +10 -3
- package/dist/lib/title.js +53 -19
- 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/table.js +6 -7
- package/dist/src/extLink.js +5 -2
- package/dist/src/imageParameter.js +4 -4
- package/dist/src/imagemap.js +1 -1
- package/dist/src/index.js +28 -27
- package/dist/src/link/base.js +3 -3
- package/dist/src/link/galleryImage.js +2 -1
- package/dist/src/magicLink.js +1 -1
- package/dist/src/paramTag/inputbox.js +2 -2
- package/dist/src/table/index.js +13 -5
- package/dist/src/table/td.js +1 -1
- package/dist/src/table/trBase.js +1 -1
- package/dist/src/transclude.js +3 -3
- package/dist/util/debug.js +11 -2
- package/dist/util/diff.js +2 -2
- package/dist/util/string.js +4 -1
- package/package.json +2 -1
package/dist/base.d.ts
CHANGED
|
@@ -47,9 +47,6 @@ interface AstElement extends AstNode {
|
|
|
47
47
|
export interface Parser {
|
|
48
48
|
config: string | Config;
|
|
49
49
|
i18n: string | Record<string, string> | undefined;
|
|
50
|
-
rules: readonly LintError.Rule[];
|
|
51
|
-
/** 获取解析设置 */
|
|
52
|
-
getConfig(): Config;
|
|
53
50
|
/**
|
|
54
51
|
* 解析wikitext
|
|
55
52
|
* @param include 是否嵌入
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Config, LintError, Parser as ParserBase } from './base';
|
|
|
2
2
|
import type { Title } from './lib/title';
|
|
3
3
|
import type { Token } from './internal';
|
|
4
4
|
declare interface Parser extends ParserBase {
|
|
5
|
+
rules: readonly LintError.Rule[];
|
|
5
6
|
/**
|
|
6
7
|
* 规范化页面标题
|
|
7
8
|
* @param title 标题(含或不含命名空间前缀)
|
package/dist/index.js
CHANGED
|
@@ -37,13 +37,21 @@ const Parser = {
|
|
|
37
37
|
return msg && (this.i18n?.[msg] ?? msg).replace('$1', this.msg(arg));
|
|
38
38
|
},
|
|
39
39
|
/** @implements */
|
|
40
|
-
normalizeTitle(title, defaultNs = 0, include
|
|
40
|
+
normalizeTitle(title, defaultNs = 0, include, config = Parser.getConfig(), halfParsed, decode = false, selfLink = false) {
|
|
41
41
|
const { Title } = require('./lib/title');
|
|
42
42
|
if (halfParsed) {
|
|
43
43
|
return new Title(title, defaultNs, config, decode, selfLink);
|
|
44
44
|
}
|
|
45
45
|
const { Token } = require('./src/index');
|
|
46
46
|
const token = debug_1.Shadow.run(() => new Token(title, config).parseOnce(0, include).parseOnce()), titleObj = new Title(String(token), defaultNs, config, decode, selfLink);
|
|
47
|
+
debug_1.Shadow.run(() => {
|
|
48
|
+
for (const key of ['main', 'fragment']) {
|
|
49
|
+
const str = titleObj[key];
|
|
50
|
+
if (str?.includes('\0')) {
|
|
51
|
+
titleObj[key] = token.buildFromStr(str, constants_1.BuildMethod.Text);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
47
55
|
return titleObj;
|
|
48
56
|
},
|
|
49
57
|
/** @implements */
|
|
@@ -60,9 +68,7 @@ const Parser = {
|
|
|
60
68
|
const file = path.join(__dirname, '..', 'errors', new Date().toISOString()), stage = token.getAttribute('stage');
|
|
61
69
|
fs.writeFileSync(file, stage === constants_1.MAX_STAGE ? wikitext : String(token));
|
|
62
70
|
fs.writeFileSync(`${file}.err`, e.stack);
|
|
63
|
-
fs.writeFileSync(`${file}.json`, JSON.stringify({
|
|
64
|
-
stage, include: token.getAttribute('include'), config: this.config,
|
|
65
|
-
}, null, '\t'));
|
|
71
|
+
fs.writeFileSync(`${file}.json`, JSON.stringify({ stage, include, config }, null, '\t'));
|
|
66
72
|
}
|
|
67
73
|
throw e;
|
|
68
74
|
}
|
package/dist/lib/element.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export declare abstract class AstElement extends AstNode {
|
|
|
31
31
|
* @param selector 选择器
|
|
32
32
|
*/
|
|
33
33
|
closest<T = Token>(selector: string): T | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* 符合选择器的所有后代节点
|
|
36
|
+
* @param selector 选择器
|
|
37
|
+
*/
|
|
38
|
+
querySelectorAll<T = Token>(selector: string): T[];
|
|
34
39
|
/**
|
|
35
40
|
* 在末尾批量插入子节点
|
|
36
41
|
* @param elements 插入节点
|
package/dist/lib/element.js
CHANGED
|
@@ -70,6 +70,31 @@ class AstElement extends node_1.AstNode {
|
|
|
70
70
|
}
|
|
71
71
|
return undefined;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* 符合条件的所有后代节点
|
|
75
|
+
* @param condition 条件
|
|
76
|
+
*/
|
|
77
|
+
#getElementsBy(condition) {
|
|
78
|
+
const descendants = [];
|
|
79
|
+
for (const child of this.childNodes) {
|
|
80
|
+
if (child.type === 'text') {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
else if (condition(child)) {
|
|
84
|
+
descendants.push(child);
|
|
85
|
+
}
|
|
86
|
+
descendants.push(...child.#getElementsBy(condition));
|
|
87
|
+
}
|
|
88
|
+
return descendants;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 符合选择器的所有后代节点
|
|
92
|
+
* @param selector 选择器
|
|
93
|
+
*/
|
|
94
|
+
querySelectorAll(selector) {
|
|
95
|
+
const condition = this.#getCondition(selector);
|
|
96
|
+
return this.#getElementsBy(condition);
|
|
97
|
+
}
|
|
73
98
|
/**
|
|
74
99
|
* 在末尾批量插入子节点
|
|
75
100
|
* @param elements 插入节点
|
package/dist/lib/title.d.ts
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { Config } from '../base';
|
|
2
2
|
/** MediaWiki页面标题对象 */
|
|
3
3
|
export declare class Title {
|
|
4
4
|
#private;
|
|
5
|
-
readonly valid: boolean;
|
|
6
5
|
ns: number;
|
|
7
6
|
fragment: string | undefined;
|
|
7
|
+
interwiki: string;
|
|
8
|
+
readonly valid: boolean;
|
|
8
9
|
/** 不含命名空间的标题主体部分 */
|
|
9
10
|
get main(): string;
|
|
10
11
|
set main(title: string);
|
|
12
|
+
/** 命名空间前缀 */
|
|
13
|
+
get prefix(): string;
|
|
14
|
+
/** 完整标题 */
|
|
15
|
+
get title(): string;
|
|
11
16
|
/** 扩展名 */
|
|
12
17
|
get extension(): string | undefined;
|
|
13
18
|
/**
|
|
19
|
+
* @see MediaWikiTitleCodec::splitTitleString
|
|
20
|
+
*
|
|
14
21
|
* @param title 标题(含或不含命名空间前缀)
|
|
15
22
|
* @param defaultNs 命名空间
|
|
16
23
|
* @param decode 是否需要解码
|
|
17
24
|
* @param selfLink 是否允许selfLink
|
|
18
25
|
*/
|
|
19
|
-
constructor(title: string, defaultNs
|
|
26
|
+
constructor(title: string, defaultNs: number, config: Config, decode: boolean, selfLink: boolean);
|
|
20
27
|
}
|
package/dist/lib/title.js
CHANGED
|
@@ -2,15 +2,21 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Title = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* PHP的`rawurldecode`函数的JavaScript实现
|
|
7
|
+
* @param str 要解码的字符串
|
|
8
|
+
*/
|
|
9
|
+
const rawurldecode = (str) => decodeURIComponent(str.replace(/%(?![\da-f]{2})/giu, '%25'));
|
|
6
10
|
/** MediaWiki页面标题对象 */
|
|
7
11
|
class Title {
|
|
8
|
-
|
|
12
|
+
#main;
|
|
13
|
+
#namespaces;
|
|
9
14
|
ns;
|
|
10
15
|
fragment;
|
|
16
|
+
interwiki = '';
|
|
17
|
+
valid;
|
|
11
18
|
/** @private */
|
|
12
19
|
encoded = false;
|
|
13
|
-
#main;
|
|
14
20
|
/** 不含命名空间的标题主体部分 */
|
|
15
21
|
get main() {
|
|
16
22
|
return this.#main;
|
|
@@ -19,57 +25,85 @@ class Title {
|
|
|
19
25
|
title = title.replace(/_/gu, ' ').trim();
|
|
20
26
|
this.#main = title && `${title[0].toUpperCase()}${title.slice(1)}`;
|
|
21
27
|
}
|
|
28
|
+
/** 命名空间前缀 */
|
|
29
|
+
get prefix() {
|
|
30
|
+
const namespace = this.#namespaces[this.ns];
|
|
31
|
+
return `${namespace}${namespace && ':'}`;
|
|
32
|
+
}
|
|
33
|
+
/** 完整标题 */
|
|
34
|
+
get title() {
|
|
35
|
+
const prefix = `${this.interwiki}${this.interwiki && ':'}${this.prefix}`;
|
|
36
|
+
// eslint-disable-next-line prefer-const
|
|
37
|
+
let title = `${prefix}${this.main}`.replace(/ /gu, '_');
|
|
38
|
+
return title;
|
|
39
|
+
}
|
|
22
40
|
/** 扩展名 */
|
|
23
41
|
get extension() {
|
|
24
42
|
const { main } = this, i = main.lastIndexOf('.');
|
|
25
43
|
return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
|
|
26
44
|
}
|
|
27
45
|
/**
|
|
46
|
+
* @see MediaWikiTitleCodec::splitTitleString
|
|
47
|
+
*
|
|
28
48
|
* @param title 标题(含或不含命名空间前缀)
|
|
29
49
|
* @param defaultNs 命名空间
|
|
30
50
|
* @param decode 是否需要解码
|
|
31
51
|
* @param selfLink 是否允许selfLink
|
|
32
52
|
*/
|
|
33
|
-
constructor(title, defaultNs
|
|
53
|
+
constructor(title, defaultNs, config, decode, selfLink) {
|
|
54
|
+
const subpage = title.trim().startsWith('../');
|
|
34
55
|
title = (0, string_1.decodeHtml)(title);
|
|
35
56
|
if (decode && title.includes('%')) {
|
|
36
57
|
try {
|
|
37
58
|
const encoded = /%(?!21|3[ce]|5[bd]|7[b-d])[\da-f]{2}/iu.test(title);
|
|
38
|
-
title =
|
|
59
|
+
title = rawurldecode(title);
|
|
39
60
|
this.encoded = encoded;
|
|
40
61
|
}
|
|
41
62
|
catch { }
|
|
42
63
|
}
|
|
43
64
|
title = title.replace(/_/gu, ' ').trim();
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
ns = 0;
|
|
47
|
-
title = title.slice(1).trim();
|
|
65
|
+
if (subpage) {
|
|
66
|
+
this.ns = 0;
|
|
48
67
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
else {
|
|
69
|
+
let ns = defaultNs;
|
|
70
|
+
if (title.startsWith(':')) {
|
|
71
|
+
ns = 0;
|
|
72
|
+
title = title.slice(1).trim();
|
|
73
|
+
}
|
|
74
|
+
const m = title.split(':');
|
|
75
|
+
if (m.length > 1) {
|
|
76
|
+
const id = config.nsid[m[0].trim().toLowerCase()];
|
|
77
|
+
if (id) {
|
|
78
|
+
ns = id;
|
|
79
|
+
title = m.slice(1).join(':').trim();
|
|
80
|
+
}
|
|
55
81
|
}
|
|
82
|
+
this.ns = ns;
|
|
56
83
|
}
|
|
57
|
-
this.ns = ns;
|
|
58
84
|
const i = title.indexOf('#');
|
|
59
85
|
if (i !== -1) {
|
|
60
86
|
let fragment = title.slice(i + 1).trimEnd();
|
|
61
87
|
if (fragment.includes('%')) {
|
|
62
88
|
try {
|
|
63
|
-
fragment =
|
|
89
|
+
fragment = rawurldecode(fragment);
|
|
64
90
|
}
|
|
65
91
|
catch { }
|
|
66
92
|
}
|
|
67
93
|
this.fragment = fragment;
|
|
68
94
|
title = title.slice(0, i).trim();
|
|
69
95
|
}
|
|
70
|
-
this.valid = Boolean(title || this.interwiki || selfLink && this.fragment !== undefined)
|
|
71
|
-
&& !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}
|
|
96
|
+
this.valid = Boolean(title || this.interwiki || selfLink && this.ns === 0 && this.fragment !== undefined)
|
|
97
|
+
&& !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|\n]|%[\da-f]{2}|(?:^|\/)\.{1,2}(?:$|\/)/iu.test(subpage ? /^(?:\.\.\/)+(.*)/u.exec(title)[1] : title);
|
|
72
98
|
this.main = title;
|
|
99
|
+
Object.defineProperties(this, {
|
|
100
|
+
encoded: { enumerable: false, writable: false },
|
|
101
|
+
});
|
|
102
|
+
this.#namespaces = config.namespaces;
|
|
103
|
+
}
|
|
104
|
+
/** @private */
|
|
105
|
+
toString() {
|
|
106
|
+
return `${this.title}${this.fragment === undefined ? '' : `#${this.fragment}`}`;
|
|
73
107
|
}
|
|
74
108
|
}
|
|
75
109
|
exports.Title = Title;
|
package/dist/parser/braces.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseBraces = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const heading_1 = require("../src/heading");
|
|
7
6
|
const transclude_1 = require("../src/transclude");
|
|
8
7
|
const arg_1 = require("../src/arg");
|
|
@@ -13,7 +12,7 @@ const arg_1 = require("../src/arg");
|
|
|
13
12
|
* @param accum
|
|
14
13
|
* @throws TranscludeToken.constructor()
|
|
15
14
|
*/
|
|
16
|
-
const parseBraces = (wikitext, config
|
|
15
|
+
const parseBraces = (wikitext, config, accum) => {
|
|
17
16
|
const source = `${config.excludes?.includes('heading') ? '' : '^(\0\\d+c\x7F)*={1,6}|'}\\[\\[|\\{{2,}|-\\{(?!\\{)`, { parserFunction: [, , , subst] } = config, stack = [], closes = { '=': '\n', '{': '\\}{2,}|\\|', '-': '\\}-', '[': '\\]\\]' }, marks = new Map([['!', '!'], ['!!', '+'], ['(!', '{'], ['!)', '}'], ['!-', '-'], ['=', '~']]);
|
|
18
17
|
let regex = new RegExp(source, 'gmu'), mt = regex.exec(wikitext), moreBraces = wikitext.includes('}}'), lastIndex;
|
|
19
18
|
while (mt
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseCommentAndExt = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
4
|
const onlyinclude_1 = require("../src/onlyinclude");
|
|
6
5
|
const noinclude_1 = require("../src/nowiki/noinclude");
|
|
7
6
|
const include_1 = require("../src/tagPair/include");
|
|
@@ -14,7 +13,7 @@ const comment_1 = require("../src/nowiki/comment");
|
|
|
14
13
|
* @param accum
|
|
15
14
|
* @param includeOnly 是否嵌入
|
|
16
15
|
*/
|
|
17
|
-
const parseCommentAndExt = (wikitext, config
|
|
16
|
+
const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
|
|
18
17
|
const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft;
|
|
19
18
|
/** 更新`<onlyinclude>`和`</onlyinclude>`的位置 */
|
|
20
19
|
const update = () => {
|
package/dist/parser/converter.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseConverter = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
4
|
const converter_1 = require("../src/converter");
|
|
6
5
|
/**
|
|
7
6
|
* 解析语言变体转换
|
|
@@ -9,7 +8,7 @@ const converter_1 = require("../src/converter");
|
|
|
9
8
|
* @param config
|
|
10
9
|
* @param accum
|
|
11
10
|
*/
|
|
12
|
-
const parseConverter = (text, config
|
|
11
|
+
const parseConverter = (text, config, accum) => {
|
|
13
12
|
const regex1 = /-\{/gu, regex2 = /-\{|\}-/gu, stack = [];
|
|
14
13
|
let regex = regex1, mt = regex.exec(text);
|
|
15
14
|
while (mt) {
|
|
@@ -2,26 +2,39 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseExternalLinks = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const extLink_1 = require("../src/extLink");
|
|
6
|
+
const magicLink_1 = require("../src/magicLink");
|
|
7
7
|
/**
|
|
8
8
|
* 解析外部链接
|
|
9
9
|
* @param wikitext
|
|
10
10
|
* @param config
|
|
11
11
|
* @param accum
|
|
12
|
+
* @param inFile 是否在图链中
|
|
12
13
|
*/
|
|
13
|
-
const parseExternalLinks = (wikitext, config
|
|
14
|
+
const parseExternalLinks = (wikitext, config, accum, inFile) => {
|
|
14
15
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
15
16
|
/\[((?:\[[\da-f:.]+\]|[^[\]\t\n\p{Zs}])[^[\]\t\n\p{Zs}]*(?=[[\]\t\p{Zs}]|\0\d))(\p{Zs}*(?=\P{Zs}))([^\]\n]*)\]/giu;
|
|
16
|
-
const regex = new RegExp(
|
|
17
|
-
+
|
|
17
|
+
const regex = new RegExp('\\[' // 左括号
|
|
18
|
+
+ `(${'\0\\d+f\x7F' // 预先解析的MagicLinkToken
|
|
19
|
+
+ '|'
|
|
20
|
+
+ `(?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\\d+m\x7F)${string_1.extUrlChar}(?=[[\\]<>"\\t\\p{Zs}]|\0\\d)`})` // 链接网址
|
|
21
|
+
+ '(\\p{Zs}*(?=\\P{Zs}))' // 空格
|
|
22
|
+
+ '([^\\]\x01-\x08\x0A-\x1F\uFFFD]*)' // 链接文字
|
|
23
|
+
+ '\\]', // 右括号
|
|
24
|
+
'giu');
|
|
18
25
|
return wikitext.replace(regex, (_, url, space, text) => {
|
|
19
|
-
const { length } = accum
|
|
26
|
+
const { length } = accum;
|
|
27
|
+
const mt = /&[lg]t;/u.exec(url);
|
|
20
28
|
if (mt) {
|
|
21
29
|
url = url.slice(0, mt.index);
|
|
22
30
|
space = '';
|
|
23
31
|
text = `${url.slice(mt.index)}${space}${text}`;
|
|
24
32
|
}
|
|
33
|
+
if (inFile) {
|
|
34
|
+
// @ts-expect-error abstract class
|
|
35
|
+
new magicLink_1.MagicLinkToken(url, true, config, accum);
|
|
36
|
+
return `[\0${length}f\x7F${space}${text}]`;
|
|
37
|
+
}
|
|
25
38
|
// @ts-expect-error abstract class
|
|
26
39
|
new extLink_1.ExtLinkToken(url, space, text, config, accum);
|
|
27
40
|
return `\0${length}w\x7F`;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseHrAndDoubleUnderscore = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
4
|
const hr_1 = require("../src/nowiki/hr");
|
|
6
5
|
const doubleUnderscore_1 = require("../src/nowiki/doubleUnderscore");
|
|
7
6
|
const heading_1 = require("../src/heading");
|
|
@@ -11,7 +10,7 @@ const heading_1 = require("../src/heading");
|
|
|
11
10
|
* @param config
|
|
12
11
|
* @param accum
|
|
13
12
|
*/
|
|
14
|
-
const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config
|
|
13
|
+
const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config, accum) => {
|
|
15
14
|
const { doubleUnderscore } = config, insensitive = new Set(doubleUnderscore[0]), sensitive = new Set(doubleUnderscore[1]);
|
|
16
15
|
if (type !== 'root' && (type !== 'ext-inner' || name !== 'poem')) {
|
|
17
16
|
data = `\0${data}`;
|
package/dist/parser/html.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseHtml = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
4
|
const attributes_1 = require("../src/attributes");
|
|
6
5
|
const html_1 = require("../src/html");
|
|
7
6
|
/**
|
|
@@ -10,7 +9,7 @@ const html_1 = require("../src/html");
|
|
|
10
9
|
* @param config
|
|
11
10
|
* @param accum
|
|
12
11
|
*/
|
|
13
|
-
const parseHtml = (wikitext, config
|
|
12
|
+
const parseHtml = (wikitext, config, accum) => {
|
|
14
13
|
const regex = /^(\/?)([a-z][^\s/>]*)((?:\s|\/(?!>))[^>]*?)?(\/?>)([^<]*)$/iu, elements = new Set(config.html.flat()), bits = wikitext.split('<');
|
|
15
14
|
let text = bits.shift();
|
|
16
15
|
for (const x of bits) {
|
|
@@ -19,18 +18,18 @@ const parseHtml = (wikitext, config = index_1.default.getConfig(), accum = []) =
|
|
|
19
18
|
text += `<${x}`;
|
|
20
19
|
continue;
|
|
21
20
|
}
|
|
22
|
-
const [, slash, , params = '', brace, rest] = mt,
|
|
21
|
+
const [, slash, , params = '', brace, rest] = mt, { length } = accum,
|
|
23
22
|
// @ts-expect-error abstract class
|
|
24
|
-
|
|
25
|
-
if (name === 'meta' && (itemprop === undefined ||
|
|
26
|
-
|| name === 'link' && (itemprop === undefined ||
|
|
23
|
+
attrs = new attributes_1.AttributesToken(params, 'html-attrs', name, config, accum), itemprop = attrs.getAttr('itemprop');
|
|
24
|
+
if (name === 'meta' && (itemprop === undefined || attrs.getAttr('content') === undefined)
|
|
25
|
+
|| name === 'link' && (itemprop === undefined || attrs.getAttr('href') === undefined)) {
|
|
27
26
|
text += `<${x}`;
|
|
28
|
-
accum.
|
|
27
|
+
accum.length = length;
|
|
29
28
|
continue;
|
|
30
29
|
}
|
|
31
30
|
text += `\0${accum.length}x\x7F${rest}`;
|
|
32
31
|
// @ts-expect-error abstract class
|
|
33
|
-
new html_1.HtmlToken(t,
|
|
32
|
+
new html_1.HtmlToken(t, attrs, slash === '/', brace === '/>', config, accum);
|
|
34
33
|
}
|
|
35
34
|
return text;
|
|
36
35
|
};
|
package/dist/parser/links.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseLinks = void 0;
|
|
4
4
|
const index_1 = require("../index");
|
|
5
|
+
const quotes_1 = require("./quotes");
|
|
6
|
+
const externalLinks_1 = require("./externalLinks");
|
|
5
7
|
const index_2 = require("../src/link/index");
|
|
6
8
|
const file_1 = require("../src/link/file");
|
|
7
9
|
const category_1 = require("../src/link/category");
|
|
@@ -11,8 +13,7 @@ const category_1 = require("../src/link/category");
|
|
|
11
13
|
* @param config
|
|
12
14
|
* @param accum
|
|
13
15
|
*/
|
|
14
|
-
const parseLinks = (wikitext, config
|
|
15
|
-
const { parseQuotes } = require('./quotes');
|
|
16
|
+
const parseLinks = (wikitext, config, accum) => {
|
|
16
17
|
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('[[');
|
|
17
18
|
let s = bits.shift();
|
|
18
19
|
for (let i = 0; i < bits.length; i++) {
|
|
@@ -74,17 +75,18 @@ const parseLinks = (wikitext, config = index_1.default.getConfig(), accum = [])
|
|
|
74
75
|
continue;
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
|
-
text &&= parseQuotes(text, config, accum);
|
|
78
|
-
s += `\0${accum.length}l\x7F${after}`;
|
|
78
|
+
text &&= (0, quotes_1.parseQuotes)(text, config, accum);
|
|
79
79
|
let SomeLinkToken = index_2.LinkToken;
|
|
80
80
|
if (!force) {
|
|
81
81
|
if (!interwiki && ns === 6) {
|
|
82
|
+
text &&= (0, externalLinks_1.parseExternalLinks)(text, config, accum, true);
|
|
82
83
|
SomeLinkToken = file_1.FileToken;
|
|
83
84
|
}
|
|
84
85
|
else if (!interwiki && ns === 14) {
|
|
85
86
|
SomeLinkToken = category_1.CategoryToken;
|
|
86
87
|
}
|
|
87
88
|
}
|
|
89
|
+
s += `\0${accum.length}l\x7F${after}`;
|
|
88
90
|
// @ts-expect-error abstract class
|
|
89
91
|
new SomeLinkToken(link, text, config, accum, delimiter);
|
|
90
92
|
}
|
package/dist/parser/list.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseList = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
4
|
const list_1 = require("../src/nowiki/list");
|
|
6
5
|
const dd_1 = require("../src/nowiki/dd");
|
|
7
6
|
/**
|
|
@@ -10,7 +9,7 @@ const dd_1 = require("../src/nowiki/dd");
|
|
|
10
9
|
* @param config
|
|
11
10
|
* @param accum
|
|
12
11
|
*/
|
|
13
|
-
const parseList = (wikitext, config
|
|
12
|
+
const parseList = (wikitext, config, accum) => {
|
|
14
13
|
const mt = /^((?:\0\d+c\x7F)*)([;:*#]+)/u.exec(wikitext);
|
|
15
14
|
if (!mt) {
|
|
16
15
|
return wikitext;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseMagicLinks = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
|
-
const index_1 = require("../index");
|
|
6
5
|
const magicLink_1 = require("../src/magicLink");
|
|
7
6
|
/**
|
|
8
7
|
* 解析自由外链
|
|
@@ -10,18 +9,18 @@ const magicLink_1 = require("../src/magicLink");
|
|
|
10
9
|
* @param config
|
|
11
10
|
* @param accum
|
|
12
11
|
*/
|
|
13
|
-
const parseMagicLinks = (wikitext, config
|
|
12
|
+
const parseMagicLinks = (wikitext, config, accum) => {
|
|
14
13
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
15
14
|
/(^|[^\p{L}\d_])((?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])(?:[^[\]<>"\0\t\n\p{Zs}]|\0\d+c\x7F)*)/giu;
|
|
16
15
|
const regex = new RegExp(`(^|[^\\p{L}\\d_])(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})`, 'giu');
|
|
17
16
|
return wikitext.replace(regex, (m, lead, p1) => {
|
|
18
|
-
let trail = '', url = lead ? m.slice(
|
|
17
|
+
let trail = '', url = lead ? m.slice(lead.length) : m;
|
|
19
18
|
const m2 = /&(?:lt|gt|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu.exec(url);
|
|
20
19
|
if (m2) {
|
|
21
20
|
trail = url.slice(m2.index);
|
|
22
21
|
url = url.slice(0, m2.index);
|
|
23
22
|
}
|
|
24
|
-
const sep = new RegExp(`[
|
|
23
|
+
const sep = new RegExp(`[,;\\\\.:!?${url.includes('(') ? '' : ')'}]+$`, 'u'), sepChars = sep.exec(url);
|
|
25
24
|
if (sepChars) {
|
|
26
25
|
let correction = 0;
|
|
27
26
|
if (sepChars[0].startsWith(';') && /&(?:[a-z]+|#x[\da-f]+|#\d+)$/iu.test(url.slice(0, sepChars.index))) {
|
package/dist/parser/quotes.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseQuotes = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
4
|
const quote_1 = require("../src/nowiki/quote");
|
|
6
5
|
/**
|
|
7
6
|
* 解析单引号
|
|
@@ -9,7 +8,7 @@ const quote_1 = require("../src/nowiki/quote");
|
|
|
9
8
|
* @param config
|
|
10
9
|
* @param accum
|
|
11
10
|
*/
|
|
12
|
-
const parseQuotes = (wikitext, config
|
|
11
|
+
const parseQuotes = (wikitext, config, accum) => {
|
|
13
12
|
const arr = wikitext.split(/('{2,})/u), { length } = arr;
|
|
14
13
|
if (length === 1) {
|
|
15
14
|
return wikitext;
|
package/dist/parser/table.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseTable = void 0;
|
|
4
|
-
const index_1 = require("../index");
|
|
5
|
-
const index_2 = require("../src/index");
|
|
6
|
-
const index_3 = require("../src/table/index");
|
|
4
|
+
const index_1 = require("../src/index");
|
|
5
|
+
const index_2 = require("../src/table/index");
|
|
7
6
|
const tr_1 = require("../src/table/tr");
|
|
8
7
|
const td_1 = require("../src/table/td");
|
|
9
8
|
const dd_1 = require("../src/nowiki/dd");
|
|
@@ -11,14 +10,14 @@ const dd_1 = require("../src/nowiki/dd");
|
|
|
11
10
|
* 判断是否为表格行或表格
|
|
12
11
|
* @param token 表格节点
|
|
13
12
|
*/
|
|
14
|
-
const isTr = (token) => token.lastChild.constructor !==
|
|
13
|
+
const isTr = (token) => token.lastChild.constructor !== index_1.Token;
|
|
15
14
|
/**
|
|
16
15
|
* 解析表格,注意`tr`和`td`包含开头的换行
|
|
17
16
|
* @param {Token & {firstChild: AstText}} root 根节点
|
|
18
17
|
* @param config
|
|
19
18
|
* @param accum
|
|
20
19
|
*/
|
|
21
|
-
const parseTable = ({ firstChild: { data }, type, name }, config
|
|
20
|
+
const parseTable = ({ firstChild: { data }, type, name }, config, accum) => {
|
|
22
21
|
const stack = [], lines = data.split('\n');
|
|
23
22
|
let out = type === 'root' || type === 'parameter-value' || type === 'ext-inner' && name === 'poem'
|
|
24
23
|
? ''
|
|
@@ -35,7 +34,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config = index_1.defau
|
|
|
35
34
|
}
|
|
36
35
|
const { lastChild } = topToken;
|
|
37
36
|
if (isTr(topToken)) {
|
|
38
|
-
const token = new
|
|
37
|
+
const token = new index_1.Token(str, config, accum);
|
|
39
38
|
token.type = 'table-inter';
|
|
40
39
|
token.setAttribute('stage', 3);
|
|
41
40
|
topToken.insertAt(token);
|
|
@@ -61,7 +60,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config = index_1.defau
|
|
|
61
60
|
}
|
|
62
61
|
push(`\n${spaces}${indent && `\0${accum.length - 1}d\x7F`}${moreSpaces}\0${accum.length}b\x7F`, top);
|
|
63
62
|
// @ts-expect-error abstract class
|
|
64
|
-
stack.push(...top ? [top] : [], new
|
|
63
|
+
stack.push(...top ? [top] : [], new index_2.TableToken(tableSyntax, attr, config, accum));
|
|
65
64
|
continue;
|
|
66
65
|
}
|
|
67
66
|
else if (!top) {
|
package/dist/src/extLink.js
CHANGED
|
@@ -20,8 +20,11 @@ class ExtLinkToken extends index_2.Token {
|
|
|
20
20
|
*/
|
|
21
21
|
constructor(url, space = '', text = '', config = index_1.default.getConfig(), accum = []) {
|
|
22
22
|
super(undefined, config, accum, {});
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const link = url && /\0\d+f\x7F/u.test(url)
|
|
24
|
+
? accum[Number(url.slice(1, -2))]
|
|
25
|
+
// @ts-expect-error abstract class
|
|
26
|
+
: new magicLink_1.MagicLinkToken(url, true, config, accum);
|
|
27
|
+
this.insertAt(link);
|
|
25
28
|
this.#space = space;
|
|
26
29
|
if (text) {
|
|
27
30
|
const inner = new index_2.Token(text, config, accum, {});
|
|
@@ -6,12 +6,12 @@ const lint_1 = require("../util/lint");
|
|
|
6
6
|
const index_1 = require("../index");
|
|
7
7
|
const index_2 = require("./index");
|
|
8
8
|
exports.galleryParams = new Set(['alt', 'link', 'lang', 'page', 'caption']);
|
|
9
|
-
function validate(key, val, config, halfParsed
|
|
9
|
+
function validate(key, val, config, halfParsed, ext) {
|
|
10
10
|
val = val.trim();
|
|
11
11
|
let value = val.replace(/\0\d+t\x7F/gu, '').trim();
|
|
12
12
|
switch (key) {
|
|
13
13
|
case 'width':
|
|
14
|
-
return !value || /^(?:\d+x?|\d*x\d+)
|
|
14
|
+
return !value || /^(?:\d+x?|\d*x\d+)(?:\s*px)?$/u.test(value);
|
|
15
15
|
case 'link': {
|
|
16
16
|
if (!value) {
|
|
17
17
|
return val;
|
|
@@ -35,9 +35,9 @@ function validate(key, val, config, halfParsed = false, ext) {
|
|
|
35
35
|
case 'manualthumb':
|
|
36
36
|
return true;
|
|
37
37
|
case 'page':
|
|
38
|
-
return (ext === 'djvu' || ext === 'djv') && Number(value) > 0;
|
|
38
|
+
return (ext === 'djvu' || ext === 'djv' || ext === 'pdf') && Number(value) > 0;
|
|
39
39
|
default:
|
|
40
|
-
return !
|
|
40
|
+
return Boolean(value) && !isNaN(value);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
/** 图片参数 */
|
package/dist/src/imagemap.js
CHANGED
|
@@ -49,7 +49,7 @@ class ImagemapToken extends index_2.Token {
|
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
51
|
else if (line.includes('[')) {
|
|
52
|
-
const i = line.indexOf('['), substr = line.slice(i), mtIn = /^\[
|
|
52
|
+
const i = line.indexOf('['), substr = line.slice(i), mtIn = /^\[\[([^|]+)(?:\|([^\]]+))?\]\][\w\s]*$/u
|
|
53
53
|
.exec(substr);
|
|
54
54
|
if (mtIn) {
|
|
55
55
|
if (this.normalizeTitle(mtIn[1], 0, true, false, true).valid) {
|
package/dist/src/index.js
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
// c: CommentToken、NoIncludeToken和IncludeToken
|
|
27
27
|
// d: ListToken
|
|
28
28
|
// e: ExtToken
|
|
29
|
+
// f: MagicLinkToken inside ImageParameterToken
|
|
29
30
|
// h: HeadingToken
|
|
30
31
|
// l: LinkToken
|
|
31
32
|
// m: `{{fullurl:}}`、`{{canonicalurl:}}`或`{{filepath:}}`
|
|
@@ -128,7 +129,7 @@ class Token extends element_1.AstElement {
|
|
|
128
129
|
if (i % 2 === 0) {
|
|
129
130
|
return new text_1.AstText(s);
|
|
130
131
|
}
|
|
131
|
-
else if (
|
|
132
|
+
else if (isNaN(s.slice(-1))) {
|
|
132
133
|
return this.#accum[Number(s.slice(0, -1))];
|
|
133
134
|
}
|
|
134
135
|
throw new Error(`解析错误!未正确标记的 Token:${s}`);
|
|
@@ -164,7 +165,7 @@ class Token extends element_1.AstElement {
|
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
/** @private */
|
|
167
|
-
parse(n = constants_1.MAX_STAGE, include
|
|
168
|
+
parse(n = constants_1.MAX_STAGE, include) {
|
|
168
169
|
n = Math.min(n, constants_1.MAX_STAGE);
|
|
169
170
|
while (this.#stage < n) {
|
|
170
171
|
this.parseOnce(this.#stage, include);
|
|
@@ -315,38 +316,38 @@ class Token extends element_1.AstElement {
|
|
|
315
316
|
* @param decode 是否需要解码
|
|
316
317
|
* @param selfLink 是否允许selfLink
|
|
317
318
|
*/
|
|
318
|
-
normalizeTitle(title, defaultNs = 0, halfParsed
|
|
319
|
+
normalizeTitle(title, defaultNs = 0, halfParsed, decode, selfLink) {
|
|
319
320
|
return index_1.default.normalizeTitle(title, defaultNs, this.#include, this.#config, halfParsed, decode, selfLink);
|
|
320
321
|
}
|
|
321
322
|
/** @override */
|
|
322
323
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
323
324
|
const errors = super.lint(start, re);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
thisCat
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
325
|
+
if (this.type === 'root') {
|
|
326
|
+
const record = {};
|
|
327
|
+
for (const cat of this.querySelectorAll('category')) {
|
|
328
|
+
const thisCat = record[cat.name];
|
|
329
|
+
if (thisCat) {
|
|
330
|
+
thisCat.add(cat);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
record[cat.name] = new Set([cat]);
|
|
334
|
+
}
|
|
332
335
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
336
|
+
for (const value of Object.values(record)) {
|
|
337
|
+
if (value.size > 1) {
|
|
338
|
+
errors.push(...[...value].map(cat => {
|
|
339
|
+
const e = (0, lint_1.generateForSelf)(cat, { start: cat.getAbsoluteIndex() }, 'no-duplicate', 'duplicated category');
|
|
340
|
+
e.suggestions = [
|
|
341
|
+
{
|
|
342
|
+
desc: 'remove',
|
|
343
|
+
range: [e.startIndex, e.endIndex],
|
|
344
|
+
text: '',
|
|
345
|
+
},
|
|
346
|
+
];
|
|
347
|
+
return e;
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
347
350
|
}
|
|
348
|
-
}
|
|
349
|
-
if (this.type === 'root') {
|
|
350
351
|
const regex = /<!--\s*lint-(disable(?:(?:-next)?-line)?|enable)(\s[\sa-z,-]*)?-->/gu, wikitext = String(this), ignores = [];
|
|
351
352
|
let mt = regex.exec(wikitext), last = 0, curLine = 0;
|
|
352
353
|
while (mt) {
|
package/dist/src/link/base.js
CHANGED
|
@@ -36,12 +36,12 @@ class LinkBaseToken extends index_2.Token {
|
|
|
36
36
|
if (this.#delimiter.includes('\0')) {
|
|
37
37
|
this.#delimiter = this.buildFromStr(this.#delimiter, constants_1.BuildMethod.String);
|
|
38
38
|
}
|
|
39
|
-
this.setAttribute('name', this.#title.
|
|
39
|
+
this.setAttribute('name', this.#title.title);
|
|
40
40
|
}
|
|
41
41
|
/** @private */
|
|
42
42
|
setAttribute(key, value) {
|
|
43
43
|
if (key === 'bracket') {
|
|
44
|
-
this.#bracket =
|
|
44
|
+
this.#bracket = value;
|
|
45
45
|
}
|
|
46
46
|
else if (key === 'title') {
|
|
47
47
|
this.#title = value;
|
|
@@ -115,7 +115,7 @@ class LinkBaseToken extends index_2.Token {
|
|
|
115
115
|
return errors;
|
|
116
116
|
}
|
|
117
117
|
/** @private */
|
|
118
|
-
getTitle(halfParsed
|
|
118
|
+
getTitle(halfParsed) {
|
|
119
119
|
return this.normalizeTitle(this.firstChild.text(), 0, halfParsed, true, true);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -16,12 +16,13 @@ class GalleryImageToken extends file_1.FileToken {
|
|
|
16
16
|
constructor(type, link, text, config = index_1.default.getConfig(), accum = []) {
|
|
17
17
|
let token;
|
|
18
18
|
if (text !== undefined) {
|
|
19
|
+
const { length } = accum;
|
|
19
20
|
token = new index_2.Token(text, config, accum);
|
|
20
21
|
token.type = 'plain';
|
|
21
22
|
for (let n = 1; n < constants_1.MAX_STAGE; n++) {
|
|
22
23
|
token.parseOnce();
|
|
23
24
|
}
|
|
24
|
-
accum.splice(
|
|
25
|
+
accum.splice(length, 1);
|
|
25
26
|
}
|
|
26
27
|
super(link, token?.toString(), config, accum);
|
|
27
28
|
this.setAttribute('bracket', false);
|
package/dist/src/magicLink.js
CHANGED
|
@@ -13,7 +13,7 @@ class MagicLinkToken extends index_2.Token {
|
|
|
13
13
|
* @param url 网址
|
|
14
14
|
* @param doubleSlash 是否接受"//"作为协议
|
|
15
15
|
*/
|
|
16
|
-
constructor(url, doubleSlash
|
|
16
|
+
constructor(url, doubleSlash, config = index_1.default.getConfig(), accum = []) {
|
|
17
17
|
super(url, config, accum, {});
|
|
18
18
|
this.type = doubleSlash ? 'ext-link-url' : 'free-ext-link';
|
|
19
19
|
}
|
|
@@ -8,10 +8,10 @@ const index_2 = require("./index");
|
|
|
8
8
|
class InputboxToken extends index_2.ParamTagToken {
|
|
9
9
|
/** @class */
|
|
10
10
|
constructor(wikitext, config = index_1.default.getConfig(), accum = []) {
|
|
11
|
-
const placeholder = Symbol('InputboxToken');
|
|
11
|
+
const placeholder = Symbol('InputboxToken'), { length } = accum;
|
|
12
12
|
accum.push(placeholder);
|
|
13
13
|
wikitext &&= (0, braces_1.parseBraces)(wikitext, config, accum);
|
|
14
|
-
accum.splice(
|
|
14
|
+
accum.splice(length, 1);
|
|
15
15
|
super(wikitext, config, accum, {});
|
|
16
16
|
}
|
|
17
17
|
}
|
package/dist/src/table/index.js
CHANGED
|
@@ -60,13 +60,17 @@ class TableToken extends trBase_1.TrBaseToken {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
if (j < length) {
|
|
63
|
-
|
|
63
|
+
const e = (0, lint_1.generateForChild)(this.getNthRow(j), { start }, 'table-layout', 'inconsistent table layout', 'warning');
|
|
64
|
+
e.startIndex++;
|
|
65
|
+
e.startLine++;
|
|
66
|
+
e.startCol = 0;
|
|
67
|
+
errors.push(e);
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
return errors;
|
|
67
71
|
}
|
|
68
72
|
/** @private */
|
|
69
|
-
close(syntax = '\n|}', halfParsed
|
|
73
|
+
close(syntax = '\n|}', halfParsed) {
|
|
70
74
|
const config = this.getAttribute('config'), accum = this.getAttribute('accum'), inner = halfParsed ? [syntax] : index_1.default.parse(syntax, this.getAttribute('include'), 2, config).childNodes;
|
|
71
75
|
const token = debug_1.Shadow.run(() => super.insertAt(new syntax_1.SyntaxToken(undefined, closingPattern, 'table-syntax', config, accum, {})));
|
|
72
76
|
if (!halfParsed) {
|
|
@@ -125,12 +129,16 @@ class TableToken extends trBase_1.TrBaseToken {
|
|
|
125
129
|
* 获取指定坐标的单元格
|
|
126
130
|
* @param coords 表格坐标
|
|
127
131
|
*/
|
|
128
|
-
getNthCell(
|
|
129
|
-
|
|
132
|
+
getNthCell(
|
|
133
|
+
// eslint-disable-next-line @stylistic/comma-dangle
|
|
134
|
+
coords) {
|
|
130
135
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
136
|
+
const rawCoords = coords.row === undefined
|
|
137
|
+
? undefined
|
|
138
|
+
: coords;
|
|
131
139
|
return rawCoords && this.getNthRow(rawCoords.row, false, false)?.getNthCol(rawCoords.column);
|
|
132
140
|
}
|
|
133
|
-
getNthRow(n, force
|
|
141
|
+
getNthRow(n, force, insert) {
|
|
134
142
|
const isRow = super.getRowCount();
|
|
135
143
|
if (n === 0
|
|
136
144
|
// eslint-disable-next-line @stylistic/no-extra-parens
|
package/dist/src/table/td.js
CHANGED
|
@@ -127,7 +127,7 @@ class TdToken extends base_1.TableBaseToken {
|
|
|
127
127
|
*/
|
|
128
128
|
getAttr(key) {
|
|
129
129
|
const value = super.getAttr(key);
|
|
130
|
-
return (key === 'rowspan' || key === 'colspan' ?
|
|
130
|
+
return (key === 'rowspan' || key === 'colspan' ? parseInt(value) || 1 : value);
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
exports.TdToken = TdToken;
|
package/dist/src/table/trBase.js
CHANGED
|
@@ -39,7 +39,7 @@ class TrBaseToken extends base_1.TableBaseToken {
|
|
|
39
39
|
getRowCount() {
|
|
40
40
|
return Number(this.childNodes.some(child => child instanceof td_1.TdToken && child.isIndependent() && !child.firstChild.text().endsWith('+')));
|
|
41
41
|
}
|
|
42
|
-
getNthCol(n, insert
|
|
42
|
+
getNthCol(n, insert) {
|
|
43
43
|
let last = 0;
|
|
44
44
|
for (const child of this.childNodes.slice(2)) {
|
|
45
45
|
if (child instanceof td_1.TdToken) {
|
package/dist/src/transclude.js
CHANGED
|
@@ -69,8 +69,8 @@ class TranscludeToken extends index_2.Token {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
if (this.type === 'template') {
|
|
72
|
-
const name = (0, string_1.removeComment)(
|
|
73
|
-
if (!name
|
|
72
|
+
const name = (0, string_1.removeComment)(title).trim();
|
|
73
|
+
if (!this.normalizeTitle(name, 10, true).valid) {
|
|
74
74
|
accum.pop();
|
|
75
75
|
throw new SyntaxError('非法的模板名称');
|
|
76
76
|
}
|
|
@@ -234,7 +234,7 @@ class TranscludeToken extends index_2.Token {
|
|
|
234
234
|
* @param exact 是否匹配匿名性
|
|
235
235
|
* @param copy 是否返回一个备份
|
|
236
236
|
*/
|
|
237
|
-
getArgs(key, exact
|
|
237
|
+
getArgs(key, exact, copy = true) {
|
|
238
238
|
const keyStr = String(key).replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
|
|
239
239
|
let args;
|
|
240
240
|
if (this.#args.has(keyStr)) {
|
package/dist/util/debug.js
CHANGED
|
@@ -5,8 +5,17 @@ exports.Shadow = {
|
|
|
5
5
|
running: false,
|
|
6
6
|
/** @private */
|
|
7
7
|
run(callback) {
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const { running } = this;
|
|
9
|
+
this.running = true;
|
|
10
|
+
try {
|
|
11
|
+
const result = callback();
|
|
12
|
+
this.running = running;
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
this.running = running;
|
|
17
|
+
throw e;
|
|
18
|
+
}
|
|
10
19
|
},
|
|
11
20
|
};
|
|
12
21
|
/**
|
package/dist/util/diff.js
CHANGED
|
@@ -53,7 +53,7 @@ exports.cmd = cmd;
|
|
|
53
53
|
* @param newStr 新文本
|
|
54
54
|
* @param uid 唯一标识
|
|
55
55
|
*/
|
|
56
|
-
const diff = async (oldStr, newStr, uid
|
|
56
|
+
const diff = async (oldStr, newStr, uid) => {
|
|
57
57
|
if (oldStr === newStr) {
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
@@ -67,8 +67,8 @@ const diff = async (oldStr, newStr, uid = -1) => {
|
|
|
67
67
|
oldFile,
|
|
68
68
|
newFile,
|
|
69
69
|
]);
|
|
70
|
-
await Promise.all([fs.unlink(oldFile), fs.unlink(newFile)]);
|
|
71
70
|
console.log(stdout?.split('\n').slice(4).join('\n'));
|
|
71
|
+
await Promise.all([fs.unlink(oldFile), fs.unlink(newFile)]);
|
|
72
72
|
};
|
|
73
73
|
exports.diff = diff;
|
|
74
74
|
/** @implements */
|
package/dist/util/string.js
CHANGED
|
@@ -23,7 +23,10 @@ exports.escapeRegExp = factory(/[\\{}()|.?*+^$[\]]/gu, '\\$&');
|
|
|
23
23
|
*/
|
|
24
24
|
const text = (childNodes, separator = '') => childNodes.map(child => typeof child === 'string' ? child : child.text()).join(separator);
|
|
25
25
|
exports.text = text;
|
|
26
|
+
const names = { lt: '<', gt: '>', lbrack: '[', rbrack: ']', lbrace: '{', rbrace: '}' };
|
|
26
27
|
/** decode HTML entities */
|
|
27
|
-
exports.decodeHtml = factory(
|
|
28
|
+
exports.decodeHtml = factory(/&(?:#(\d+|x[\da-fA-F]+)|([lLgG][tT]|[lr]brac[ke]));/gu, (_, code, name) => code
|
|
29
|
+
? String.fromCodePoint(Number(`${/^x/iu.test(code) ? '0' : ''}${code}`))
|
|
30
|
+
: names[name.toLowerCase()]);
|
|
28
31
|
/** escape newlines */
|
|
29
32
|
exports.noWrap = factory(/\n/gu, '\\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"lint:ts": "tsc --noEmit && eslint --cache .",
|
|
41
41
|
"lint:json": "ajv -s config/.schema.json -d 'config/*.json' --strict=true --strict-required=false",
|
|
42
42
|
"lint": "npm run lint:ts && npm run lint:json",
|
|
43
|
+
"test": "node dist/test/test.js",
|
|
43
44
|
"test:end": "pkill -x http-server",
|
|
44
45
|
"test:real": "node dist/test/real.js"
|
|
45
46
|
},
|