wikilint 2.48.1 → 2.48.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/README.md +1 -1
- package/dist/bin/config.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/lsp.js +2 -2
- package/dist/lib/text.js +1 -11
- package/dist/parser/commentAndExt.js +99 -61
- package/dist/parser/converter.js +2 -3
- package/dist/parser/externalLinks.js +11 -6
- package/dist/parser/magicLinks.js +5 -13
- package/dist/parser/table.js +2 -3
- package/dist/src/attribute.js +1 -1
- package/dist/src/attributes.js +3 -14
- package/dist/src/commented.js +9 -14
- package/dist/src/index.js +1 -3
- package/dist/src/link/file.js +2 -3
- package/dist/src/nested.js +45 -7
- package/dist/src/parameter.js +3 -3
- package/dist/src/pre.js +8 -23
- package/dist/src/singleLine/charinsertLine.js +12 -12
- package/dist/src/tagPair/ext.js +2 -2
- package/dist/src/tagPair/translate.js +43 -13
- package/dist/util/replace.js +59 -0
- package/package.json +9 -8
package/README.md
CHANGED
package/dist/bin/config.js
CHANGED
|
@@ -41,7 +41,7 @@ const filterGadget = (id) => {
|
|
|
41
41
|
const n = Number(id);
|
|
42
42
|
return n < 2300 || n > 2303; // Gadget, Gadget talk, Gadget definition, Gadget definition talk
|
|
43
43
|
};
|
|
44
|
-
const pkg = 'wikilint', version = '2.48.
|
|
44
|
+
const pkg = 'wikilint', version = '2.48.2';
|
|
45
45
|
/**
|
|
46
46
|
* Get the parser configuration for a Wikimedia Foundation project.
|
|
47
47
|
* @param site site nickname
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
16
16
|
const common_1 = require("@bhsd/common");
|
|
17
17
|
const diff_1 = require("./util/diff");
|
|
18
18
|
/* NOT FOR BROWSER ONLY */
|
|
19
|
-
const re = new RegExp(String.raw `^https
|
|
19
|
+
const re = new RegExp(String.raw `^https?://([^./]+)\.(${common_1.wmf})\.org`, 'iu');
|
|
20
20
|
/**
|
|
21
21
|
* require一个JSON文件
|
|
22
22
|
* @param file 文件名
|
package/dist/lib/lsp.js
CHANGED
|
@@ -583,7 +583,7 @@ class LanguageService {
|
|
|
583
583
|
this.config ??= index_1.default.getConfig();
|
|
584
584
|
const { nsid, ext, html, parserFunction: [insensitive, sensitive, ...other], doubleUnderscore, protocol, img, } = this.config, tags = new Set([ext, html].flat(2));
|
|
585
585
|
const re = new RegExp('(?:' // eslint-disable-line prefer-template
|
|
586
|
-
+ String.raw `<(
|
|
586
|
+
+ String.raw `<(/?\w*)` // tag ($1)
|
|
587
587
|
+ '|'
|
|
588
588
|
+ String.raw `(\{{2,4}|\[\[)\s*([^|{}<>[\]\s][^|{}<>[\]#]*)?` // braces and brackets ($2, $3)
|
|
589
589
|
+ '|'
|
|
@@ -625,7 +625,7 @@ class LanguageService {
|
|
|
625
625
|
* @param position position / 位置
|
|
626
626
|
*/
|
|
627
627
|
async provideCompletionItems(text, position) {
|
|
628
|
-
const { re, allTags, functions, switches, jaSwitches, protocols, params, tags, ext, } = this.#prepareCompletionConfig(), { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], mt = re.exec(curLine?.slice(0, character) ?? '');
|
|
628
|
+
const { re, allTags, functions, switches, jaSwitches, protocols, params, tags, ext, } = this.#prepareCompletionConfig(), { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], mt = re.exec(curLine?.slice(Math.max(0, character - 1e4), character) ?? '');
|
|
629
629
|
if (mt?.[1] !== undefined) { // tag
|
|
630
630
|
const closing = mt[1].startsWith('/');
|
|
631
631
|
return getCompletion(allTags, 'Class', mt[1].slice(closing ? 1 : 0), position, closing && !curLine?.slice(character).trimStart().startsWith('>') ? '>' : '');
|
package/dist/lib/text.js
CHANGED
|
@@ -43,16 +43,6 @@ const errorSyntaxUrl = /* #__PURE__ */ new RegExp(source, 'giu'), noLinkTypes =
|
|
|
43
43
|
'select',
|
|
44
44
|
'textarea',
|
|
45
45
|
]);
|
|
46
|
-
const wordRegex = /* #__PURE__ */ (() => {
|
|
47
|
-
try {
|
|
48
|
-
// eslint-disable-next-line prefer-regex-literals
|
|
49
|
-
return new RegExp(String.raw `[\p{L}\p{N}_]`, 'u');
|
|
50
|
-
}
|
|
51
|
-
catch /* c8 ignore start */ {
|
|
52
|
-
return /\w/u;
|
|
53
|
-
}
|
|
54
|
-
/* c8 ignore stop */
|
|
55
|
-
})();
|
|
56
46
|
/**
|
|
57
47
|
* text node
|
|
58
48
|
*
|
|
@@ -274,7 +264,7 @@ class AstText extends node_1.AstNode {
|
|
|
274
264
|
if (char === '<') {
|
|
275
265
|
e.suggestions = [(0, lint_1.fixByEscape)(startIndex, '<')];
|
|
276
266
|
}
|
|
277
|
-
else if (char === 'h' && type !== 'link-text' &&
|
|
267
|
+
else if (char === 'h' && type !== 'link-text' && /[\p{L}\p{N}_]/u.test(previousChar ?? '')) {
|
|
278
268
|
e.suggestions = [(0, lint_1.fixBySpace)(startIndex)];
|
|
279
269
|
}
|
|
280
270
|
else if (lbrackInExtLinkText) {
|
|
@@ -3,24 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseCommentAndExt = void 0;
|
|
4
4
|
const common_1 = require("@bhsd/common");
|
|
5
5
|
const string_1 = require("../util/string");
|
|
6
|
+
const replace_1 = require("../util/replace");
|
|
6
7
|
const onlyinclude_1 = require("../src/onlyinclude");
|
|
7
8
|
const noinclude_1 = require("../src/nowiki/noinclude");
|
|
8
9
|
const include_1 = require("../src/tagPair/include");
|
|
9
10
|
const ext_1 = require("../src/tagPair/ext");
|
|
10
11
|
const comment_1 = require("../src/nowiki/comment");
|
|
11
|
-
const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>',
|
|
12
|
+
const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', getExtRegex = [false, true].map(includeOnly => {
|
|
12
13
|
const noincludeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', includeRegex = includeOnly ? 'noinclude' : 'includeonly';
|
|
13
|
-
return (0, common_1.getRegex)(exts => new RegExp(String.raw `<!--.*?(?:-->|$)|<${noincludeRegex}(
|
|
14
|
-
})(\s[^>]*?)?(?:/>|>(.*?)</(${'\\1'}\s*)>)|<(${includeRegex})(\s[^>]*?)?(?:/>|>(.*?)(?:</(${includeRegex}\s*)>|$))`, 'gisu'));
|
|
14
|
+
return (0, common_1.getRegex)(exts => new RegExp(String.raw `<!--.*?(?:-->|$)|<${noincludeRegex}(?=\s|\/?>)|</${noincludeRegex}\s*>|<(${exts})(?=\s|\/?>)|<(${includeRegex})(?=\s|\/?>)`, 'gisu'));
|
|
15
15
|
});
|
|
16
|
-
/**
|
|
17
|
-
* 更新`<onlyinclude>`和`</onlyinclude>`的位置
|
|
18
|
-
* @param wikitext
|
|
19
|
-
*/
|
|
20
|
-
const update = (wikitext) => {
|
|
21
|
-
const i = wikitext.indexOf(onlyincludeLeft);
|
|
22
|
-
return { i, j: wikitext.indexOf(onlyincludeRight, i + length) };
|
|
23
|
-
};
|
|
24
16
|
/**
|
|
25
17
|
* 解析HTML注释和扩展标签
|
|
26
18
|
* @param wikitext
|
|
@@ -30,32 +22,20 @@ const update = (wikitext) => {
|
|
|
30
22
|
*/
|
|
31
23
|
const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
|
|
32
24
|
if (includeOnly) {
|
|
33
|
-
|
|
34
|
-
if (i !== -1 &&
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 忽略未被`<onlyinclude>`和`</onlyinclude>`包裹的内容
|
|
38
|
-
* @param text 未被包裹的内容
|
|
39
|
-
*/
|
|
40
|
-
const noinclude = (text) => {
|
|
41
|
-
// @ts-expect-error abstract class
|
|
42
|
-
new noinclude_1.NoincludeToken(text, config, accum);
|
|
43
|
-
str += `\0${accum.length - 1}n\x7F`;
|
|
44
|
-
};
|
|
45
|
-
while (i !== -1 && j !== -1) {
|
|
25
|
+
const i = wikitext.indexOf(onlyincludeLeft);
|
|
26
|
+
if (i !== -1 && wikitext.includes(onlyincludeRight, i)) { // `<onlyinclude>`拥有最高优先级
|
|
27
|
+
return (0, replace_1.safeStringReplace)(wikitext, onlyincludeLeft, onlyincludeRight, false, inner => {
|
|
46
28
|
const token = `\0${accum.length}g\x7F`;
|
|
47
|
-
new onlyinclude_1.OnlyincludeToken(
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
new onlyinclude_1.OnlyincludeToken(inner, config, accum);
|
|
30
|
+
return token;
|
|
31
|
+
}, s => {
|
|
32
|
+
if (!s) {
|
|
33
|
+
return '';
|
|
50
34
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
if (wikitext) {
|
|
56
|
-
noinclude(wikitext);
|
|
57
|
-
}
|
|
58
|
-
return str;
|
|
35
|
+
// @ts-expect-error abstract class
|
|
36
|
+
new noinclude_1.NoincludeToken(s, config, accum);
|
|
37
|
+
return `\0${accum.length - 1}n\x7F`;
|
|
38
|
+
});
|
|
59
39
|
}
|
|
60
40
|
}
|
|
61
41
|
const { ext } = config;
|
|
@@ -65,45 +45,103 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
|
|
|
65
45
|
const stack = [];
|
|
66
46
|
newExt = ext.filter(e => e !== 'translate' && e !== 'tvar');
|
|
67
47
|
newConfig = { ...config, ext: newExt };
|
|
68
|
-
|
|
69
|
-
|
|
48
|
+
// 隐藏`<nowiki>`标签
|
|
49
|
+
const text = (0, replace_1.safeStringReplace)(wikitext, '<nowiki>', '</nowiki>', true, (inner, open, close) => {
|
|
50
|
+
stack.push(open + inner + close);
|
|
70
51
|
return `\0${stack.length - 1}\x7F`;
|
|
71
|
-
})
|
|
52
|
+
});
|
|
53
|
+
// 解析`<translate>`标签
|
|
54
|
+
wikitext = (0, replace_1.safePatternReplace)(text, /<translate( nowrap)?>/gu, '</translate>', (inner, [, p1]) => {
|
|
72
55
|
const l = accum.length;
|
|
73
56
|
// @ts-expect-error abstract class
|
|
74
|
-
new TranslateToken(p1,
|
|
57
|
+
new TranslateToken(p1, inner && (0, string_1.restore)(inner, stack), newConfig, accum);
|
|
75
58
|
return `\0${l}g\x7F`;
|
|
76
59
|
});
|
|
77
60
|
wikitext = (0, string_1.restore)(wikitext, stack);
|
|
78
61
|
}
|
|
79
|
-
const re = getExtRegex[includeOnly ? 1 : 0](newExt.join('|'));
|
|
62
|
+
const re = getExtRegex[includeOnly ? 1 : 0](newExt.join('|')), noMoreTags = new Set();
|
|
80
63
|
re.lastIndex = 0;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
64
|
+
let lastIndex = 0, text = '', noMoreGt = false;
|
|
65
|
+
for (let mt = re.exec(wikitext); mt; mt = re.exec(wikitext)) {
|
|
66
|
+
const [substr, name, include] = mt, tag = name || include, { index } = mt, l = accum.length;
|
|
67
|
+
text += wikitext.slice(lastIndex, index);
|
|
68
|
+
({ lastIndex } = re);
|
|
69
|
+
let ch = 'n', matched = true;
|
|
70
|
+
if (substr.startsWith('<!--')) {
|
|
71
|
+
ch = 'c';
|
|
72
|
+
const closed = substr.endsWith('-->');
|
|
73
|
+
// @ts-expect-error abstract class
|
|
74
|
+
new comment_1.CommentToken((0, string_1.restore)(substr, accum, 1)
|
|
75
|
+
.slice(4, closed ? -3 : undefined), closed, config, accum);
|
|
76
|
+
}
|
|
77
|
+
else if (noMoreGt) {
|
|
78
|
+
matched = false;
|
|
79
|
+
}
|
|
80
|
+
else if (tag) {
|
|
81
|
+
const i = wikitext.indexOf('>', lastIndex);
|
|
82
|
+
let attr, inner, closing;
|
|
83
|
+
if (i === -1) {
|
|
84
|
+
matched = false;
|
|
85
|
+
noMoreGt = true;
|
|
89
86
|
}
|
|
90
|
-
else if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
new comment_1.CommentToken((0, string_1.restore)(substr, accum, 1)
|
|
95
|
-
.slice(4, closed ? -3 : undefined), closed, config, accum);
|
|
87
|
+
else if (wikitext[i - 1] === '/') {
|
|
88
|
+
attr = wikitext.slice(lastIndex, i - 1);
|
|
89
|
+
lastIndex = i + 1;
|
|
90
|
+
re.lastIndex = lastIndex;
|
|
96
91
|
}
|
|
97
|
-
else if (
|
|
98
|
-
|
|
99
|
-
new include_1.IncludeToken(include, includeAttr && (0, string_1.restore)(includeAttr, accum, 1), includeInner && (0, string_1.restore)(includeInner, accum, 1), includeClosing, config, accum);
|
|
92
|
+
else if (noMoreTags.has(tag.toLowerCase())) {
|
|
93
|
+
matched = false;
|
|
100
94
|
}
|
|
101
95
|
else {
|
|
96
|
+
attr = wikitext.slice(lastIndex, i);
|
|
97
|
+
const after = wikitext.slice(i + 1), m = new RegExp(String.raw `</(${tag}\s*)>`, 'iu').exec(after);
|
|
98
|
+
if (m) {
|
|
99
|
+
inner = after.slice(0, m.index);
|
|
100
|
+
[, closing] = m;
|
|
101
|
+
lastIndex = i + 1 + m.index + m[0].length;
|
|
102
|
+
re.lastIndex = lastIndex;
|
|
103
|
+
}
|
|
104
|
+
else if (include) {
|
|
105
|
+
inner = after;
|
|
106
|
+
lastIndex = wikitext.length;
|
|
107
|
+
re.lastIndex = lastIndex;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
matched = false;
|
|
111
|
+
noMoreTags.add(tag.toLowerCase());
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (matched) {
|
|
115
|
+
if (name) {
|
|
116
|
+
ch = 'e';
|
|
117
|
+
// @ts-expect-error abstract class
|
|
118
|
+
new ext_1.ExtToken(name, attr, inner, closing, newConfig, include, accum);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// @ts-expect-error abstract class
|
|
122
|
+
new include_1.IncludeToken(include, attr && (0, string_1.restore)(attr, accum, 1), inner && (0, string_1.restore)(inner, accum, 1), closing, config, accum);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (substr.startsWith('</')) {
|
|
127
|
+
// @ts-expect-error abstract class
|
|
128
|
+
new noinclude_1.NoincludeToken(wikitext.slice(index, lastIndex), config, accum, true);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const i = wikitext.indexOf('>', lastIndex);
|
|
132
|
+
if (i === -1) {
|
|
133
|
+
matched = false;
|
|
134
|
+
noMoreGt = true;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
lastIndex = i + 1;
|
|
138
|
+
re.lastIndex = lastIndex;
|
|
102
139
|
// @ts-expect-error abstract class
|
|
103
|
-
new noinclude_1.NoincludeToken(
|
|
140
|
+
new noinclude_1.NoincludeToken(wikitext.slice(index, lastIndex), config, accum, true);
|
|
104
141
|
}
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
142
|
+
}
|
|
143
|
+
text += matched ? `\0${l}${ch}\x7F` : substr;
|
|
144
|
+
}
|
|
145
|
+
return text + wikitext.slice(lastIndex);
|
|
108
146
|
};
|
|
109
147
|
exports.parseCommentAndExt = parseCommentAndExt;
|
package/dist/parser/converter.js
CHANGED
|
@@ -11,8 +11,8 @@ const converter_1 = require("../src/converter");
|
|
|
11
11
|
const parseConverter = (text, config, accum) => {
|
|
12
12
|
config.regexConverter ??= new RegExp(String.raw `;(?=(?:[^;]*?=>)?\s*(?:${config.variants.join('|')})\s*:|(?:\s|\0\d+[cn]\x7F)*$)`, 'u');
|
|
13
13
|
const regex1 = /-\{/gu, regex2 = /-\{|\}-/gu, stack = [];
|
|
14
|
-
let regex = regex1
|
|
15
|
-
|
|
14
|
+
let regex = regex1;
|
|
15
|
+
for (let mt = regex.exec(text); mt; mt = regex.exec(text)) {
|
|
16
16
|
const { 0: syntax, index } = mt;
|
|
17
17
|
if (syntax === '}-') {
|
|
18
18
|
const top = stack.pop(), { length } = accum, str = text.slice(top.index + 2, index), i = str.indexOf('|'), [flags, raw] = i === -1 ? [[], str] : [str.slice(0, i).split(';'), str.slice(i + 1)], temp = raw.replace(/(&[#a-z\d]+);/giu, '$1\x01'), rules = temp.split(config.regexConverter)
|
|
@@ -30,7 +30,6 @@ const parseConverter = (text, config, accum) => {
|
|
|
30
30
|
regex = regex2;
|
|
31
31
|
regex.lastIndex = index + 2;
|
|
32
32
|
}
|
|
33
|
-
mt = regex.exec(text);
|
|
34
33
|
}
|
|
35
34
|
return text;
|
|
36
35
|
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseExternalLinks = void 0;
|
|
4
4
|
const string_1 = require("../util/string");
|
|
5
|
+
const replace_1 = require("../util/replace");
|
|
5
6
|
const extLink_1 = require("../src/extLink");
|
|
6
7
|
const magicLink_1 = require("../src/magicLink");
|
|
7
8
|
/**
|
|
@@ -12,13 +13,17 @@ const magicLink_1 = require("../src/magicLink");
|
|
|
12
13
|
* @param inFile 是否在图链中
|
|
13
14
|
*/
|
|
14
15
|
const parseExternalLinks = (wikitext, config, accum, inFile) => {
|
|
15
|
-
config.regexExternalLinks ??= new RegExp(String.raw `\[((?:\0\d+[cn]\x7F)*(?:\0\d+f\x7F|(?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\d+m\x7F)${string_1.extUrlChar}(?=[[\]<>"\t${string_1.zs}]|\0\d)))([${string_1.zs}]*(?![${string_1.zs}]))
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (
|
|
16
|
+
config.regexExternalLinks ??= new RegExp(String.raw `\[((?:\0\d+[cn]\x7F)*(?:\0\d+f\x7F|(?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\d+m\x7F)${string_1.extUrlChar}(?=[[\]<>"\t${string_1.zs}]|\0\d)))([${string_1.zs}]*(?![${string_1.zs}]))`, 'giu');
|
|
17
|
+
const re = config.regexExternalLinks;
|
|
18
|
+
return (0, replace_1.safePatternReplace)(wikitext, re, ']', (text, [, url, space]) => {
|
|
19
|
+
if (/[\x01-\x08\x0A-\x1F\uFFFD]/u.test(text)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const { length } = accum, i = url.search(/&[lg]t;/u);
|
|
23
|
+
if (i !== -1) {
|
|
19
24
|
space = '';
|
|
20
|
-
text = url.slice(
|
|
21
|
-
url = url.slice(0,
|
|
25
|
+
text = url.slice(i) + space + text;
|
|
26
|
+
url = url.slice(0, i);
|
|
22
27
|
}
|
|
23
28
|
if (inFile) {
|
|
24
29
|
// @ts-expect-error abstract class
|
|
@@ -11,23 +11,15 @@ const space = String.raw `[${string_1.zs}\t]| |�*160;|�*a0;`, sp = `(?
|
|
|
11
11
|
* @param accum
|
|
12
12
|
*/
|
|
13
13
|
const parseMagicLinks = (wikitext, config, accum) => {
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
config.regexMagicLinks = new RegExp(String.raw `(^|[^\p{L}\p{N}_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
|
|
17
|
-
}
|
|
18
|
-
catch /* c8 ignore start */ {
|
|
19
|
-
config.regexMagicLinks = new RegExp(String.raw `(^|\W)(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
|
|
20
|
-
}
|
|
21
|
-
/* c8 ignore stop */
|
|
22
|
-
}
|
|
14
|
+
config.regexMagicLinks ??= new RegExp(String.raw `(^|[^\p{L}\p{N}_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
|
|
23
15
|
return wikitext.replace(config.regexMagicLinks, (m, lead, p1) => {
|
|
24
16
|
let url = lead ? m.slice(lead.length) : m;
|
|
25
17
|
if (p1) {
|
|
26
18
|
let trail = '';
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
trail = url.slice(
|
|
30
|
-
url = url.slice(0,
|
|
19
|
+
const index = url.search(/&(?:[lg]t|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu);
|
|
20
|
+
if (index !== -1) {
|
|
21
|
+
trail = url.slice(index);
|
|
22
|
+
url = url.slice(0, index);
|
|
31
23
|
}
|
|
32
24
|
const sep = url.includes('(') ? /[^,;\\.:!?][,;\\.:!?]+$/u : /[^,;\\.:!?)][,;\\.:!?)]+$/u, sepChars = sep.exec(url);
|
|
33
25
|
if (sepChars) {
|
package/dist/parser/table.js
CHANGED
|
@@ -99,7 +99,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config, accum) => {
|
|
|
99
99
|
else {
|
|
100
100
|
top = pop(top, stack);
|
|
101
101
|
const regex = cell === '!' ? /!!|(?:\||\0\d+!\x7F){2}|\0\d+\+\x7F/gu : /(?:\||\0\d+!\x7F){2}|\0\d+\+\x7F/gu;
|
|
102
|
-
let
|
|
102
|
+
let lastIndex = 0, lastSyntax = `\n${spaces}${cell}`, mt;
|
|
103
103
|
/**
|
|
104
104
|
* 创建表格单元格
|
|
105
105
|
* @param tr 当前表格行
|
|
@@ -110,11 +110,10 @@ const parseTable = ({ firstChild: { data }, type, name }, config, accum) => {
|
|
|
110
110
|
tr.insertAt(td);
|
|
111
111
|
return td;
|
|
112
112
|
};
|
|
113
|
-
|
|
113
|
+
for (mt = regex.exec(attr); mt; mt = regex.exec(attr)) {
|
|
114
114
|
newTd(top);
|
|
115
115
|
({ lastIndex } = regex);
|
|
116
116
|
[lastSyntax] = mt;
|
|
117
|
-
mt = regex.exec(attr);
|
|
118
117
|
}
|
|
119
118
|
stack.push(top, newTd(top));
|
|
120
119
|
}
|
package/dist/src/attribute.js
CHANGED
|
@@ -14,7 +14,7 @@ const index_2 = require("./index");
|
|
|
14
14
|
const atom_1 = require("./atom");
|
|
15
15
|
/* NOT FOR BROWSER ONLY */
|
|
16
16
|
const document_1 = require("../lib/document");
|
|
17
|
-
const insecureStyle = /expression|(?:accelerator|-o-link(?:-source)?|-o-replace)\s*:|(?:url|src|image(?:-set)?)\s*\(|attr\s*\([^)]+[\s,]url/u, evil = /(?:^|\s|\*\/)(?:java|vb)script(?:\W|$)/iu, complexTypes = new Set(['ext', 'arg', 'magic-word', 'template']), itemAttrs = new Set(['itemtype', 'itemid', 'itemref']), urlAttrs = new Set([
|
|
17
|
+
const insecureStyle = /expression|(?:accelerator|-o-link(?:-source)?|-o-replace)\s*:|(?:url|src|image(?:-set)?)\s*\(|attr\s*\((?:(?!attr\s*\()[^)])+[\s,]url/u, evil = /(?:^|\s|\*\/)(?:java|vb)script(?:\W|$)/iu, complexTypes = new Set(['ext', 'arg', 'magic-word', 'template']), itemAttrs = new Set(['itemtype', 'itemid', 'itemref']), urlAttrs = new Set([
|
|
18
18
|
'about',
|
|
19
19
|
'property',
|
|
20
20
|
'resource',
|
package/dist/src/attributes.js
CHANGED
|
@@ -22,16 +22,6 @@ exports.toAttributeType = toAttributeType;
|
|
|
22
22
|
* @param type 属性类型
|
|
23
23
|
*/
|
|
24
24
|
const toDirty = (type) => `${(0, exports.toAttributeType)(type)}-dirty`;
|
|
25
|
-
const wordRegex = /* #__PURE__ */ (() => {
|
|
26
|
-
try {
|
|
27
|
-
// eslint-disable-next-line prefer-regex-literals
|
|
28
|
-
return new RegExp(String.raw `[\p{L}\p{N}]`, 'u');
|
|
29
|
-
}
|
|
30
|
-
catch /* c8 ignore start */ {
|
|
31
|
-
return /[^\W_]/u;
|
|
32
|
-
}
|
|
33
|
-
/* c8 ignore stop */
|
|
34
|
-
})();
|
|
35
25
|
const required = new Map([
|
|
36
26
|
['indicator', ['name']],
|
|
37
27
|
['langconvert', ['from', 'to']],
|
|
@@ -63,14 +53,14 @@ class AttributesToken extends index_2.Token {
|
|
|
63
53
|
this.setAttribute('name', name);
|
|
64
54
|
if (attr) {
|
|
65
55
|
const regex = /([^\s/](?:(?!\0\d+~\x7F)[^\s/=])*)(?:((?:\s(?:\s|\0\d+[cn]\x7F)*)?(?:=|\0\d+~\x7F)(?:\s|\0\d+[cn]\x7F)*)(?:(["'])(.*?)(\3|$)|(\S*)))?/gsu;
|
|
66
|
-
let out = '',
|
|
56
|
+
let out = '', lastIndex = 0;
|
|
67
57
|
const insertDirty = /** 插入无效属性 */ () => {
|
|
68
58
|
if (out) {
|
|
69
59
|
super.insertAt(new atom_1.AtomToken(out, toDirty(type), config, accum));
|
|
70
60
|
out = '';
|
|
71
61
|
}
|
|
72
62
|
};
|
|
73
|
-
|
|
63
|
+
for (let mt = regex.exec(attr); mt; mt = regex.exec(attr)) {
|
|
74
64
|
const { index, 0: full, 1: key, 2: equal, 3: quoteStart, 4: quoted, 5: quoteEnd, 6: unquoted } = mt;
|
|
75
65
|
out += attr.slice(lastIndex, index);
|
|
76
66
|
if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u
|
|
@@ -85,7 +75,6 @@ class AttributesToken extends index_2.Token {
|
|
|
85
75
|
out += full;
|
|
86
76
|
}
|
|
87
77
|
({ lastIndex } = regex);
|
|
88
|
-
mt = regex.exec(attr);
|
|
89
78
|
}
|
|
90
79
|
out += attr.slice(lastIndex);
|
|
91
80
|
insertDirty();
|
|
@@ -185,7 +174,7 @@ class AttributesToken extends index_2.Token {
|
|
|
185
174
|
}
|
|
186
175
|
}
|
|
187
176
|
else {
|
|
188
|
-
const str = attr.text().trim(), severity = s[
|
|
177
|
+
const str = attr.text().trim(), severity = s[/[\p{L}\p{N}]/u.test(str) ? 1 : 2];
|
|
189
178
|
if (str && severity) {
|
|
190
179
|
const e = (0, lint_1.generateForChild)(attr, rect, rules[0], 'invalid-attribute', severity);
|
|
191
180
|
if (computeEditInfo) {
|
package/dist/src/commented.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CommentedToken = void 0;
|
|
4
|
+
const replace_1 = require("../util/replace");
|
|
4
5
|
const index_1 = require("./index");
|
|
5
6
|
const comment_1 = require("./nowiki/comment");
|
|
6
7
|
/**
|
|
@@ -15,25 +16,19 @@ class CommentedToken extends index_1.Token {
|
|
|
15
16
|
constructor(wikitext, config, accum = []) {
|
|
16
17
|
super(undefined, config, accum, {});
|
|
17
18
|
if (wikitext) {
|
|
18
|
-
|
|
19
|
-
while (j !== false && j !== -1) {
|
|
20
|
-
if (i > lastIndex) {
|
|
21
|
-
this.insertAt(wikitext.slice(lastIndex, i));
|
|
22
|
-
}
|
|
19
|
+
(0, replace_1.safeStringReplace)(wikitext, '<!--', '-->', false, inner => {
|
|
23
20
|
// @ts-expect-error abstract class
|
|
24
|
-
this.insertAt(new comment_1.CommentToken(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.insertAt(wikitext.slice(lastIndex));
|
|
31
|
-
}
|
|
21
|
+
this.insertAt(new comment_1.CommentToken(inner, true, config, accum));
|
|
22
|
+
return '';
|
|
23
|
+
}, s => {
|
|
24
|
+
this.insertAt(s);
|
|
25
|
+
return '';
|
|
26
|
+
});
|
|
32
27
|
}
|
|
33
28
|
}
|
|
34
29
|
/** @private */
|
|
35
30
|
lint(start = this.getAbsoluteIndex()) {
|
|
36
|
-
LINT: return super.lint(start, new RegExp(String.raw `<\s*(
|
|
31
|
+
LINT: return super.lint(start, new RegExp(String.raw `<\s*(?:/\s*)?(${this.name})\b`, 'giu'));
|
|
37
32
|
}
|
|
38
33
|
}
|
|
39
34
|
exports.CommentedToken = CommentedToken;
|
package/dist/src/index.js
CHANGED
|
@@ -424,8 +424,7 @@ class Token extends element_1.AstElement {
|
|
|
424
424
|
}
|
|
425
425
|
if (!ignoreDisables) {
|
|
426
426
|
const regex = new RegExp(String.raw `<!--\s*${configurationComment}-(disable(?:(?:-next)?-line)?|enable)(\s[\sa-z,-]*)?-->`, 'gu'), ignores = [];
|
|
427
|
-
let mt = regex.exec(wikitext);
|
|
428
|
-
while (mt) {
|
|
427
|
+
for (let mt = regex.exec(wikitext); mt; mt = regex.exec(wikitext)) {
|
|
429
428
|
const { 1: type, index } = mt, detail = mt[2]?.trim();
|
|
430
429
|
let line;
|
|
431
430
|
if (type === 'disable-line' || type === 'disable-next-line') {
|
|
@@ -437,7 +436,6 @@ class Token extends element_1.AstElement {
|
|
|
437
436
|
to: type === 'enable' ? regex.lastIndex : undefined,
|
|
438
437
|
rules: detail ? new Set(detail.split(',').map(rule => rule.trim())) : undefined,
|
|
439
438
|
});
|
|
440
|
-
mt = regex.exec(wikitext);
|
|
441
439
|
}
|
|
442
440
|
errors = errors.filter(({ rule, startLine, startIndex }) => {
|
|
443
441
|
const nearest = { pos: 0 };
|
package/dist/src/link/file.js
CHANGED
|
@@ -25,8 +25,8 @@ const explode = (str) => {
|
|
|
25
25
|
return [];
|
|
26
26
|
}
|
|
27
27
|
const regex = /-\{|\}-|\|/gu, exploded = [];
|
|
28
|
-
let
|
|
29
|
-
|
|
28
|
+
let depth = 0, lastIndex = 0;
|
|
29
|
+
for (let mt = regex.exec(str); mt; mt = regex.exec(str)) {
|
|
30
30
|
const { 0: match, index } = mt;
|
|
31
31
|
if (match !== '|') {
|
|
32
32
|
depth += match === '-{' ? 1 : -1;
|
|
@@ -35,7 +35,6 @@ const explode = (str) => {
|
|
|
35
35
|
exploded.push(str.slice(lastIndex, index));
|
|
36
36
|
({ lastIndex } = regex);
|
|
37
37
|
}
|
|
38
|
-
mt = regex.exec(str);
|
|
39
38
|
}
|
|
40
39
|
exploded.push(str.slice(lastIndex));
|
|
41
40
|
return exploded;
|
package/dist/src/nested.js
CHANGED
|
@@ -40,13 +40,51 @@ class NestedToken extends index_2.Token {
|
|
|
40
40
|
wikitext &&= (0, braces_1.parseBraces)(wikitext, config, accum);
|
|
41
41
|
accum.splice(length, 1);
|
|
42
42
|
}
|
|
43
|
-
else {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
else if (wikitext) {
|
|
44
|
+
const noMoreTags = new Set();
|
|
45
|
+
regex.lastIndex = 0;
|
|
46
|
+
let lastIndex = 0, text = '';
|
|
47
|
+
for (let mt = regex.exec(wikitext); mt; mt = regex.exec(wikitext)) {
|
|
48
|
+
const i = wikitext.indexOf('>', regex.lastIndex);
|
|
49
|
+
if (i === -1) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
const [substr, name] = mt, { index } = mt;
|
|
53
|
+
text += wikitext.slice(lastIndex, index);
|
|
54
|
+
({ lastIndex } = regex);
|
|
55
|
+
let matched = true, attr, inner, closing;
|
|
56
|
+
if (wikitext[i - 1] === '/') {
|
|
57
|
+
attr = wikitext.slice(lastIndex, i - 1);
|
|
58
|
+
lastIndex = i + 1;
|
|
59
|
+
regex.lastIndex = lastIndex;
|
|
60
|
+
}
|
|
61
|
+
else if (noMoreTags.has(name.toLowerCase())) {
|
|
62
|
+
matched = false;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const after = wikitext.slice(i + 1), m = new RegExp(String.raw `</(${name}\s*)>`, 'iu').exec(after);
|
|
66
|
+
if (m) {
|
|
67
|
+
inner = after.slice(0, m.index);
|
|
68
|
+
[, closing] = m;
|
|
69
|
+
lastIndex = i + 1 + m.index + m[0].length;
|
|
70
|
+
regex.lastIndex = lastIndex;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
matched = false;
|
|
74
|
+
noMoreTags.add(name.toLowerCase());
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (matched) {
|
|
78
|
+
const str = `\0${accum.length + 1}e\x7F`;
|
|
79
|
+
// @ts-expect-error abstract class
|
|
80
|
+
new ext_1.ExtToken(name, attr, inner, closing, config, false, accum);
|
|
81
|
+
text += str;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
text += substr;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
wikitext = text + wikitext.slice(lastIndex);
|
|
50
88
|
}
|
|
51
89
|
wikitext &&= wikitext.replace(/(^|\0\d+.\x7F)([^\0]+)(?=$|\0\d+.\x7F)/gu, (_, lead, substr) => {
|
|
52
90
|
// @ts-expect-error abstract class
|
package/dist/src/parameter.js
CHANGED
|
@@ -8,7 +8,7 @@ const string_1 = require("../util/string");
|
|
|
8
8
|
const lint_1 = require("../util/lint");
|
|
9
9
|
const index_1 = __importDefault(require("../index"));
|
|
10
10
|
const index_2 = require("./index");
|
|
11
|
-
const linkRegex = /* #__PURE__ */ (() => new RegExp(
|
|
11
|
+
const linkRegex = /* #__PURE__ */ (() => new RegExp(`^https?://${string_1.extUrlCharFirst}${string_1.extUrlChar}$`, 'u'))();
|
|
12
12
|
/**
|
|
13
13
|
* template or magic word parameter
|
|
14
14
|
*
|
|
@@ -74,9 +74,9 @@ class ParameterToken extends index_2.Token {
|
|
|
74
74
|
LINT: {
|
|
75
75
|
const errors = super.lint(start, re), rule = 'unescaped', { lintConfig } = index_1.default, s = lintConfig.getSeverity(rule);
|
|
76
76
|
if (s) {
|
|
77
|
-
const { firstChild } = this,
|
|
77
|
+
const { firstChild } = this, key = firstChild.text().toLowerCase(), i = Math.max(key.lastIndexOf('http://'), key.lastIndexOf('https://')), link = i !== -1 && key.slice(i);
|
|
78
78
|
try {
|
|
79
|
-
if (link && new URL(link).search) {
|
|
79
|
+
if (link && linkRegex.test(link) && new URL(link).search) {
|
|
80
80
|
const e = (0, lint_1.generateForChild)(firstChild, { start }, rule, 'unescaped-query', s);
|
|
81
81
|
e.startIndex = e.endIndex;
|
|
82
82
|
e.startLine = e.endLine;
|
package/dist/src/pre.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PreToken = void 0;
|
|
4
4
|
const constants_1 = require("../util/constants");
|
|
5
|
+
const replace_1 = require("../util/replace");
|
|
5
6
|
const index_1 = require("./index");
|
|
6
7
|
const noinclude_1 = require("./nowiki/noinclude");
|
|
7
8
|
/**
|
|
@@ -14,29 +15,13 @@ class PreToken extends index_1.Token {
|
|
|
14
15
|
}
|
|
15
16
|
/** @class */
|
|
16
17
|
constructor(wikitext, config, accum = []) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
while (i && j) {
|
|
25
|
-
// @ts-expect-error abstract class
|
|
26
|
-
new noinclude_1.NoincludeToken(i[0], config, accum, true);
|
|
27
|
-
// @ts-expect-error abstract class
|
|
28
|
-
new noinclude_1.NoincludeToken(j[0], config, accum, true);
|
|
29
|
-
str += `${wikitext.slice(lastIndex, i.index)}\0${accum.length - 1}n\x7F${wikitext.slice(i.index + length, j.index)}\0${accum.length}n\x7F`;
|
|
30
|
-
lastIndex = j.index + length + 1;
|
|
31
|
-
opening.lastIndex = lastIndex;
|
|
32
|
-
i = opening.exec(wikitext);
|
|
33
|
-
if (i) {
|
|
34
|
-
closing.lastIndex = i.index + length;
|
|
35
|
-
}
|
|
36
|
-
j = closing.exec(wikitext);
|
|
37
|
-
}
|
|
38
|
-
wikitext = str + wikitext.slice(lastIndex);
|
|
39
|
-
}
|
|
18
|
+
wikitext &&= (0, replace_1.safeStringReplace)(wikitext, '<nowiki>', '</nowiki>', true, (inner, opening, closing) => {
|
|
19
|
+
// @ts-expect-error abstract class
|
|
20
|
+
new noinclude_1.NoincludeToken(opening, config, accum, true);
|
|
21
|
+
// @ts-expect-error abstract class
|
|
22
|
+
new noinclude_1.NoincludeToken(closing, config, accum, true);
|
|
23
|
+
return `\0${accum.length - 1}n\x7F${inner}\0${accum.length}n\x7F`;
|
|
24
|
+
});
|
|
40
25
|
super(wikitext, config, accum, {});
|
|
41
26
|
this.setAttribute('stage', constants_1.MAX_STAGE - 1);
|
|
42
27
|
}
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.CharinsertLineToken = void 0;
|
|
7
7
|
const lint_1 = require("../../util/lint");
|
|
8
|
+
const replace_1 = require("../../util/replace");
|
|
8
9
|
const rect_1 = require("../../lib/rect");
|
|
9
10
|
const index_1 = __importDefault(require("../../index"));
|
|
10
11
|
const index_2 = require("./index");
|
|
@@ -21,9 +22,9 @@ class CharinsertLineToken extends index_2.SingleLineToken {
|
|
|
21
22
|
}
|
|
22
23
|
/** @class */
|
|
23
24
|
constructor(wikitext, config, accum) {
|
|
24
|
-
super(wikitext
|
|
25
|
+
super(wikitext && (0, replace_1.safeStringReplace)(wikitext, '<nowiki>', '</nowiki>', true, (content, opening, closing) => {
|
|
25
26
|
// @ts-expect-error abstract class
|
|
26
|
-
new ext_1.ExtToken(opening, undefined, content, closing, config, false, accum);
|
|
27
|
+
new ext_1.ExtToken(opening.slice(1, -1), undefined, content, closing.slice(2, -1), config, false, accum);
|
|
27
28
|
return `\0${accum.length - 2}e\x7F`;
|
|
28
29
|
}), config, accum);
|
|
29
30
|
}
|
|
@@ -37,22 +38,21 @@ class CharinsertLineToken extends index_2.SingleLineToken {
|
|
|
37
38
|
const errors = [], str = this.childNodes.map(child => child.type === 'text'
|
|
38
39
|
? child.data
|
|
39
40
|
: `<nowiki>${child.innerText.replace(/[^+]/gu, '_')}</nowiki>`).join(''), re = /(?:^|\s)\S+/gu, rect = new rect_1.BoundingRect(this, start), msg = index_1.default.msg('invalid-content', 'charinsert');
|
|
40
|
-
let mt = re.exec(str);
|
|
41
|
-
while (mt) {
|
|
41
|
+
for (let mt = re.exec(str); mt; mt = re.exec(str)) {
|
|
42
42
|
const [item] = mt;
|
|
43
43
|
let i = item.indexOf('+');
|
|
44
44
|
if (i !== -1 && item.slice(0, i).trim()) {
|
|
45
45
|
i = item.indexOf('+', i + 1);
|
|
46
46
|
}
|
|
47
|
-
if (i
|
|
48
|
-
|
|
49
|
-
e.endIndex = start + endOffset;
|
|
50
|
-
e.endCol = e.startCol + endOffset;
|
|
51
|
-
e.startIndex += startOffset;
|
|
52
|
-
e.startCol += startOffset;
|
|
53
|
-
errors.push(e);
|
|
47
|
+
if (i === -1) {
|
|
48
|
+
continue;
|
|
54
49
|
}
|
|
55
|
-
|
|
50
|
+
const e = (0, lint_1.generateForSelf)(this, rect, rule, msg, s), startOffset = mt.index + i, endOffset = mt.index + item.length;
|
|
51
|
+
e.endIndex = start + endOffset;
|
|
52
|
+
e.endCol = e.startCol + endOffset;
|
|
53
|
+
e.startIndex += startOffset;
|
|
54
|
+
e.startCol += startOffset;
|
|
55
|
+
errors.push(e);
|
|
56
56
|
}
|
|
57
57
|
return errors;
|
|
58
58
|
}
|
package/dist/src/tagPair/ext.js
CHANGED
|
@@ -152,14 +152,14 @@ let ExtToken = (() => {
|
|
|
152
152
|
// NestedToken 依赖 ExtToken
|
|
153
153
|
const { NestedToken } = require('../nested');
|
|
154
154
|
// @ts-expect-error abstract class
|
|
155
|
-
innerToken = new NestedToken(inner, /<(option|choicetemplate)(
|
|
155
|
+
innerToken = new NestedToken(inner, /<(option|choicetemplate)(?=\s|\/?>)/gu, ['option', 'choicetemplate'], newConfig, accum);
|
|
156
156
|
break;
|
|
157
157
|
}
|
|
158
158
|
case 'combobox': {
|
|
159
159
|
// NestedToken 依赖 ExtToken
|
|
160
160
|
const { NestedToken } = require('../nested');
|
|
161
161
|
// @ts-expect-error abstract class
|
|
162
|
-
innerToken = new NestedToken(inner, /<(combooption)(
|
|
162
|
+
innerToken = new NestedToken(inner, /<(combooption)(?=\s|\/?>)/gu, ['combooption'], newConfig, accum);
|
|
163
163
|
break;
|
|
164
164
|
}
|
|
165
165
|
case 'gallery': {
|
|
@@ -22,19 +22,49 @@ class TranslateToken extends index_2.TagPairToken {
|
|
|
22
22
|
*/
|
|
23
23
|
constructor(attr, inner, config, accum = []) {
|
|
24
24
|
const attrToken = new syntax_1.SyntaxToken(attr, 'translate-attr', config, accum);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
if (inner) {
|
|
26
|
+
let result = '', lastIndex = 0, i, j, k, index;
|
|
27
|
+
const update = /** @ignore */ () => {
|
|
28
|
+
i = inner.indexOf('<tvar|', lastIndex);
|
|
29
|
+
index = i + 6;
|
|
30
|
+
j = inner.indexOf('>', index);
|
|
31
|
+
k = inner.indexOf('</>', j + 1);
|
|
32
|
+
return [i, j === index ? -1 : j, k];
|
|
33
|
+
};
|
|
34
|
+
for ([i, j, k] = update(); i !== -1 && j !== -1 && k !== -1; [i, j, k] = update()) {
|
|
35
|
+
result += inner.slice(lastIndex, i);
|
|
36
|
+
lastIndex = k + 3;
|
|
37
|
+
// @ts-expect-error abstract class
|
|
38
|
+
new tvar_1.TvarToken('tvar', inner.slice(index - 1, j), false, config, accum);
|
|
39
|
+
// @ts-expect-error abstract class
|
|
40
|
+
new tvar_1.TvarToken('', '', true, config, accum);
|
|
41
|
+
result += `\0${accum.length - 2}n\x7F${inner.slice(j + 1, k)}\0${accum.length}n\x7F`;
|
|
42
|
+
}
|
|
43
|
+
inner = result + inner.slice(lastIndex);
|
|
44
|
+
result = '';
|
|
45
|
+
lastIndex = 0;
|
|
46
|
+
const start = /<(tvar)(\s+name\s*=)/giu, end = /<\/(tvar)(\s*)>/giu;
|
|
47
|
+
for (let mt = start.exec(inner); mt; mt = start.exec(inner)) {
|
|
48
|
+
i = inner.indexOf('>', start.lastIndex);
|
|
49
|
+
const name = inner.slice(start.lastIndex, i);
|
|
50
|
+
if (i === -1 || !/^(?:\s*(?:(["']).*?\1|[^"'\s>]+))?\s*$/su.test(name)) {
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
end.lastIndex = i + 1;
|
|
54
|
+
const mt2 = end.exec(inner);
|
|
55
|
+
if (!mt2) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
// @ts-expect-error abstract class
|
|
59
|
+
new tvar_1.TvarToken(mt[1], mt[2] + name, false, config, accum);
|
|
60
|
+
// @ts-expect-error abstract class
|
|
61
|
+
new tvar_1.TvarToken(mt2[1], mt2[2], true, config, accum);
|
|
62
|
+
result += `${inner.slice(lastIndex, mt.index)}\0${accum.length - 2}n\x7F${inner.slice(i + 1, mt2.index)}\0${accum.length}n\x7F`;
|
|
63
|
+
({ lastIndex } = end);
|
|
64
|
+
start.lastIndex = lastIndex;
|
|
65
|
+
}
|
|
66
|
+
inner = result + inner.slice(lastIndex);
|
|
67
|
+
}
|
|
38
68
|
const innerToken = new index_1.Token(inner, config, accum);
|
|
39
69
|
innerToken.type = 'translate-inner';
|
|
40
70
|
super('translate', attrToken, innerToken, 'translate', config, accum);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.safePatternReplace = exports.safeStringReplace = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 使用`String#indexOf`避免正则表达式的回溯
|
|
6
|
+
* @param wikitext 源文本
|
|
7
|
+
* @param start 起始字符串
|
|
8
|
+
* @param end 结束字符串
|
|
9
|
+
* @param insensitive 是否忽略大小写
|
|
10
|
+
* @param matched 匹配到的内容处理函数
|
|
11
|
+
* @param unmatched 未匹配到的内容处理函数
|
|
12
|
+
*/
|
|
13
|
+
const safeStringReplace = (wikitext, start, end, insensitive, matched, unmatched = (str) => str) => {
|
|
14
|
+
const text = insensitive ? wikitext.toLowerCase() : wikitext, lStart = start.length, lEnd = end.length;
|
|
15
|
+
let result = '', lastIndex = 0, i, j, index;
|
|
16
|
+
const update = /** @ignore */ () => {
|
|
17
|
+
i = text.indexOf(start, lastIndex);
|
|
18
|
+
index = i + lStart;
|
|
19
|
+
return [i, text.indexOf(end, index), index];
|
|
20
|
+
};
|
|
21
|
+
for ([i, j, index] = update(); i !== -1 && j !== -1; [i, j, index] = update()) {
|
|
22
|
+
result += unmatched(wikitext.slice(lastIndex, i));
|
|
23
|
+
lastIndex = j + lEnd;
|
|
24
|
+
result += matched(wikitext.slice(index, j), insensitive ? wikitext.slice(i, index) : start, insensitive ? wikitext.slice(j, lastIndex) : end);
|
|
25
|
+
}
|
|
26
|
+
return result + unmatched(wikitext.slice(lastIndex));
|
|
27
|
+
};
|
|
28
|
+
exports.safeStringReplace = safeStringReplace;
|
|
29
|
+
/**
|
|
30
|
+
* 使用`RegExp#exec`避免正则表达式的回溯
|
|
31
|
+
* @param wikitext 源文本
|
|
32
|
+
* @param start 起始正则表达式
|
|
33
|
+
* @param end 结束字符串
|
|
34
|
+
* @param matched 匹配到的内容处理函数
|
|
35
|
+
*/
|
|
36
|
+
const safePatternReplace = (wikitext, start, end, matched) => {
|
|
37
|
+
let result = '', lastIndex = 0;
|
|
38
|
+
start.lastIndex = 0;
|
|
39
|
+
for (let mt = start.exec(wikitext); mt; mt = start.exec(wikitext)) {
|
|
40
|
+
const i = wikitext.indexOf(end, start.lastIndex);
|
|
41
|
+
if (i === -1) {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
const { index } = mt;
|
|
45
|
+
result += wikitext.slice(lastIndex, index);
|
|
46
|
+
lastIndex = i + end.length;
|
|
47
|
+
const r = matched(wikitext.slice(start.lastIndex, i), mt);
|
|
48
|
+
if (r === false) {
|
|
49
|
+
({ lastIndex } = start);
|
|
50
|
+
result += wikitext.slice(index, lastIndex);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
result += r;
|
|
54
|
+
start.lastIndex = lastIndex;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result + wikitext.slice(lastIndex);
|
|
58
|
+
};
|
|
59
|
+
exports.safePatternReplace = safePatternReplace;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.48.
|
|
3
|
+
"version": "2.48.2",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"mathoid-texvcjs": ">=0.4.0",
|
|
78
|
-
"stylelint": ">=
|
|
78
|
+
"stylelint-config-recommended": ">=14.0.0",
|
|
79
79
|
"vscode-css-languageservice": ">=3.0.0",
|
|
80
80
|
"vscode-html-languageservice": ">=3.1.0",
|
|
81
81
|
"vscode-json-languageservice": ">=3.2.0"
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"mathoid-texvcjs": {
|
|
85
85
|
"optional": true
|
|
86
86
|
},
|
|
87
|
-
"stylelint": {
|
|
87
|
+
"stylelint-config-recommended": {
|
|
88
88
|
"optional": true
|
|
89
89
|
},
|
|
90
90
|
"vscode-css-languageservice": {
|
|
@@ -100,13 +100,13 @@
|
|
|
100
100
|
"dependencies": {
|
|
101
101
|
"@bhsd/cm-util": "^2.4.2",
|
|
102
102
|
"@bhsd/common": "^4.1.0",
|
|
103
|
-
"@bhsd/stylelint-util": "^
|
|
103
|
+
"@bhsd/stylelint-util": "^2.0.0",
|
|
104
104
|
"culori": "^4.0.2",
|
|
105
105
|
"entities": "^8.1.0",
|
|
106
|
-
"vscode-languageserver-types": "^3.18.
|
|
106
|
+
"vscode-languageserver-types": "^3.18.5"
|
|
107
107
|
},
|
|
108
108
|
"devDependencies": {
|
|
109
|
-
"@bhsd/code-standard": "^5.
|
|
109
|
+
"@bhsd/code-standard": "^5.1.0",
|
|
110
110
|
"@bhsd/nodejs": "^1.2.1",
|
|
111
111
|
"@bhsd/test-util": "^3.3.0",
|
|
112
112
|
"ajv": "^8.20.0",
|
|
@@ -114,14 +114,15 @@
|
|
|
114
114
|
"c8": "^12.0.0",
|
|
115
115
|
"diff2html-cli": "^5.2.15",
|
|
116
116
|
"esbuild": "^0.28.2",
|
|
117
|
-
"eslint": "^10.
|
|
117
|
+
"eslint": "^10.14.0",
|
|
118
118
|
"mathoid-texvcjs": "^0.6.0",
|
|
119
119
|
"stylelint": "^17.16.0",
|
|
120
|
+
"stylelint-config-recommended": "^18.0.0",
|
|
120
121
|
"typescript": "^6.0.3",
|
|
121
122
|
"vscode-css-languageservice": "^6.3.10",
|
|
122
123
|
"vscode-html-languageservice": "^5.6.2",
|
|
123
124
|
"vscode-json-languageservice": "^5.7.2",
|
|
124
|
-
"vscode-languageserver-textdocument": "^1.0.
|
|
125
|
+
"vscode-languageserver-textdocument": "^1.0.16"
|
|
125
126
|
},
|
|
126
127
|
"engines": {
|
|
127
128
|
"node": "^20.19.0 || ^22.13.0 || >=24.11.0"
|