wikilint 2.5.0 → 2.5.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/config/default.json +2 -3
- package/config/enwiki.json +2 -3
- package/config/llwiki.json +1 -1
- package/config/minimum.json +3 -6
- package/config/zhwiki.json +1 -1
- package/dist/base.d.ts +3 -1
- package/dist/base.js +38 -0
- package/dist/index.js +2 -0
- package/dist/lib/title.d.ts +6 -0
- package/dist/lib/title.js +15 -0
- package/dist/parser/list.js +42 -12
- package/dist/src/attribute.js +3 -2
- package/dist/src/html.d.ts +2 -0
- package/dist/src/html.js +8 -4
- package/dist/src/imageParameter.d.ts +1 -1
- package/dist/src/imageParameter.js +7 -4
- package/dist/src/link/file.d.ts +2 -0
- package/dist/src/link/file.js +6 -1
- package/dist/src/tagPair/include.js +7 -4
- package/dist/util/string.js +3 -2
- package/package.json +2 -2
package/config/default.json
CHANGED
|
@@ -767,7 +767,7 @@
|
|
|
767
767
|
"EXPECTED_UNCONNECTED_PAGE"
|
|
768
768
|
]
|
|
769
769
|
],
|
|
770
|
-
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
770
|
+
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
771
771
|
"interwiki": [],
|
|
772
772
|
"img": {
|
|
773
773
|
"thumbnail": "thumbnail",
|
|
@@ -830,8 +830,7 @@
|
|
|
830
830
|
"page=$1": "page",
|
|
831
831
|
"page $1": "page",
|
|
832
832
|
"页数=$1": "page",
|
|
833
|
-
"$1页": "page"
|
|
834
|
-
"lossy=$1": "lossy"
|
|
833
|
+
"$1页": "page"
|
|
835
834
|
},
|
|
836
835
|
"variants": [
|
|
837
836
|
"zh",
|
package/config/enwiki.json
CHANGED
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
"EXPECTED_UNCONNECTED_PAGE"
|
|
370
370
|
]
|
|
371
371
|
],
|
|
372
|
-
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
372
|
+
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
373
373
|
"interwiki": [],
|
|
374
374
|
"img": {
|
|
375
375
|
"thumbnail": "thumbnail",
|
|
@@ -404,8 +404,7 @@
|
|
|
404
404
|
"text-bottom": "text-bottom",
|
|
405
405
|
"lang=$1": "lang",
|
|
406
406
|
"page=$1": "page",
|
|
407
|
-
"page $1": "page"
|
|
408
|
-
"lossy=$1": "lossy"
|
|
407
|
+
"page $1": "page"
|
|
409
408
|
},
|
|
410
409
|
"variants": []
|
|
411
410
|
}
|
package/config/llwiki.json
CHANGED
|
@@ -518,7 +518,7 @@
|
|
|
518
518
|
"静态重定向"
|
|
519
519
|
]
|
|
520
520
|
],
|
|
521
|
-
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
521
|
+
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
522
522
|
"interwiki": [],
|
|
523
523
|
"img": {
|
|
524
524
|
"thumbnail": "thumbnail",
|
package/config/minimum.json
CHANGED
|
@@ -66,8 +66,7 @@
|
|
|
66
66
|
"wbr",
|
|
67
67
|
"hr",
|
|
68
68
|
"meta",
|
|
69
|
-
"link"
|
|
70
|
-
"img"
|
|
69
|
+
"link"
|
|
71
70
|
]
|
|
72
71
|
],
|
|
73
72
|
"namespaces": {},
|
|
@@ -82,6 +81,7 @@
|
|
|
82
81
|
"#speciale": "speciale",
|
|
83
82
|
"#tag": "tag",
|
|
84
83
|
"#formatdate": "formatdate",
|
|
84
|
+
"#dateformat": "formatdate",
|
|
85
85
|
"#invoke": "invoke",
|
|
86
86
|
"#while": "while",
|
|
87
87
|
"#dowhile": "dowhile",
|
|
@@ -118,13 +118,10 @@
|
|
|
118
118
|
],
|
|
119
119
|
[
|
|
120
120
|
"msg",
|
|
121
|
-
"原始",
|
|
122
121
|
"raw"
|
|
123
122
|
],
|
|
124
123
|
[
|
|
125
|
-
"替代",
|
|
126
124
|
"subst",
|
|
127
|
-
"安全替代",
|
|
128
125
|
"safesubst"
|
|
129
126
|
]
|
|
130
127
|
],
|
|
@@ -132,7 +129,7 @@
|
|
|
132
129
|
[],
|
|
133
130
|
[]
|
|
134
131
|
],
|
|
135
|
-
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
132
|
+
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
136
133
|
"interwiki": [],
|
|
137
134
|
"img": {},
|
|
138
135
|
"variants": []
|
package/config/zhwiki.json
CHANGED
|
@@ -707,7 +707,7 @@
|
|
|
707
707
|
"EXPECTED_UNCONNECTED_PAGE"
|
|
708
708
|
]
|
|
709
709
|
],
|
|
710
|
-
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
710
|
+
"protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|worldwind://|xmpp:",
|
|
711
711
|
"interwiki": [],
|
|
712
712
|
"img": {
|
|
713
713
|
"thumbnail": "thumbnail",
|
package/dist/base.d.ts
CHANGED
|
@@ -10,9 +10,10 @@ export interface Config {
|
|
|
10
10
|
readonly variants: string[];
|
|
11
11
|
readonly excludes?: string[];
|
|
12
12
|
}
|
|
13
|
+
export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext"];
|
|
13
14
|
export declare namespace LintError {
|
|
14
15
|
type Severity = 'error' | 'warning';
|
|
15
|
-
type Rule =
|
|
16
|
+
type Rule = typeof rules[number];
|
|
16
17
|
interface Fix {
|
|
17
18
|
readonly range: [number, number];
|
|
18
19
|
text: string;
|
|
@@ -46,6 +47,7 @@ interface AstElement extends AstNode {
|
|
|
46
47
|
export interface Parser {
|
|
47
48
|
config: string | Config;
|
|
48
49
|
i18n: string | Record<string, string> | undefined;
|
|
50
|
+
rules: readonly LintError.Rule[];
|
|
49
51
|
/** 获取解析设置 */
|
|
50
52
|
getConfig(): Config;
|
|
51
53
|
/**
|
package/dist/base.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rules = void 0;
|
|
4
|
+
exports.rules = [
|
|
5
|
+
'bold-header',
|
|
6
|
+
'format-leakage',
|
|
7
|
+
'fostered-content',
|
|
8
|
+
'h1',
|
|
9
|
+
'illegal-attr',
|
|
10
|
+
'insecure-style',
|
|
11
|
+
'invalid-gallery',
|
|
12
|
+
'invalid-imagemap',
|
|
13
|
+
'invalid-invoke',
|
|
14
|
+
'lonely-apos',
|
|
15
|
+
'lonely-bracket',
|
|
16
|
+
'lonely-http',
|
|
17
|
+
'nested-link',
|
|
18
|
+
'no-arg',
|
|
19
|
+
'no-duplicate',
|
|
20
|
+
'no-ignored',
|
|
21
|
+
'obsolete-attr',
|
|
22
|
+
'obsolete-tag',
|
|
23
|
+
'parsing-order',
|
|
24
|
+
'pipe-like',
|
|
25
|
+
'table-layout',
|
|
26
|
+
'tag-like',
|
|
27
|
+
'unbalanced-header',
|
|
28
|
+
'unclosed-comment',
|
|
29
|
+
'unclosed-quote',
|
|
30
|
+
'unclosed-table',
|
|
31
|
+
'unescaped',
|
|
32
|
+
'unknown-page',
|
|
33
|
+
'unmatched-tag',
|
|
34
|
+
'unterminated-url',
|
|
35
|
+
'url-encoding',
|
|
36
|
+
'var-anchor',
|
|
37
|
+
'void-ext',
|
|
38
|
+
];
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/* eslint n/exports-style: 0 */
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
|
+
const base_1 = require("./base");
|
|
5
6
|
const debug_1 = require("./util/debug");
|
|
6
7
|
const constants_1 = require("./util/constants");
|
|
7
8
|
const string_1 = require("./util/string");
|
|
@@ -15,6 +16,7 @@ const rootRequire = (file, dir) => require(file.startsWith('/') ? file : `../${f
|
|
|
15
16
|
const Parser = {
|
|
16
17
|
config: 'default',
|
|
17
18
|
i18n: undefined,
|
|
19
|
+
rules: base_1.rules,
|
|
18
20
|
/** @implements */
|
|
19
21
|
getConfig() {
|
|
20
22
|
if (typeof this.config === 'string') {
|
package/dist/lib/title.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import Parser from '../index';
|
|
2
2
|
/** MediaWiki页面标题对象 */
|
|
3
3
|
export declare class Title {
|
|
4
|
+
#private;
|
|
4
5
|
readonly valid: boolean;
|
|
5
6
|
ns: number;
|
|
6
7
|
fragment: string | undefined;
|
|
8
|
+
/** 不含命名空间的标题主体部分 */
|
|
9
|
+
get main(): string;
|
|
10
|
+
set main(title: string);
|
|
11
|
+
/** 扩展名 */
|
|
12
|
+
get extension(): string | undefined;
|
|
7
13
|
/**
|
|
8
14
|
* @param title 标题(含或不含命名空间前缀)
|
|
9
15
|
* @param defaultNs 命名空间
|
package/dist/lib/title.js
CHANGED
|
@@ -10,6 +10,20 @@ class Title {
|
|
|
10
10
|
fragment;
|
|
11
11
|
/** @private */
|
|
12
12
|
encoded = false;
|
|
13
|
+
#main;
|
|
14
|
+
/** 不含命名空间的标题主体部分 */
|
|
15
|
+
get main() {
|
|
16
|
+
return this.#main;
|
|
17
|
+
}
|
|
18
|
+
set main(title) {
|
|
19
|
+
title = title.replace(/_/gu, ' ').trim();
|
|
20
|
+
this.#main = title && `${title[0].toUpperCase()}${title.slice(1)}`;
|
|
21
|
+
}
|
|
22
|
+
/** 扩展名 */
|
|
23
|
+
get extension() {
|
|
24
|
+
const { main } = this, i = main.lastIndexOf('.');
|
|
25
|
+
return i === -1 ? undefined : main.slice(i + 1).toLowerCase();
|
|
26
|
+
}
|
|
13
27
|
/**
|
|
14
28
|
* @param title 标题(含或不含命名空间前缀)
|
|
15
29
|
* @param defaultNs 命名空间
|
|
@@ -61,6 +75,7 @@ class Title {
|
|
|
61
75
|
}
|
|
62
76
|
this.valid = Boolean(title || this.interwiki || selfLink && this.fragment !== undefined)
|
|
63
77
|
&& !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|]|%[\da-f]{2}/iu.test(title);
|
|
78
|
+
this.main = title;
|
|
64
79
|
}
|
|
65
80
|
}
|
|
66
81
|
exports.Title = Title;
|
package/dist/parser/list.js
CHANGED
|
@@ -22,7 +22,8 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
|
|
|
22
22
|
if (!dt) {
|
|
23
23
|
return text;
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
const { html: [normalTags] } = config, fullRegex = /:+|-\{|\0\d+[xq]\x7F/gu;
|
|
26
|
+
let regex = fullRegex, ex = regex.exec(text), lt = 0, lb = false, li = false, lc = 0;
|
|
26
27
|
/**
|
|
27
28
|
* 创建`DdToken`
|
|
28
29
|
* @param syntax `:`
|
|
@@ -33,17 +34,21 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
|
|
|
33
34
|
new dd_1.DdToken(syntax, config, accum);
|
|
34
35
|
return `${text.slice(0, index)}\0${accum.length - 1}d\x7F${text.slice(index + syntax.length)}`;
|
|
35
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* 更新 `lt`
|
|
39
|
+
* @param closing 是否是闭合标签
|
|
40
|
+
*/
|
|
41
|
+
const update = (closing) => {
|
|
42
|
+
if (!closing) {
|
|
43
|
+
lt++;
|
|
44
|
+
}
|
|
45
|
+
else if (lt) {
|
|
46
|
+
lt--;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
36
49
|
while (ex && dt) {
|
|
37
50
|
const { 0: syntax, index } = ex;
|
|
38
|
-
if (syntax
|
|
39
|
-
if (syntax.length >= dt) {
|
|
40
|
-
return dd(syntax.slice(0, dt), index);
|
|
41
|
-
}
|
|
42
|
-
dt -= syntax.length;
|
|
43
|
-
regex.lastIndex = index + 4 + String(accum.length).length;
|
|
44
|
-
text = dd(syntax, index);
|
|
45
|
-
}
|
|
46
|
-
else if (syntax === '-{') {
|
|
51
|
+
if (syntax === '-{') {
|
|
47
52
|
if (!lc) {
|
|
48
53
|
const { lastIndex } = regex;
|
|
49
54
|
regex = /-\{|\}-/gu;
|
|
@@ -51,14 +56,39 @@ const parseList = (wikitext, config = index_1.default.getConfig(), accum = []) =
|
|
|
51
56
|
}
|
|
52
57
|
lc++;
|
|
53
58
|
}
|
|
54
|
-
else {
|
|
59
|
+
else if (syntax === '}-') {
|
|
55
60
|
lc--;
|
|
56
61
|
if (!lc) {
|
|
57
62
|
const { lastIndex } = regex;
|
|
58
|
-
regex =
|
|
63
|
+
regex = fullRegex;
|
|
59
64
|
regex.lastIndex = lastIndex;
|
|
60
65
|
}
|
|
61
66
|
}
|
|
67
|
+
else if (syntax.endsWith('x\x7F')) {
|
|
68
|
+
const { name, closing, selfClosing } = accum[Number(syntax.slice(1, -2))];
|
|
69
|
+
if (!selfClosing || normalTags.includes(name)) {
|
|
70
|
+
update(closing);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (syntax.endsWith('q\x7F')) {
|
|
74
|
+
const { bold, italic } = accum[Number(syntax.slice(1, -2))];
|
|
75
|
+
if (bold) {
|
|
76
|
+
update(lb);
|
|
77
|
+
lb = !lb;
|
|
78
|
+
}
|
|
79
|
+
if (italic) {
|
|
80
|
+
update(li);
|
|
81
|
+
li = !li;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (lt === 0) { // syntax === ':'
|
|
85
|
+
if (syntax.length >= dt) {
|
|
86
|
+
return dd(syntax.slice(0, dt), index);
|
|
87
|
+
}
|
|
88
|
+
dt -= syntax.length;
|
|
89
|
+
regex.lastIndex = index + 4 + String(accum.length).length;
|
|
90
|
+
text = dd(syntax, index);
|
|
91
|
+
}
|
|
62
92
|
ex = regex.exec(text);
|
|
63
93
|
}
|
|
64
94
|
return text;
|
package/dist/src/attribute.js
CHANGED
|
@@ -20,6 +20,7 @@ const commonHtmlAttrs = new Set([
|
|
|
20
20
|
'aria-hidden',
|
|
21
21
|
'aria-label',
|
|
22
22
|
'aria-labelledby',
|
|
23
|
+
'aria-level',
|
|
23
24
|
'aria-owns',
|
|
24
25
|
'role',
|
|
25
26
|
'about',
|
|
@@ -145,7 +146,7 @@ const commonHtmlAttrs = new Set([
|
|
|
145
146
|
combobox: new Set(['placeholder', 'value', 'id', 'class', 'text', 'dropdown', 'style']),
|
|
146
147
|
}, insecureStyle = new RegExp('expression'
|
|
147
148
|
+ '|'
|
|
148
|
-
+ '(?:
|
|
149
|
+
+ '(?:accelerator|-o-link(?:-source)?|-o-replace)\\s*:'
|
|
149
150
|
+ '|'
|
|
150
151
|
+ '(?:url|image(?:-set)?)\\s*\\('
|
|
151
152
|
+ '|'
|
|
@@ -270,7 +271,7 @@ class AttributeToken extends index_2.Token {
|
|
|
270
271
|
if (lastChild.childNodes.some(child => child.type === 'text' && /\s/u.test(child.text()))) {
|
|
271
272
|
e.suggestions = [
|
|
272
273
|
{
|
|
273
|
-
desc: '
|
|
274
|
+
desc: 'close',
|
|
274
275
|
...fix,
|
|
275
276
|
},
|
|
276
277
|
];
|
package/dist/src/html.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export declare abstract class HtmlToken extends Token {
|
|
|
13
13
|
readonly childNodes: readonly [AttributesToken];
|
|
14
14
|
abstract get firstChild(): AttributesToken;
|
|
15
15
|
abstract get lastChild(): AttributesToken;
|
|
16
|
+
/** 是否自封闭 */
|
|
17
|
+
get selfClosing(): boolean;
|
|
16
18
|
/** 是否是闭合标签 */
|
|
17
19
|
get closing(): boolean;
|
|
18
20
|
/**
|
package/dist/src/html.js
CHANGED
|
@@ -41,6 +41,10 @@ class HtmlToken extends index_2.Token {
|
|
|
41
41
|
#closing;
|
|
42
42
|
#selfClosing;
|
|
43
43
|
#tag;
|
|
44
|
+
/** 是否自封闭 */
|
|
45
|
+
get selfClosing() {
|
|
46
|
+
return this.#selfClosing;
|
|
47
|
+
}
|
|
44
48
|
/** 是否是闭合标签 */
|
|
45
49
|
get closing() {
|
|
46
50
|
return this.#closing;
|
|
@@ -163,14 +167,14 @@ class HtmlToken extends index_2.Token {
|
|
|
163
167
|
* @throws `SyntaxError` 未匹配的标签
|
|
164
168
|
*/
|
|
165
169
|
findMatchingTag() {
|
|
166
|
-
const { html } = this.getAttribute('config'), { name: tagName, parentNode, closing } = this, string = (0, string_1.noWrap)(String(this));
|
|
167
|
-
if (closing && (this.#selfClosing ||
|
|
170
|
+
const { html: [normalTags, flexibleTags, voidTags] } = this.getAttribute('config'), { name: tagName, parentNode, closing } = this, string = (0, string_1.noWrap)(String(this));
|
|
171
|
+
if (closing && (this.#selfClosing || voidTags.includes(tagName))) {
|
|
168
172
|
throw new SyntaxError(`tag that is both closing and self-closing: ${string}`);
|
|
169
173
|
}
|
|
170
|
-
else if (
|
|
174
|
+
else if (voidTags.includes(tagName) || this.#selfClosing && flexibleTags.includes(tagName)) { // 自封闭标签
|
|
171
175
|
return this;
|
|
172
176
|
}
|
|
173
|
-
else if (this.#selfClosing &&
|
|
177
|
+
else if (this.#selfClosing && normalTags.includes(tagName)) {
|
|
174
178
|
throw new SyntaxError(`invalid self-closing tag: ${string}`);
|
|
175
179
|
}
|
|
176
180
|
else if (!parentNode) {
|
|
@@ -15,7 +15,7 @@ export declare abstract class ImageParameterToken extends Token {
|
|
|
15
15
|
/** 图片链接 */
|
|
16
16
|
get link(): string | Title | undefined;
|
|
17
17
|
/** @param str 图片参数 */
|
|
18
|
-
constructor(str: string, config?: Parser.Config, accum?: Token[]);
|
|
18
|
+
constructor(str: string, extension: string | undefined, config?: Parser.Config, accum?: Token[]);
|
|
19
19
|
/** @override */
|
|
20
20
|
text(): string;
|
|
21
21
|
/** @override */
|
|
@@ -6,7 +6,7 @@ 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
|
|
9
|
+
function validate(key, val, config, halfParsed = false, ext) {
|
|
10
10
|
val = val.trim();
|
|
11
11
|
let value = val.replace(/\0\d+t\x7F/gu, '').trim();
|
|
12
12
|
switch (key) {
|
|
@@ -29,11 +29,13 @@ function validate(key, val, config = index_1.default.getConfig(), halfParsed = f
|
|
|
29
29
|
return title.valid && title;
|
|
30
30
|
}
|
|
31
31
|
case 'lang':
|
|
32
|
-
return
|
|
32
|
+
return (ext === 'svg' || ext === 'svgz') && !/[^a-z\d-]/u.test(value);
|
|
33
33
|
case 'alt':
|
|
34
34
|
case 'class':
|
|
35
35
|
case 'manualthumb':
|
|
36
36
|
return true;
|
|
37
|
+
case 'page':
|
|
38
|
+
return (ext === 'djvu' || ext === 'djv') && Number(value) > 0;
|
|
37
39
|
default:
|
|
38
40
|
return !Number.isNaN(Number(value));
|
|
39
41
|
}
|
|
@@ -47,7 +49,7 @@ class ImageParameterToken extends index_2.Token {
|
|
|
47
49
|
return this.name === 'link' ? validate('link', super.text(), this.getAttribute('config')) : undefined;
|
|
48
50
|
}
|
|
49
51
|
/** @param str 图片参数 */
|
|
50
|
-
constructor(str, config = index_1.default.getConfig(), accum = []) {
|
|
52
|
+
constructor(str, extension, config = index_1.default.getConfig(), accum = []) {
|
|
51
53
|
let mt;
|
|
52
54
|
const regexes = Object.entries(config.img).map(([syntax, param]) => [
|
|
53
55
|
syntax,
|
|
@@ -56,7 +58,8 @@ class ImageParameterToken extends index_2.Token {
|
|
|
56
58
|
]), param = regexes.find(([, key, regex]) => {
|
|
57
59
|
mt = regex.exec(str);
|
|
58
60
|
return mt
|
|
59
|
-
&& (mt.length !== 4
|
|
61
|
+
&& (mt.length !== 4
|
|
62
|
+
|| validate(key, mt[2], config, true, extension) !== false);
|
|
60
63
|
});
|
|
61
64
|
// @ts-expect-error mt already assigned
|
|
62
65
|
if (param && mt) {
|
package/dist/src/link/file.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export declare abstract class FileToken extends LinkBaseToken {
|
|
|
12
12
|
readonly type: 'file' | 'gallery-image' | 'imagemap-image';
|
|
13
13
|
readonly childNodes: readonly [AtomToken, ...ImageParameterToken[]];
|
|
14
14
|
abstract get lastChild(): AtomToken | ImageParameterToken;
|
|
15
|
+
/** 扩展名 */
|
|
16
|
+
get extension(): string | undefined;
|
|
15
17
|
/**
|
|
16
18
|
* @param link 文件名
|
|
17
19
|
* @param text 图片参数
|
package/dist/src/link/file.js
CHANGED
|
@@ -40,6 +40,10 @@ const explode = (start, end, separator, str) => {
|
|
|
40
40
|
*/
|
|
41
41
|
class FileToken extends base_1.LinkBaseToken {
|
|
42
42
|
type = 'file';
|
|
43
|
+
/** 扩展名 */
|
|
44
|
+
get extension() {
|
|
45
|
+
return this.getTitle().extension;
|
|
46
|
+
}
|
|
43
47
|
/**
|
|
44
48
|
* @param link 文件名
|
|
45
49
|
* @param text 图片参数
|
|
@@ -47,9 +51,10 @@ class FileToken extends base_1.LinkBaseToken {
|
|
|
47
51
|
*/
|
|
48
52
|
constructor(link, text, config = index_1.default.getConfig(), accum = [], delimiter = '|') {
|
|
49
53
|
super(link, undefined, config, accum, delimiter);
|
|
54
|
+
const { extension } = this;
|
|
50
55
|
this.append(...explode('-{', '}-', '|', text).map(
|
|
51
56
|
// @ts-expect-error abstract class
|
|
52
|
-
part => new imageParameter_1.ImageParameterToken(part, config, accum)));
|
|
57
|
+
part => new imageParameter_1.ImageParameterToken(part, extension, config, accum)));
|
|
53
58
|
}
|
|
54
59
|
/** @override */
|
|
55
60
|
lint(start = this.getAbsoluteIndex()) {
|
|
@@ -26,10 +26,13 @@ class IncludeToken extends (0, hidden_1.hiddenToken)(index_2.TagPairToken) {
|
|
|
26
26
|
return [];
|
|
27
27
|
}
|
|
28
28
|
const e = (0, lint_1.generateForSelf)(this, { start }, 'unclosed-comment', index_1.default.msg('unclosed $1', `<${this.name}>`));
|
|
29
|
-
e.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
e.suggestions = [
|
|
30
|
+
{
|
|
31
|
+
desc: 'close',
|
|
32
|
+
range: [e.endIndex, e.endIndex],
|
|
33
|
+
text: `</${this.name}>`,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
33
36
|
return [e];
|
|
34
37
|
}
|
|
35
38
|
}
|
package/dist/util/string.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noWrap = exports.decodeHtml = exports.text = exports.escapeRegExp = exports.removeComment = exports.tidy = exports.extUrlChar = exports.extUrlCharFirst = void 0;
|
|
4
|
-
|
|
5
|
-
exports.
|
|
4
|
+
const commonExtUrlChar = '[^[\\]<>"\0-\x1F\x7F\\p{Zs}\uFFFD]';
|
|
5
|
+
exports.extUrlCharFirst = `(?:\\[[\\da-f:.]+\\]|${commonExtUrlChar})`;
|
|
6
|
+
exports.extUrlChar = `(?:${commonExtUrlChar}|\0\\d+[c!~]\x7F)*`;
|
|
6
7
|
/**
|
|
7
8
|
* 生成正则替换函数
|
|
8
9
|
* @param regex 正则表达式
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"declaration": "grep -rl --include='*.d.ts' '@private' dist/ | xargs bash sed.sh -i -E '/^\\s+\\/\\*\\* @private/,+1d'; node ./dist/bin/declaration.js",
|
|
36
|
-
"prepublishOnly": "npm run build && rm dist/internal.js dist/
|
|
36
|
+
"prepublishOnly": "npm run build && rm dist/internal.js dist/[bmpu]*/*.d.ts",
|
|
37
37
|
"build": "bash build.sh",
|
|
38
38
|
"diff": "bash diff.sh",
|
|
39
39
|
"diff:stat": "f() { git diff --stat --ignore-all-space --color=always $1 $2 -- . ':!extensions/' ':!bin/' | grep '\\.ts'; }; f",
|