wikilint 2.39.1 → 2.41.0
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 +2 -2
- package/config/.schema.json +5 -0
- package/config/default.json +11 -2
- package/config/enwiki.json +91 -89
- package/config/jawiki.json +168 -158
- package/config/llwiki.json +2 -1
- package/config/minimum.json +3 -81
- package/config/moegirl.json +2 -1
- package/config/zhwiki.json +128 -126
- package/data/signatures.json +1 -1
- package/dist/base.d.mts +9 -9
- package/dist/base.d.ts +9 -9
- package/dist/base.js +1 -0
- package/dist/base.mjs +1 -0
- package/dist/bin/cli.js +1 -1
- package/dist/bin/config.js +11 -10
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -1
- package/dist/lib/lintConfig.js +42 -23
- package/dist/lib/lsp.js +6 -12
- package/dist/lib/node.js +4 -1
- package/dist/lib/text.js +5 -2
- package/dist/lib/title.js +6 -5
- package/dist/parser/commentAndExt.js +2 -1
- package/dist/src/attribute.d.ts +4 -1
- package/dist/src/attribute.js +3 -2
- package/dist/src/attributes.js +29 -5
- package/dist/src/heading.js +8 -3
- package/dist/src/link/base.d.ts +1 -1
- package/dist/src/link/base.js +10 -4
- package/dist/src/link/file.js +2 -2
- package/dist/src/link/galleryImage.js +0 -1
- package/dist/src/magicLink.js +20 -16
- package/dist/src/multiLine/gallery.d.ts +5 -3
- package/dist/src/multiLine/gallery.js +6 -3
- package/dist/src/nowiki/base.d.ts +1 -1
- package/dist/src/parameter.js +3 -1
- package/dist/src/tagPair/ext.js +11 -5
- package/dist/src/tagPair/index.d.ts +1 -1
- package/dist/src/transclude.d.ts +6 -1
- package/dist/src/transclude.js +18 -15
- package/dist/util/constants.js +2 -1
- package/dist/util/sharable.js +2 -0
- package/dist/util/sharable.mjs +3 -1
- package/i18n/en.json +1 -0
- package/i18n/zh-hans.json +1 -0
- package/i18n/zh-hant.json +1 -0
- package/package.json +15 -27
package/dist/lib/lintConfig.js
CHANGED
|
@@ -12,8 +12,8 @@ const dict = new Map([
|
|
|
12
12
|
['error', 'error'],
|
|
13
13
|
]);
|
|
14
14
|
const defaultLintRuleConfig = {
|
|
15
|
-
'arg-in-ext': 1,
|
|
16
|
-
'blank-alt': 1,
|
|
15
|
+
'arg-in-ext': [1],
|
|
16
|
+
'blank-alt': [1],
|
|
17
17
|
'bold-header': [
|
|
18
18
|
1,
|
|
19
19
|
{
|
|
@@ -47,7 +47,7 @@ const defaultLintRuleConfig = {
|
|
|
47
47
|
// value: 2,
|
|
48
48
|
},
|
|
49
49
|
],
|
|
50
|
-
'insecure-style': 2,
|
|
50
|
+
'insecure-style': [2],
|
|
51
51
|
'invalid-gallery': [
|
|
52
52
|
2,
|
|
53
53
|
{
|
|
@@ -72,14 +72,14 @@ const defaultLintRuleConfig = {
|
|
|
72
72
|
// name: 2,
|
|
73
73
|
},
|
|
74
74
|
],
|
|
75
|
-
'invalid-isbn': 2,
|
|
75
|
+
'invalid-isbn': [2],
|
|
76
76
|
'invalid-json': [
|
|
77
77
|
2,
|
|
78
78
|
{
|
|
79
79
|
duplicate: 1,
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
|
-
'invalid-url': 1,
|
|
82
|
+
'invalid-url': [1],
|
|
83
83
|
'lonely-apos': [
|
|
84
84
|
1,
|
|
85
85
|
{
|
|
@@ -110,7 +110,7 @@ const defaultLintRuleConfig = {
|
|
|
110
110
|
// ref: 2,
|
|
111
111
|
},
|
|
112
112
|
],
|
|
113
|
-
'no-arg': 1,
|
|
113
|
+
'no-arg': [1],
|
|
114
114
|
'no-duplicate': [
|
|
115
115
|
2,
|
|
116
116
|
{
|
|
@@ -144,8 +144,8 @@ const defaultLintRuleConfig = {
|
|
|
144
144
|
// references: 2,
|
|
145
145
|
},
|
|
146
146
|
],
|
|
147
|
-
'obsolete-attr': 1,
|
|
148
|
-
'obsolete-tag': 1,
|
|
147
|
+
'obsolete-attr': [1],
|
|
148
|
+
'obsolete-tag': [1],
|
|
149
149
|
'parsing-order': [
|
|
150
150
|
2,
|
|
151
151
|
{
|
|
@@ -163,6 +163,18 @@ const defaultLintRuleConfig = {
|
|
|
163
163
|
// td: 1,
|
|
164
164
|
},
|
|
165
165
|
],
|
|
166
|
+
'required-attr': [
|
|
167
|
+
2,
|
|
168
|
+
{
|
|
169
|
+
// indicator: 2,
|
|
170
|
+
// langconvert: 2,
|
|
171
|
+
// mapframe: 2,
|
|
172
|
+
// maplink: 2,
|
|
173
|
+
// phonos: 2,
|
|
174
|
+
// section: 2,
|
|
175
|
+
// templatestyles: 2,
|
|
176
|
+
},
|
|
177
|
+
],
|
|
166
178
|
'syntax-like': [
|
|
167
179
|
2,
|
|
168
180
|
{
|
|
@@ -170,7 +182,7 @@ const defaultLintRuleConfig = {
|
|
|
170
182
|
// redirect: 2,
|
|
171
183
|
},
|
|
172
184
|
],
|
|
173
|
-
'table-layout': 1,
|
|
185
|
+
'table-layout': [1],
|
|
174
186
|
'tag-like': [
|
|
175
187
|
2,
|
|
176
188
|
{
|
|
@@ -178,17 +190,17 @@ const defaultLintRuleConfig = {
|
|
|
178
190
|
invalid: 1,
|
|
179
191
|
},
|
|
180
192
|
],
|
|
181
|
-
'unbalanced-header': 2,
|
|
193
|
+
'unbalanced-header': [2],
|
|
182
194
|
'unclosed-comment': [
|
|
183
195
|
1,
|
|
184
196
|
{
|
|
185
197
|
// include: 1,
|
|
186
198
|
},
|
|
187
199
|
],
|
|
188
|
-
'unclosed-quote': 1,
|
|
189
|
-
'unclosed-table': 2,
|
|
190
|
-
unescaped: 2,
|
|
191
|
-
'unknown-page': 1,
|
|
200
|
+
'unclosed-quote': [1],
|
|
201
|
+
'unclosed-table': [2],
|
|
202
|
+
unescaped: [2],
|
|
203
|
+
'unknown-page': [1],
|
|
192
204
|
'unmatched-tag': [
|
|
193
205
|
1,
|
|
194
206
|
{
|
|
@@ -235,7 +247,7 @@ const defaultLintRuleConfig = {
|
|
|
235
247
|
warn: 1,
|
|
236
248
|
},
|
|
237
249
|
],
|
|
238
|
-
'invalid-math': 2,
|
|
250
|
+
'invalid-math': [2],
|
|
239
251
|
};
|
|
240
252
|
const defaultLintConfig = {
|
|
241
253
|
configurationComment: 'lint',
|
|
@@ -252,8 +264,9 @@ const validateSeverity = (severity) => dict.has(severity);
|
|
|
252
264
|
* 验证设置值是否符合规范
|
|
253
265
|
* @param value 设置值
|
|
254
266
|
*/
|
|
255
|
-
const validateConfigValue = (value) => validateSeverity(value)
|
|
256
|
-
|
|
267
|
+
const validateConfigValue = (value) => validateSeverity(value) || (Array.isArray(value)
|
|
268
|
+
? validateSeverity(value[0]) && (value.length === 1 || typeof value[1] === 'object')
|
|
269
|
+
: typeof value === 'object');
|
|
257
270
|
/**
|
|
258
271
|
* 设置语法检查规则
|
|
259
272
|
* @param obj 语法检查设置对象
|
|
@@ -270,7 +283,16 @@ const set = (obj, key, value) => {
|
|
|
270
283
|
return false;
|
|
271
284
|
}
|
|
272
285
|
if (validateConfigValue(value)) {
|
|
273
|
-
|
|
286
|
+
if (Array.isArray(value)) {
|
|
287
|
+
obj[key] = value;
|
|
288
|
+
}
|
|
289
|
+
else if (typeof value === 'object') {
|
|
290
|
+
const [base, options = {}] = defaultLintRuleConfig[key];
|
|
291
|
+
obj[key] = [base, { ...clone(options), ...value }];
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
obj[key] = [value];
|
|
295
|
+
}
|
|
274
296
|
return true;
|
|
275
297
|
}
|
|
276
298
|
/* c8 ignore next */
|
|
@@ -293,11 +315,8 @@ class LintRuleConfiguration {
|
|
|
293
315
|
}
|
|
294
316
|
/** @implements */
|
|
295
317
|
getSeverity(rule, key) {
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
return dict.get(value);
|
|
299
|
-
}
|
|
300
|
-
return key ? dict.get(value[1]?.[key]) ?? dict.get(value[0]) : dict.get(value[0]);
|
|
318
|
+
const [base, options] = this[rule], severity = dict.get(base);
|
|
319
|
+
return key ? dict.get(options?.[key]) ?? severity : severity;
|
|
301
320
|
}
|
|
302
321
|
}
|
|
303
322
|
/** 语法检查设置 */
|
package/dist/lib/lsp.js
CHANGED
|
@@ -847,21 +847,16 @@ class LanguageService {
|
|
|
847
847
|
end: { line: endLine, character: endCol },
|
|
848
848
|
},
|
|
849
849
|
severity: severity === 'error' ? 1 : 2,
|
|
850
|
-
source:
|
|
851
|
-
/* eslint-disable @stylistic/operator-linebreak */
|
|
852
|
-
sources[rule] ??
|
|
850
|
+
source: sources[rule] ??
|
|
853
851
|
'WikiLint',
|
|
854
852
|
code: code ??
|
|
855
|
-
/* eslint-enable @stylistic/operator-linebreak */
|
|
856
853
|
rule,
|
|
857
854
|
message,
|
|
858
855
|
data: [
|
|
859
856
|
...fix ? [getQuickFix(root, fix, true)] : [],
|
|
860
857
|
...suggestions ? suggestions.map(suggestion => getQuickFix(root, suggestion)) : [],
|
|
861
858
|
],
|
|
862
|
-
})),
|
|
863
|
-
/* eslint-disable @stylistic/operator-linebreak */
|
|
864
|
-
cssDiagnostics = stylelint ?
|
|
859
|
+
})), cssDiagnostics = stylelint ?
|
|
865
860
|
await (async () => {
|
|
866
861
|
NPM: {
|
|
867
862
|
const tokens = this.findStyleTokens();
|
|
@@ -920,7 +915,6 @@ class LanguageService {
|
|
|
920
915
|
return warning ? e : e.filter(({ severity }) => severity === 1);
|
|
921
916
|
})) :
|
|
922
917
|
[];
|
|
923
|
-
/* eslint-enable @stylistic/operator-linebreak */
|
|
924
918
|
/* NOT FOR BROWSER ONLY */
|
|
925
919
|
let lilypondDiagnostics = [];
|
|
926
920
|
if (this.lilypond) {
|
|
@@ -1004,7 +998,7 @@ class LanguageService {
|
|
|
1004
998
|
* @param text source Wikitext / 源代码
|
|
1005
999
|
*/
|
|
1006
1000
|
async provideFoldingRanges(text) {
|
|
1007
|
-
const root = await this.#queue(text), { length } = root.getLines(), ranges = [], levels =
|
|
1001
|
+
const root = await this.#queue(text), { length } = root.getLines(), ranges = [], levels = Array.from({ length: 6 }), tokens = root.querySelectorAll('heading-title,table,template,magic-word');
|
|
1008
1002
|
for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
|
|
1009
1003
|
token.getRelativeIndex();
|
|
1010
1004
|
}
|
|
@@ -1388,7 +1382,7 @@ class LanguageService {
|
|
|
1388
1382
|
if (!this.data) {
|
|
1389
1383
|
return undefined;
|
|
1390
1384
|
}
|
|
1391
|
-
const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queueSignature(`${curLine.slice(0, character +
|
|
1385
|
+
const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queueSignature(`${curLine.slice(0, character + (0, common_1.numLeadingSpaces)(curLine.slice(character), /[{}<]|$/u))}}}`);
|
|
1392
1386
|
if (!lastChild.is('magic-word') || lastChild.length === 1) {
|
|
1393
1387
|
return undefined;
|
|
1394
1388
|
}
|
|
@@ -1552,7 +1546,7 @@ class LanguageService {
|
|
|
1552
1546
|
* @param text source Wikitext / 源代码
|
|
1553
1547
|
*/
|
|
1554
1548
|
async provideDocumentSymbols(text) {
|
|
1555
|
-
const root = await this.#queue(text), lines = root.getLines(), { length } = lines, symbols = [], names = new Set(), sections =
|
|
1549
|
+
const root = await this.#queue(text), lines = root.getLines(), { length } = lines, symbols = [], names = new Set(), sections = Array.from({ length: 6 }), tokens = root.querySelectorAll('heading-title');
|
|
1556
1550
|
for (const token of tokens) {
|
|
1557
1551
|
const { top, height, left, width } = token.getBoundingClientRect(), { level } = token.parentNode;
|
|
1558
1552
|
for (let i = level - 1; i < 6; i++) {
|
|
@@ -1603,7 +1597,7 @@ class LanguageService {
|
|
|
1603
1597
|
catch {
|
|
1604
1598
|
this.config = await index_1.default.fetchConfig(site, `${host}/w`, user);
|
|
1605
1599
|
}
|
|
1606
|
-
|
|
1600
|
+
this.config.articlePath = `${host}/wiki/`;
|
|
1607
1601
|
}
|
|
1608
1602
|
/** @implements */
|
|
1609
1603
|
[Symbol.dispose]() {
|
package/dist/lib/node.js
CHANGED
|
@@ -90,7 +90,10 @@ let AstNode = (() => {
|
|
|
90
90
|
/** @private */
|
|
91
91
|
getChildNodes() {
|
|
92
92
|
const { childNodes } = this;
|
|
93
|
-
|
|
93
|
+
if (Object.isFrozen(childNodes)) {
|
|
94
|
+
return [...childNodes];
|
|
95
|
+
}
|
|
96
|
+
return childNodes;
|
|
94
97
|
}
|
|
95
98
|
/** @private */
|
|
96
99
|
getAttribute(key) {
|
package/dist/lib/text.js
CHANGED
|
@@ -70,7 +70,10 @@ class AstText extends node_1.AstNode {
|
|
|
70
70
|
}
|
|
71
71
|
/** @private */
|
|
72
72
|
toString(skip) {
|
|
73
|
-
|
|
73
|
+
if (skip && !this.parentNode?.getAttribute('built')) {
|
|
74
|
+
return (0, string_1.removeComment)(this.data);
|
|
75
|
+
}
|
|
76
|
+
return this.data;
|
|
74
77
|
}
|
|
75
78
|
/** @private */
|
|
76
79
|
text() {
|
|
@@ -101,7 +104,7 @@ class AstText extends node_1.AstNode {
|
|
|
101
104
|
return [];
|
|
102
105
|
}
|
|
103
106
|
errorRegex.lastIndex = 0;
|
|
104
|
-
const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), { lintConfig } = index_1.default, tagLike = lintConfig.rules['tag-like'], specified =
|
|
107
|
+
const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), { lintConfig } = index_1.default, tagLike = lintConfig.rules['tag-like'], specified = tagLike[1]
|
|
105
108
|
? new Set(Object.keys(tagLike[1]).filter(tag => tag !== 'invalid' && tag !== 'disallowed'))
|
|
106
109
|
: new Set(), tags = new Set([
|
|
107
110
|
'onlyinclude',
|
package/dist/lib/title.js
CHANGED
|
@@ -87,7 +87,8 @@ class Title {
|
|
|
87
87
|
catch /* c8 ignore next */ { }
|
|
88
88
|
}
|
|
89
89
|
title = (0, string_1.decodeHtml)(title).replace(/[_ ]+/gu, ' ').trim();
|
|
90
|
-
if (subpage
|
|
90
|
+
if (subpage
|
|
91
|
+
|| page && trimmed.startsWith('/')) {
|
|
91
92
|
this.#ns = 0;
|
|
92
93
|
}
|
|
93
94
|
else {
|
|
@@ -139,7 +140,9 @@ class Title {
|
|
|
139
140
|
#getTitle(prefix, redirect = true) {
|
|
140
141
|
let title = (prefix + this.main).replace(/ /gu, '_');
|
|
141
142
|
if (title.startsWith('/')) {
|
|
142
|
-
title =
|
|
143
|
+
title =
|
|
144
|
+
(this.page ?? '') +
|
|
145
|
+
title.replace(/(.)\/$/u, '$1');
|
|
143
146
|
}
|
|
144
147
|
else if (title.startsWith('../') && this.page?.includes('/')) {
|
|
145
148
|
const [level, sub] = resolve(title), dirs = this.page.split('/');
|
|
@@ -183,9 +186,7 @@ class Title {
|
|
|
183
186
|
if (title) {
|
|
184
187
|
return this.#path.replace('$1', encodeURIComponent(title)
|
|
185
188
|
+ (fragment
|
|
186
|
-
? `#${encodeURIComponent(
|
|
187
|
-
// eslint-disable-next-line @stylistic/comma-dangle
|
|
188
|
-
fragment)}`
|
|
189
|
+
? `#${encodeURIComponent(fragment)}`
|
|
189
190
|
: ''));
|
|
190
191
|
}
|
|
191
192
|
return fragment === undefined ? '' : `#${encodeURIComponent(fragment)}`;
|
|
@@ -91,7 +91,8 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
|
|
|
91
91
|
ch = 'c';
|
|
92
92
|
const closed = substr.endsWith('-->');
|
|
93
93
|
// @ts-expect-error abstract class
|
|
94
|
-
new comment_1.CommentToken((0, string_1.restore)(substr, accum, 1)
|
|
94
|
+
new comment_1.CommentToken((0, string_1.restore)(substr, accum, 1)
|
|
95
|
+
.slice(4, closed ? -3 : undefined), closed, config, accum);
|
|
95
96
|
}
|
|
96
97
|
else if (include) {
|
|
97
98
|
// @ts-expect-error abstract class
|
package/dist/src/attribute.d.ts
CHANGED
|
@@ -12,7 +12,10 @@ export type AttributeTypes = 'ext-attr' | 'html-attr' | 'table-attr';
|
|
|
12
12
|
export declare abstract class AttributeToken extends Token {
|
|
13
13
|
#private;
|
|
14
14
|
readonly name: string;
|
|
15
|
-
readonly childNodes: readonly [
|
|
15
|
+
readonly childNodes: readonly [
|
|
16
|
+
AtomToken,
|
|
17
|
+
Token
|
|
18
|
+
];
|
|
16
19
|
abstract get firstChild(): AtomToken;
|
|
17
20
|
abstract get lastChild(): Token;
|
|
18
21
|
abstract get parentNode(): AttributesToken | undefined;
|
package/dist/src/attribute.js
CHANGED
|
@@ -77,7 +77,8 @@ class AttributeToken extends index_2.Token {
|
|
|
77
77
|
valueToken.setAttribute('stage', 1);
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
valueToken =
|
|
80
|
+
valueToken =
|
|
81
|
+
new atom_1.AtomToken(value, 'attr-value', config, accum, {});
|
|
81
82
|
}
|
|
82
83
|
super(undefined, config, accum);
|
|
83
84
|
this.#type = type;
|
|
@@ -174,7 +175,7 @@ class AttributeToken extends index_2.Token {
|
|
|
174
175
|
}
|
|
175
176
|
else if (typeof value === 'string' && ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
|
|
176
177
|
|| simple
|
|
177
|
-
&& (name === 'href' || tag === 'img' && name === 'src')
|
|
178
|
+
&& (name === 'href' || type === 'ext-attr' && tag === 'img' && name === 'src')
|
|
178
179
|
&& !new RegExp(String.raw `^(?:${this.getAttribute('config').protocol}|//)\S+$`, 'iu')
|
|
179
180
|
.test(value))) {
|
|
180
181
|
LINT: {
|
package/dist/src/attributes.js
CHANGED
|
@@ -32,6 +32,15 @@ const wordRegex = /* #__PURE__ */ (() => {
|
|
|
32
32
|
}
|
|
33
33
|
/* c8 ignore stop */
|
|
34
34
|
})();
|
|
35
|
+
const required = new Map([
|
|
36
|
+
['indicator', ['name']],
|
|
37
|
+
['langconvert', ['from', 'to']],
|
|
38
|
+
['mapframe', ['width', 'height']],
|
|
39
|
+
['maplink', ['width', 'height']],
|
|
40
|
+
['phonos', [['ipa', 'file', 'wikibase']]],
|
|
41
|
+
['section', [['begin', 'end']]],
|
|
42
|
+
['templatestyles', ['src']],
|
|
43
|
+
]);
|
|
35
44
|
/**
|
|
36
45
|
* attributes of extension and HTML tags
|
|
37
46
|
*
|
|
@@ -57,14 +66,15 @@ class AttributesToken extends index_2.Token {
|
|
|
57
66
|
let out = '', mt = regex.exec(attr), lastIndex = 0;
|
|
58
67
|
const insertDirty = /** 插入无效属性 */ () => {
|
|
59
68
|
if (out) {
|
|
60
|
-
super.insertAt(new atom_1.AtomToken(out, toDirty(type), config, accum
|
|
69
|
+
super.insertAt(new atom_1.AtomToken(out, toDirty(type), config, accum));
|
|
61
70
|
out = '';
|
|
62
71
|
}
|
|
63
72
|
};
|
|
64
73
|
while (mt) {
|
|
65
74
|
const { index, 0: full, 1: key, 2: equal, 3: quoteStart, 4: quoted, 5: quoteEnd, 6: unquoted } = mt;
|
|
66
75
|
out += attr.slice(lastIndex, index);
|
|
67
|
-
if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u
|
|
76
|
+
if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u
|
|
77
|
+
.test((0, string_1.removeComment)(key).trim())) {
|
|
68
78
|
const value = quoted ?? unquoted, quotes = [quoteStart, quoteEnd],
|
|
69
79
|
// @ts-expect-error abstract class
|
|
70
80
|
token = new attribute_1.AttributeToken((0, exports.toAttributeType)(type), name, key, quotes, config, equal, value, accum);
|
|
@@ -136,7 +146,7 @@ class AttributesToken extends index_2.Token {
|
|
|
136
146
|
/** @private */
|
|
137
147
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
138
148
|
LINT: {
|
|
139
|
-
const errors = super.lint(start, re), { parentNode, childNodes } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
|
|
149
|
+
const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'required-attr', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
|
|
140
150
|
.map(k => lintConfig.getSeverity(rules[0], k));
|
|
141
151
|
if (s[0] && this.#lint()) {
|
|
142
152
|
const e = (0, lint_1.generateForSelf)(this, rect, rules[0], 'attributes-of-closing-tag', s[0]);
|
|
@@ -171,7 +181,21 @@ class AttributesToken extends index_2.Token {
|
|
|
171
181
|
}
|
|
172
182
|
}
|
|
173
183
|
}
|
|
174
|
-
|
|
184
|
+
if (type === 'ext-attrs' && required.has(tag)) {
|
|
185
|
+
const severity = lintConfig.getSeverity(rules[1], tag);
|
|
186
|
+
if (severity) {
|
|
187
|
+
for (const key of required.get(tag)) {
|
|
188
|
+
const keys = typeof key === 'string' ? [key] : key, missing = keys.every(k => {
|
|
189
|
+
const value = this.getAttr(k);
|
|
190
|
+
return value === true || !value;
|
|
191
|
+
});
|
|
192
|
+
if (missing) {
|
|
193
|
+
errors.push((0, lint_1.generateForSelf)(this, rect, rules[1], index_1.default.msg('required-attribute', keys.join('/')), severity));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const severity = lintConfig.getSeverity(rules[2], 'attribute');
|
|
175
199
|
if (severity && duplicated.size > 0) {
|
|
176
200
|
for (const key of duplicated) {
|
|
177
201
|
const pairs = attrs.get(key).map(attr => {
|
|
@@ -179,7 +203,7 @@ class AttributesToken extends index_2.Token {
|
|
|
179
203
|
return [attr, value === true ? '' : value];
|
|
180
204
|
});
|
|
181
205
|
Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
|
|
182
|
-
const e = (0, lint_1.generateForChild)(attr, rect, rules[
|
|
206
|
+
const e = (0, lint_1.generateForChild)(attr, rect, rules[2], index_1.default.msg('duplicate-attribute', key), severity);
|
|
183
207
|
if (computeEditInfo || fix) {
|
|
184
208
|
const remove = (0, lint_1.fixByRemove)(e);
|
|
185
209
|
if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
|
package/dist/src/heading.js
CHANGED
|
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
};
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.HeadingToken = void 0;
|
|
41
|
+
const common_1 = require("@bhsd/common");
|
|
41
42
|
const lint_1 = require("../util/lint");
|
|
42
43
|
const debug_1 = require("../util/debug");
|
|
43
44
|
const rect_1 = require("../lib/rect");
|
|
@@ -126,10 +127,14 @@ let HeadingToken = (() => {
|
|
|
126
127
|
//
|
|
127
128
|
}
|
|
128
129
|
else if (unbalancedStart) {
|
|
129
|
-
const
|
|
130
|
-
e.suggestions = [{ desc: `h${level}`, range: [e.startIndex, e.startIndex + extra
|
|
130
|
+
const extra = (0, common_1.numLeadingSpaces)(innerStr, /[^=]|$/u), newLevel = level + extra;
|
|
131
|
+
e.suggestions = [{ desc: `h${level}`, range: [e.startIndex, e.startIndex + extra], text: '' }];
|
|
131
132
|
if (newLevel < 7) {
|
|
132
|
-
e.suggestions.push({
|
|
133
|
+
e.suggestions.push({
|
|
134
|
+
desc: `h${newLevel}`,
|
|
135
|
+
range: [e.endIndex, e.endIndex],
|
|
136
|
+
text: '='.repeat(extra),
|
|
137
|
+
});
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
else {
|
package/dist/src/link/base.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { Title } from '../../lib/title';
|
|
|
12
12
|
export declare abstract class LinkBaseToken extends Token {
|
|
13
13
|
#private;
|
|
14
14
|
readonly name: string;
|
|
15
|
-
abstract get type(): '
|
|
15
|
+
abstract get type(): 'gallery-image' | 'link' | 'category' | 'file' | 'redirect-target' | 'ext-inner' | 'imagemap-image';
|
|
16
16
|
readonly childNodes: readonly [AtomToken, ...Token[]];
|
|
17
17
|
abstract get firstChild(): AtomToken;
|
|
18
18
|
abstract get lastChild(): Token;
|
package/dist/src/link/base.js
CHANGED
|
@@ -74,7 +74,7 @@ let LinkBaseToken = (() => {
|
|
|
74
74
|
#title;
|
|
75
75
|
/** full link / 完整链接 */
|
|
76
76
|
get link() {
|
|
77
|
-
|
|
77
|
+
LINT: return this.#title;
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
80
|
* @param link 链接标题
|
|
@@ -83,7 +83,7 @@ let LinkBaseToken = (() => {
|
|
|
83
83
|
*/
|
|
84
84
|
constructor(link, linkText, config = index_1.default.getConfig(), accum = [], delimiter = '|') {
|
|
85
85
|
super(undefined, config, accum, {});
|
|
86
|
-
this.insertAt(new atom_1.AtomToken(link, 'link-target', config, accum
|
|
86
|
+
this.insertAt(new atom_1.AtomToken(link, 'link-target', config, accum));
|
|
87
87
|
if (linkText !== undefined) {
|
|
88
88
|
const inner = new index_2.Token(linkText, { ...config, excludes: [...config.excludes, 'list'] }, accum);
|
|
89
89
|
inner.type = 'link-text';
|
|
@@ -123,12 +123,18 @@ let LinkBaseToken = (() => {
|
|
|
123
123
|
/** @private */
|
|
124
124
|
toString(skip) {
|
|
125
125
|
const str = super.toString(skip, this.#delimiter);
|
|
126
|
-
|
|
126
|
+
if (this.#bracket) {
|
|
127
|
+
return `[[${str}]]`;
|
|
128
|
+
}
|
|
129
|
+
return str;
|
|
127
130
|
}
|
|
128
131
|
/** @private */
|
|
129
132
|
text() {
|
|
130
133
|
const str = super.text('|');
|
|
131
|
-
|
|
134
|
+
if (this.#bracket) {
|
|
135
|
+
return `[[${str}]]`;
|
|
136
|
+
}
|
|
137
|
+
return str;
|
|
132
138
|
}
|
|
133
139
|
/** @private */
|
|
134
140
|
getAttribute(key) {
|
package/dist/src/link/file.js
CHANGED
|
@@ -74,9 +74,9 @@ class FileToken extends base_1.LinkBaseToken {
|
|
|
74
74
|
constructor(link, text, config, accum = [], delimiter = '|', type) {
|
|
75
75
|
super(link, undefined, config, accum, delimiter);
|
|
76
76
|
const { extension } = this.getTitle(true, true);
|
|
77
|
-
this.safeAppend(explode(text).map(
|
|
77
|
+
this.safeAppend(explode(text).map((part) =>
|
|
78
78
|
// @ts-expect-error abstract class
|
|
79
|
-
|
|
79
|
+
new imageParameter_1.ImageParameterToken(part, extension, type, config, accum)));
|
|
80
80
|
}
|
|
81
81
|
/** @private */
|
|
82
82
|
lint(start = this.getAbsoluteIndex(), re) {
|
package/dist/src/magicLink.js
CHANGED
|
@@ -87,7 +87,7 @@ class MagicLinkToken extends index_2.Token {
|
|
|
87
87
|
let rule = 'invalid-url', severity = lintConfig.getSeverity(rule);
|
|
88
88
|
if (severity && !this.querySelector('magic-word')) {
|
|
89
89
|
try {
|
|
90
|
-
this
|
|
90
|
+
this.#getUrl();
|
|
91
91
|
}
|
|
92
92
|
catch {
|
|
93
93
|
errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'invalid-url', severity));
|
|
@@ -115,6 +115,16 @@ class MagicLinkToken extends index_2.Token {
|
|
|
115
115
|
return errors;
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
/** 获取自由外链的 URL */
|
|
119
|
+
#getUrl() {
|
|
120
|
+
LINT: {
|
|
121
|
+
let { link } = this;
|
|
122
|
+
if (link.startsWith('//')) {
|
|
123
|
+
link = `https:${link}`;
|
|
124
|
+
}
|
|
125
|
+
return new URL(link);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
118
128
|
/**
|
|
119
129
|
* Get the URL
|
|
120
130
|
*
|
|
@@ -123,22 +133,16 @@ class MagicLinkToken extends index_2.Token {
|
|
|
123
133
|
*/
|
|
124
134
|
getUrl(articlePath) {
|
|
125
135
|
LSP: {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (type === 'magic-link') {
|
|
129
|
-
if (link.startsWith('ISBN')) {
|
|
130
|
-
return this
|
|
131
|
-
.normalizeTitle(`BookSources/${link.slice(5)}`, -1, { temporary: true })
|
|
132
|
-
.getUrl(articlePath);
|
|
133
|
-
}
|
|
134
|
-
link = link.startsWith('RFC')
|
|
135
|
-
? `https://datatracker.ietf.org/doc/html/rfc${link.slice(4)}`
|
|
136
|
-
: `https://pubmed.ncbi.nlm.nih.gov/${link.slice(5)}`;
|
|
137
|
-
}
|
|
138
|
-
else if (link.startsWith('//')) {
|
|
139
|
-
link = `https:${link}`;
|
|
136
|
+
if (this.type !== 'magic-link') {
|
|
137
|
+
return this.#getUrl();
|
|
140
138
|
}
|
|
141
|
-
|
|
139
|
+
const { link } = this;
|
|
140
|
+
return link.startsWith('ISBN')
|
|
141
|
+
? this.normalizeTitle(`BookSources/${link.slice(5)}`, -1, { temporary: true })
|
|
142
|
+
.getUrl(articlePath)
|
|
143
|
+
: new URL(link.startsWith('RFC')
|
|
144
|
+
? `https://datatracker.ietf.org/doc/html/rfc${link.slice(4)}`
|
|
145
|
+
: `https://pubmed.ncbi.nlm.nih.gov/${link.slice(5)}`);
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
148
|
}
|
|
@@ -3,6 +3,7 @@ import { GalleryImageToken } from '../link/galleryImage';
|
|
|
3
3
|
import { CommentLineToken } from '../nowiki/commentLine';
|
|
4
4
|
import type { Config, LintError } from '../../base';
|
|
5
5
|
import type { AstText, Token } from '../../internal';
|
|
6
|
+
declare type Child = GalleryImageToken | CommentLineToken | AstText;
|
|
6
7
|
/**
|
|
7
8
|
* `<gallery>`
|
|
8
9
|
* @classdesc `{childNodes: (GalleryImageToken|CommentLineToken|AstText)[]}`
|
|
@@ -10,9 +11,10 @@ import type { AstText, Token } from '../../internal';
|
|
|
10
11
|
export declare abstract class GalleryToken extends MultiLineToken {
|
|
11
12
|
#private;
|
|
12
13
|
readonly name: 'gallery';
|
|
13
|
-
readonly childNodes: readonly
|
|
14
|
-
abstract get firstChild():
|
|
15
|
-
abstract get lastChild():
|
|
14
|
+
readonly childNodes: readonly Child[];
|
|
15
|
+
abstract get firstChild(): Child | undefined;
|
|
16
|
+
abstract get lastChild(): Child | undefined;
|
|
16
17
|
/** @param inner 标签内部wikitext */
|
|
17
18
|
constructor(inner?: string, config?: Config, accum?: Token[]);
|
|
18
19
|
}
|
|
20
|
+
export {};
|
|
@@ -20,8 +20,10 @@ class GalleryToken extends index_2.MultiLineToken {
|
|
|
20
20
|
for (const line of inner?.split('\n') ?? []) {
|
|
21
21
|
const matches = /^([^|]+)(?:\|(.*))?/u.exec(line);
|
|
22
22
|
if (!matches) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
super.insertAt((line.trim()
|
|
24
|
+
// @ts-expect-error abstract class
|
|
25
|
+
? new commentLine_1.CommentLineToken(line, config, accum)
|
|
26
|
+
: line));
|
|
25
27
|
continue;
|
|
26
28
|
}
|
|
27
29
|
const [, file, alt] = matches;
|
|
@@ -30,8 +32,9 @@ class GalleryToken extends index_2.MultiLineToken {
|
|
|
30
32
|
super.insertAt(new galleryImage_1.GalleryImageToken('gallery', file, alt, config, accum));
|
|
31
33
|
}
|
|
32
34
|
else {
|
|
35
|
+
super.insertAt(
|
|
33
36
|
// @ts-expect-error abstract class
|
|
34
|
-
|
|
37
|
+
new commentLine_1.CommentLineToken(line, config, accum));
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Token } from '../index';
|
|
2
2
|
import type { Config } from '../../base';
|
|
3
3
|
import type { AstText } from '../../internal';
|
|
4
|
-
declare type NowikiTypes = 'ext-inner' | 'comment' | 'dd' | 'double-underscore' | 'hr' | 'list' | '
|
|
4
|
+
declare type NowikiTypes = 'ext-inner' | 'comment' | 'dd' | 'double-underscore' | 'hr' | 'list' | 'quote' | 'noinclude';
|
|
5
5
|
/**
|
|
6
6
|
* text-only token that will not be parsed
|
|
7
7
|
*
|
package/dist/src/parameter.js
CHANGED
|
@@ -38,7 +38,9 @@ class ParameterToken extends index_2.Token {
|
|
|
38
38
|
}
|
|
39
39
|
/** @private */
|
|
40
40
|
trimName(name, set = true) {
|
|
41
|
-
const trimmed = (typeof name === 'string'
|
|
41
|
+
const trimmed = (typeof name === 'string'
|
|
42
|
+
? name :
|
|
43
|
+
name.toString(true))
|
|
42
44
|
.replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
|
|
43
45
|
this.setAttribute('name', trimmed);
|
|
44
46
|
return trimmed;
|