wikilint 2.13.9 → 2.14.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/dist/base.d.ts +1 -3
- package/dist/lib/text.js +15 -23
- package/dist/src/arg.js +3 -11
- package/dist/src/attribute.js +8 -19
- package/dist/src/attributes.js +20 -10
- package/dist/src/converterFlags.js +1 -7
- package/dist/src/gallery.js +2 -10
- package/dist/src/heading.js +40 -6
- package/dist/src/html.js +47 -27
- package/dist/src/imageParameter.js +3 -1
- package/dist/src/imagemap.js +8 -1
- package/dist/src/index.js +12 -24
- package/dist/src/link/base.js +4 -1
- package/dist/src/link/file.js +5 -1
- package/dist/src/link/galleryImage.js +3 -1
- package/dist/src/magicLink.js +3 -17
- package/dist/src/nested.js +2 -10
- package/dist/src/nowiki/comment.js +1 -1
- package/dist/src/nowiki/quote.js +10 -8
- package/dist/src/paramTag/index.js +1 -7
- package/dist/src/tagPair/include.js +2 -14
- package/dist/src/transclude.js +5 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +2 -2
package/dist/base.d.ts
CHANGED
package/dist/lib/text.js
CHANGED
|
@@ -101,7 +101,7 @@ class AstText extends node_1.AstNode {
|
|
|
101
101
|
return [];
|
|
102
102
|
}
|
|
103
103
|
errorRegex.lastIndex = 0;
|
|
104
|
-
const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), { ext, html } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), tags = new Set(['onlyinclude', 'noinclude', 'includeonly', ext, html, disallowedTags].flat(2));
|
|
104
|
+
const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), tags = new Set(['onlyinclude', 'noinclude', 'includeonly', ext, html, disallowedTags].flat(2));
|
|
105
105
|
for (let mt = errorRegex.exec(data); mt; mt = errorRegex.exec(data)) {
|
|
106
106
|
const [, tag, prefix] = mt;
|
|
107
107
|
let { index } = mt, error = mt[0].toLowerCase();
|
|
@@ -121,7 +121,7 @@ class AstText extends node_1.AstNode {
|
|
|
121
121
|
else if (char === ']' && (index || length > 1)) {
|
|
122
122
|
errorRegex.lastIndex--;
|
|
123
123
|
}
|
|
124
|
-
const startIndex = start + index, endIndex = startIndex + length,
|
|
124
|
+
const startIndex = start + index, endIndex = startIndex + length, nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], severity = length > 1 && !(char === '<' && !/[\s/>]/u.test(nextChar ?? '')
|
|
125
125
|
|| isHtmlAttrVal && (char === '[' || char === ']')
|
|
126
126
|
|| magicLink && type === 'parameter-value')
|
|
127
127
|
|| char === '{' && (nextChar === char || previousChar === '-')
|
|
@@ -166,39 +166,31 @@ class AstText extends node_1.AstNode {
|
|
|
166
166
|
endCol: startCol + length,
|
|
167
167
|
};
|
|
168
168
|
if (char === '<') {
|
|
169
|
-
e.suggestions = [
|
|
170
|
-
{
|
|
171
|
-
desc: 'escape',
|
|
172
|
-
range: [startIndex, startIndex + 1],
|
|
173
|
-
text: '<',
|
|
174
|
-
},
|
|
175
|
-
];
|
|
169
|
+
e.suggestions = [{ desc: 'escape', range: [startIndex, startIndex + 1], text: '<' }];
|
|
176
170
|
}
|
|
177
171
|
else if (char === 'h'
|
|
178
172
|
&& !(type === 'ext-link-text' || type === 'link-text')
|
|
179
173
|
&& /[\p{L}\d_]/u.test(previousChar || '')) {
|
|
180
|
-
e.suggestions = [
|
|
181
|
-
{
|
|
182
|
-
desc: 'whitespace',
|
|
183
|
-
range: [startIndex, startIndex],
|
|
184
|
-
text: ' ',
|
|
185
|
-
},
|
|
186
|
-
];
|
|
174
|
+
e.suggestions = [{ desc: 'whitespace', range: [startIndex, startIndex], text: ' ' }];
|
|
187
175
|
}
|
|
188
176
|
else if (char === '[' && type === 'ext-link-text') {
|
|
189
177
|
const i = parentNode.getAbsoluteIndex() + parentNode.toString().length;
|
|
190
|
-
e.suggestions = [
|
|
191
|
-
{
|
|
192
|
-
desc: 'escape',
|
|
193
|
-
range: [i, i + 1],
|
|
194
|
-
text: ']',
|
|
195
|
-
},
|
|
196
|
-
];
|
|
178
|
+
e.suggestions = [{ desc: 'escape', range: [i, i + 1], text: ']' }];
|
|
197
179
|
}
|
|
198
180
|
else if (char === ']' && previousType === 'free-ext-link' && severity === 'error') {
|
|
199
181
|
const i = start - previousSibling.toString().length;
|
|
200
182
|
e.fix = { range: [i, i], text: '[', desc: 'left bracket' };
|
|
201
183
|
}
|
|
184
|
+
else if (magicLink) {
|
|
185
|
+
e.suggestions = [
|
|
186
|
+
...mt[0] === error
|
|
187
|
+
? []
|
|
188
|
+
: [{ desc: 'uppercase', range: [startIndex, endIndex], text: error }],
|
|
189
|
+
...nextChar === ':' || nextChar === ':'
|
|
190
|
+
? [{ desc: 'whitespace', range: [endIndex, endIndex + 1], text: ' ' }]
|
|
191
|
+
: [],
|
|
192
|
+
];
|
|
193
|
+
}
|
|
202
194
|
errors.push(e);
|
|
203
195
|
}
|
|
204
196
|
return errors;
|
package/dist/src/arg.js
CHANGED
|
@@ -71,7 +71,7 @@ class ArgToken extends index_2.Token {
|
|
|
71
71
|
if (!this.getAttribute('include')) {
|
|
72
72
|
const e = (0, lint_1.generateForSelf)(this, { start }, 'no-arg', 'unexpected template argument');
|
|
73
73
|
if (argDefault) {
|
|
74
|
-
e.
|
|
74
|
+
e.suggestions = [{ range: [start, e.endIndex], text: argDefault.text(), desc: 'expand' }];
|
|
75
75
|
}
|
|
76
76
|
return [e];
|
|
77
77
|
}
|
|
@@ -86,16 +86,8 @@ class ArgToken extends index_2.Token {
|
|
|
86
86
|
e.startIndex--;
|
|
87
87
|
e.startCol--;
|
|
88
88
|
e.suggestions = [
|
|
89
|
-
{
|
|
90
|
-
|
|
91
|
-
range: [e.startIndex, e.endIndex],
|
|
92
|
-
text: '',
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
desc: 'escape',
|
|
96
|
-
range: [e.startIndex, e.startIndex + 1],
|
|
97
|
-
text: '{{!}}',
|
|
98
|
-
},
|
|
89
|
+
{ desc: 'remove', range: [e.startIndex, e.endIndex], text: '' },
|
|
90
|
+
{ desc: 'escape', range: [e.startIndex, e.startIndex + 1], text: '{{!}}' },
|
|
99
91
|
];
|
|
100
92
|
return e;
|
|
101
93
|
}));
|
package/dist/src/attribute.js
CHANGED
|
@@ -98,16 +98,10 @@ class AttributeToken extends index_2.Token {
|
|
|
98
98
|
const e = (0, lint_1.generateForChild)(lastChild, rect, 'unclosed-quote', index_1.default.msg('unclosed $1', 'quotes'), 'warning');
|
|
99
99
|
e.startIndex--;
|
|
100
100
|
e.startCol--;
|
|
101
|
-
|
|
102
|
-
if (lastChild.childNodes.some(({ type: t, data }) => t === 'text' && /\s/u.test(data))) {
|
|
103
|
-
e.suggestions = [fix];
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
e.fix = fix;
|
|
107
|
-
}
|
|
101
|
+
e.suggestions = [{ range: [e.endIndex, e.endIndex], text: this.#quotes[0], desc: 'close' }];
|
|
108
102
|
errors.push(e);
|
|
109
103
|
}
|
|
110
|
-
const attrs = sharable_1.extAttrs[tag], attrs2 = sharable_1.htmlAttrs[tag];
|
|
104
|
+
const attrs = sharable_1.extAttrs[tag], attrs2 = sharable_1.htmlAttrs[tag], { length } = this.toString();
|
|
111
105
|
if (!attrs?.has(name)
|
|
112
106
|
&& !attrs2?.has(name)
|
|
113
107
|
// 不是未定义的扩展标签或包含嵌入的HTML标签
|
|
@@ -115,7 +109,10 @@ class AttributeToken extends index_2.Token {
|
|
|
115
109
|
&& (type === 'ext-attr' && !attrs2
|
|
116
110
|
|| !/^(?:xmlns:[\w:.-]+|data-(?!ooui|mw|parsoid)[^:]*)$/u.test(name)
|
|
117
111
|
&& (tag === 'meta' || tag === 'link' || !sharable_1.commonHtmlAttrs.has(name)))) {
|
|
118
|
-
errors.push(
|
|
112
|
+
errors.push({
|
|
113
|
+
...(0, lint_1.generateForChild)(firstChild, rect, 'illegal-attr', 'illegal attribute name'),
|
|
114
|
+
suggestions: [{ desc: 'remove', range: [start, start + length], text: '' }],
|
|
115
|
+
});
|
|
119
116
|
}
|
|
120
117
|
else if (sharable_1.obsoleteAttrs[tag]?.has(name)) {
|
|
121
118
|
errors.push((0, lint_1.generateForChild)(firstChild, rect, 'obsolete-attr', 'obsolete attribute', 'warning'));
|
|
@@ -126,16 +123,8 @@ class AttributeToken extends index_2.Token {
|
|
|
126
123
|
else if (name === 'tabindex' && typeof value === 'string' && value !== '0') {
|
|
127
124
|
const e = (0, lint_1.generateForChild)(lastChild, rect, 'illegal-attr', 'nonzero tabindex');
|
|
128
125
|
e.suggestions = [
|
|
129
|
-
{
|
|
130
|
-
|
|
131
|
-
range: [start, e.endIndex],
|
|
132
|
-
text: '',
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
desc: '0 tabindex',
|
|
136
|
-
range: [e.startIndex, e.endIndex],
|
|
137
|
-
text: '0',
|
|
138
|
-
},
|
|
126
|
+
{ desc: 'remove', range: [start, start + length], text: '' },
|
|
127
|
+
{ desc: '0 tabindex', range: [e.startIndex, e.endIndex], text: '0' },
|
|
139
128
|
];
|
|
140
129
|
errors.push(e);
|
|
141
130
|
}
|
package/dist/src/attributes.js
CHANGED
|
@@ -99,8 +99,11 @@ class AttributesToken extends index_2.Token {
|
|
|
99
99
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
100
100
|
const errors = super.lint(start, re), { parentNode, childNodes } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start);
|
|
101
101
|
if (parentNode?.type === 'html' && parentNode.closing && this.text().trim()) {
|
|
102
|
-
const e = (0, lint_1.generateForSelf)(this, rect, 'no-ignored', 'attributes of a closing tag');
|
|
103
|
-
e.
|
|
102
|
+
const e = (0, lint_1.generateForSelf)(this, rect, 'no-ignored', 'attributes of a closing tag'), index = parentNode.getAbsoluteIndex();
|
|
103
|
+
e.suggestions = [
|
|
104
|
+
{ desc: 'remove', range: [start, e.endIndex], text: '' },
|
|
105
|
+
{ desc: 'open', range: [index + 1, index + 2], text: '' },
|
|
106
|
+
];
|
|
104
107
|
errors.push(e);
|
|
105
108
|
}
|
|
106
109
|
for (const attr of childNodes) {
|
|
@@ -118,20 +121,27 @@ class AttributesToken extends index_2.Token {
|
|
|
118
121
|
const str = attr.text().trim();
|
|
119
122
|
if (str) {
|
|
120
123
|
const e = (0, lint_1.generateForChild)(attr, rect, 'no-ignored', 'containing invalid attribute', /[\p{L}\d]/u.test(str) ? 'error' : 'warning');
|
|
121
|
-
e.suggestions = [
|
|
122
|
-
{
|
|
123
|
-
desc: 'remove',
|
|
124
|
-
range: [e.startIndex, e.endIndex],
|
|
125
|
-
text: ' ',
|
|
126
|
-
},
|
|
127
|
-
];
|
|
124
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex, e.endIndex], text: ' ' }];
|
|
128
125
|
errors.push(e);
|
|
129
126
|
}
|
|
130
127
|
}
|
|
131
128
|
}
|
|
132
129
|
if (duplicated.size > 0) {
|
|
133
130
|
for (const key of duplicated) {
|
|
134
|
-
|
|
131
|
+
const pairs = attrs.get(key).map(attr => {
|
|
132
|
+
const value = attr.getValue();
|
|
133
|
+
return [attr, value === true ? '' : value];
|
|
134
|
+
});
|
|
135
|
+
errors.push(...pairs.map(([attr, value], i) => {
|
|
136
|
+
const e = (0, lint_1.generateForChild)(attr, rect, 'no-duplicate', index_1.default.msg('duplicated $1 attribute', key)), remove = { desc: 'remove', range: [e.startIndex, e.endIndex], text: '' };
|
|
137
|
+
if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
|
|
138
|
+
e.fix = remove;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
e.suggestions = [remove];
|
|
142
|
+
}
|
|
143
|
+
return e;
|
|
144
|
+
}));
|
|
135
145
|
}
|
|
136
146
|
}
|
|
137
147
|
return errors;
|
|
@@ -65,13 +65,7 @@ class ConverterFlagsToken extends index_2.Token {
|
|
|
65
65
|
e.fix = { range: [e.startIndex, e.endIndex], text: flag.toUpperCase(), desc: 'uppercase' };
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
68
|
-
e.suggestions = [
|
|
69
|
-
{
|
|
70
|
-
desc: 'remove',
|
|
71
|
-
range: [e.startIndex - (i && 1), e.endIndex],
|
|
72
|
-
text: '',
|
|
73
|
-
},
|
|
74
|
-
];
|
|
68
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex - (i && 1), e.endIndex], text: '' }];
|
|
75
69
|
}
|
|
76
70
|
errors.push(e);
|
|
77
71
|
}
|
package/dist/src/gallery.js
CHANGED
|
@@ -71,16 +71,8 @@ class GalleryToken extends index_2.Token {
|
|
|
71
71
|
startCol,
|
|
72
72
|
endCol: startCol + length,
|
|
73
73
|
suggestions: [
|
|
74
|
-
{
|
|
75
|
-
|
|
76
|
-
range: [start, endIndex],
|
|
77
|
-
text: '',
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
desc: 'comment',
|
|
81
|
-
range: [start, endIndex],
|
|
82
|
-
text: `<!--${str}-->`,
|
|
83
|
-
},
|
|
74
|
+
{ desc: 'remove', range: [start, endIndex], text: '' },
|
|
75
|
+
{ desc: 'comment', range: [start, endIndex], text: `<!--${str}-->` },
|
|
84
76
|
],
|
|
85
77
|
});
|
|
86
78
|
}
|
package/dist/src/heading.js
CHANGED
|
@@ -57,21 +57,55 @@ class HeadingToken extends index_2.Token {
|
|
|
57
57
|
}
|
|
58
58
|
/** @private */
|
|
59
59
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
60
|
-
const errors = super.lint(start, re), { firstChild, level } = this, innerStr = firstChild.toString(), quotes = firstChild.childNodes.filter((0, debug_1.isToken)('quote')), boldQuotes = quotes.filter(({ bold }) => bold), italicQuotes = quotes.filter(({ italic }) => italic), rect = new rect_1.BoundingRect(this, start);
|
|
60
|
+
const errors = super.lint(start, re), { firstChild, level } = this, innerStr = firstChild.toString(), unbalancedStart = innerStr.startsWith('='), unbalanced = unbalancedStart || innerStr.endsWith('='), quotes = firstChild.childNodes.filter((0, debug_1.isToken)('quote')), boldQuotes = quotes.filter(({ bold }) => bold), italicQuotes = quotes.filter(({ italic }) => italic), rect = new rect_1.BoundingRect(this, start);
|
|
61
61
|
if (this.level === 1) {
|
|
62
|
-
|
|
62
|
+
const e = (0, lint_1.generateForChild)(firstChild, rect, 'h1', '<h1>');
|
|
63
|
+
if (!unbalanced) {
|
|
64
|
+
e.suggestions = [{ desc: 'h2', range: [e.startIndex, e.endIndex], text: `=${innerStr}=` }];
|
|
65
|
+
}
|
|
66
|
+
errors.push(e);
|
|
63
67
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
68
|
+
if (unbalanced) {
|
|
69
|
+
const e = (0, lint_1.generateForChild)(firstChild, rect, 'unbalanced-header', index_1.default.msg('unbalanced $1 in a section header', '"="'));
|
|
70
|
+
if (innerStr === '=') {
|
|
71
|
+
//
|
|
72
|
+
}
|
|
73
|
+
else if (unbalancedStart) {
|
|
74
|
+
const [extra] = /^=+/u.exec(innerStr);
|
|
75
|
+
e.suggestions = [
|
|
76
|
+
{ desc: `h${level}`, range: [e.startIndex, e.startIndex + extra.length], text: '' },
|
|
77
|
+
{ desc: `h${level + extra.length}`, range: [e.endIndex, e.endIndex], text: extra },
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const extra = /[^=](=+)$/u.exec(innerStr)[1];
|
|
82
|
+
e.suggestions = [
|
|
83
|
+
{ desc: `h${level}`, range: [e.endIndex - extra.length, e.endIndex], text: '' },
|
|
84
|
+
{ desc: `h${level + extra.length}`, range: [e.startIndex, e.startIndex], text: extra },
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
errors.push(e);
|
|
66
88
|
}
|
|
67
89
|
if (this.closest('html-attrs,table-attrs')) {
|
|
68
90
|
errors.push((0, lint_1.generateForSelf)(this, rect, 'parsing-order', 'section header in a HTML tag'));
|
|
69
91
|
}
|
|
92
|
+
const rootStr = this.getRootNode().toString();
|
|
70
93
|
if (boldQuotes.length % 2) {
|
|
71
|
-
|
|
94
|
+
const e = (0, lint_1.generateForChild)(boldQuotes[boldQuotes.length - 1], { ...rect, start: start + level, left: rect.left + level }, 'format-leakage', index_1.default.msg('unbalanced $1 in a section header', 'bold apostrophes')), end = start + level + innerStr.length;
|
|
95
|
+
if (rootStr.slice(e.endIndex, end).trim()) {
|
|
96
|
+
e.suggestions = [{ desc: 'close', range: [end, end], text: "'''" }];
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
e.fix = { desc: 'remove', range: [e.startIndex, e.endIndex], text: '' };
|
|
100
|
+
}
|
|
101
|
+
errors.push(e);
|
|
72
102
|
}
|
|
73
103
|
if (italicQuotes.length % 2) {
|
|
74
|
-
|
|
104
|
+
const e = (0, lint_1.generateForChild)(italicQuotes[italicQuotes.length - 1], { start: start + level }, 'format-leakage', index_1.default.msg('unbalanced $1 in a section header', 'italic apostrophes')), end = start + level + innerStr.length;
|
|
105
|
+
e.fix = rootStr.slice(e.endIndex, end).trim()
|
|
106
|
+
? { desc: 'close', range: [end, end], text: "''" }
|
|
107
|
+
: { desc: 'remove', range: [e.startIndex, e.endIndex], text: '' };
|
|
108
|
+
errors.push(e);
|
|
75
109
|
}
|
|
76
110
|
return errors;
|
|
77
111
|
}
|
package/dist/src/html.js
CHANGED
|
@@ -84,10 +84,15 @@ class HtmlToken extends index_1.Token {
|
|
|
84
84
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
85
85
|
const errors = super.lint(start, re), rect = new rect_1.BoundingRect(this, start);
|
|
86
86
|
if (this.name === 'h1' && !this.closing) {
|
|
87
|
-
errors.push(
|
|
87
|
+
errors.push({
|
|
88
|
+
...(0, lint_1.generateForSelf)(this, rect, 'h1', '<h1>'),
|
|
89
|
+
suggestions: [{ desc: 'h2', range: [start + 2, start + 3], text: '2' }],
|
|
90
|
+
});
|
|
88
91
|
}
|
|
89
92
|
if (this.closest('table-attrs')) {
|
|
90
|
-
|
|
93
|
+
const e = (0, lint_1.generateForSelf)(this, rect, 'parsing-order', 'HTML tag in table attributes');
|
|
94
|
+
e.fix = { desc: 'remove', range: [start, e.endIndex], text: '' };
|
|
95
|
+
errors.push(e);
|
|
91
96
|
}
|
|
92
97
|
try {
|
|
93
98
|
this.findMatchingTag();
|
|
@@ -95,38 +100,53 @@ class HtmlToken extends index_1.Token {
|
|
|
95
100
|
catch (e) {
|
|
96
101
|
if (e instanceof SyntaxError) {
|
|
97
102
|
const { message } = e;
|
|
98
|
-
const msg = message.split(':')[0].toLowerCase(), error = (0, lint_1.generateForSelf)(this, rect, 'unmatched-tag', msg)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
const msg = message.split(':')[0].toLowerCase(), error = (0, lint_1.generateForSelf)(this, rect, 'unmatched-tag', msg), noSelfClosing = {
|
|
104
|
+
desc: 'no self-closing',
|
|
105
|
+
range: [error.endIndex - 2, error.endIndex - 1],
|
|
106
|
+
text: '',
|
|
107
|
+
};
|
|
108
|
+
switch (msg) {
|
|
109
|
+
case 'unclosed tag': {
|
|
110
|
+
const childNodes = this.parentNode?.childNodes;
|
|
111
|
+
if (formattingTags.has(this.name)
|
|
112
|
+
&& childNodes?.slice(0, childNodes.indexOf(this))
|
|
113
|
+
.some(({ type, name }) => type === 'html' && name === this.name)) {
|
|
114
|
+
error.suggestions = [{ desc: 'close', range: [start + 1, start + 1], text: '/' }];
|
|
115
|
+
}
|
|
116
|
+
else if (!this.closest('heading-title')) {
|
|
103
117
|
error.severity = 'warning';
|
|
104
118
|
}
|
|
119
|
+
break;
|
|
105
120
|
}
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
case 'unmatched closing tag': {
|
|
122
|
+
const ancestor = this.closest('magic-word');
|
|
123
|
+
if (ancestor && magicWords.has(ancestor.name)) {
|
|
124
|
+
error.severity = 'warning';
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
error.suggestions = [{ desc: 'remove', range: [start, error.endIndex], text: '' }];
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
108
130
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
131
|
+
case 'tag that is both closing and self-closing': {
|
|
132
|
+
const { html: [normalTags, , voidTags] } = this.getAttribute('config'), open = { desc: 'open', range: [start + 1, start + 2], text: '' };
|
|
133
|
+
if (voidTags.includes(this.name)) {
|
|
134
|
+
error.fix = open;
|
|
135
|
+
}
|
|
136
|
+
else if (normalTags.includes(this.name)) {
|
|
137
|
+
error.fix = noSelfClosing;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
error.suggestions = [open, noSelfClosing];
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
114
143
|
}
|
|
115
|
-
|
|
144
|
+
case 'invalid self-closing tag':
|
|
116
145
|
error.suggestions = [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
range: [start, error.endIndex],
|
|
120
|
-
text: '',
|
|
121
|
-
},
|
|
146
|
+
noSelfClosing,
|
|
147
|
+
{ desc: 'close', range: [error.endIndex - 2, error.endIndex], text: `></${this.name}>` },
|
|
122
148
|
];
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
else if (msg === 'tag that is both closing and self-closing') {
|
|
126
|
-
const { html: [, , voidTags] } = this.getAttribute('config');
|
|
127
|
-
if (voidTags.includes(this.name)) {
|
|
128
|
-
error.fix = { range: [start + 1, start + 2], text: '', desc: 'open' };
|
|
129
|
-
}
|
|
149
|
+
// no default
|
|
130
150
|
}
|
|
131
151
|
errors.push(error);
|
|
132
152
|
}
|
|
@@ -111,7 +111,9 @@ class ImageParameterToken extends index_2.Token {
|
|
|
111
111
|
errors.push(e);
|
|
112
112
|
}
|
|
113
113
|
else if (typeof link === 'object' && link.encoded) {
|
|
114
|
-
|
|
114
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'url-encoding', 'unnecessary URL encoding in an internal link');
|
|
115
|
+
e.suggestions = [{ desc: 'decode', range: [start, e.endIndex], text: (0, string_1.rawurldecode)(this.text()) }];
|
|
116
|
+
errors.push(e);
|
|
115
117
|
}
|
|
116
118
|
return errors;
|
|
117
119
|
}
|
package/dist/src/imagemap.js
CHANGED
|
@@ -95,7 +95,14 @@ class ImagemapToken extends index_2.Token {
|
|
|
95
95
|
errors.push(...this.childNodes.filter(child => {
|
|
96
96
|
const str = child.toString().trim();
|
|
97
97
|
return child.type === 'noinclude' && str && !str.startsWith('#');
|
|
98
|
-
}).map(child =>
|
|
98
|
+
}).map(child => {
|
|
99
|
+
const e = (0, lint_1.generateForChild)(child, rect, 'invalid-imagemap', 'invalid link in <imagemap>');
|
|
100
|
+
e.suggestions = [
|
|
101
|
+
{ desc: 'remove', range: [e.startIndex - 1, e.endIndex], text: '' },
|
|
102
|
+
{ desc: 'comment', range: [e.startIndex, e.startIndex], text: '# ' },
|
|
103
|
+
];
|
|
104
|
+
return e;
|
|
105
|
+
}));
|
|
99
106
|
}
|
|
100
107
|
else {
|
|
101
108
|
errors.push((0, lint_1.generateForSelf)(this, rect, 'invalid-imagemap', '<imagemap> without an image'));
|
package/dist/src/index.js
CHANGED
|
@@ -337,47 +337,35 @@ class Token extends element_1.AstElement {
|
|
|
337
337
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
338
338
|
let errors = super.lint(start, re);
|
|
339
339
|
if (this.type === 'root') {
|
|
340
|
-
const record = new Map(), selector = 'category,html-attr#id,ext-attr#id,table-attr#id
|
|
340
|
+
const record = new Map(), selector = 'category,html-attr#id,ext-attr#id,table-attr#id';
|
|
341
341
|
for (const cat of this.querySelectorAll(selector)) {
|
|
342
342
|
let key;
|
|
343
343
|
if (cat.type === 'category') {
|
|
344
344
|
key = cat.name;
|
|
345
345
|
}
|
|
346
346
|
else {
|
|
347
|
-
const value = cat.getValue()
|
|
348
|
-
if (
|
|
349
|
-
key = `#${value
|
|
347
|
+
const value = cat.getValue();
|
|
348
|
+
if (value && value !== true) {
|
|
349
|
+
key = `#${value}`;
|
|
350
350
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
351
|
+
}
|
|
352
|
+
if (key) {
|
|
353
|
+
const thisCat = record.get(key);
|
|
354
|
+
if (thisCat) {
|
|
355
|
+
thisCat.add(cat);
|
|
355
356
|
}
|
|
356
357
|
else {
|
|
357
|
-
|
|
358
|
+
record.set(key, new Set([cat]));
|
|
358
359
|
}
|
|
359
360
|
}
|
|
360
|
-
const thisCat = record.get(key);
|
|
361
|
-
if (thisCat) {
|
|
362
|
-
thisCat.add(cat);
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
record.set(key, new Set([cat]));
|
|
366
|
-
}
|
|
367
361
|
}
|
|
368
362
|
for (const [key, value] of record) {
|
|
369
363
|
if (value.size > 1 && !key.startsWith('#mw-customcollapsible-')) {
|
|
370
|
-
const isCat = !key.
|
|
364
|
+
const isCat = !key.startsWith('#'), msg = `duplicated ${isCat ? 'category' : 'id'}`, severity = isCat ? 'error' : 'warning';
|
|
371
365
|
errors.push(...[...value].map(cat => {
|
|
372
366
|
const e = (0, lint_1.generateForSelf)(cat, { start: cat.getAbsoluteIndex() }, 'no-duplicate', msg, severity);
|
|
373
367
|
if (isCat) {
|
|
374
|
-
e.suggestions = [
|
|
375
|
-
{
|
|
376
|
-
desc: 'remove',
|
|
377
|
-
range: [e.startIndex, e.endIndex],
|
|
378
|
-
text: '',
|
|
379
|
-
},
|
|
380
|
-
];
|
|
368
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex, e.endIndex], text: '' }];
|
|
381
369
|
}
|
|
382
370
|
return e;
|
|
383
371
|
}));
|
package/dist/src/link/base.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LinkBaseToken = void 0;
|
|
4
4
|
const lint_1 = require("../../util/lint");
|
|
5
5
|
const constants_1 = require("../../util/constants");
|
|
6
|
+
const string_1 = require("../../util/string");
|
|
6
7
|
const rect_1 = require("../../lib/rect");
|
|
7
8
|
const index_1 = require("../../index");
|
|
8
9
|
const index_2 = require("../index");
|
|
@@ -85,7 +86,9 @@ class LinkBaseToken extends index_2.Token {
|
|
|
85
86
|
errors.push((0, lint_1.generateForChild)(target, rect, 'unknown-page', 'template in an internal link target', 'warning'));
|
|
86
87
|
}
|
|
87
88
|
if (encoded) {
|
|
88
|
-
|
|
89
|
+
const e = (0, lint_1.generateForChild)(target, rect, 'url-encoding', 'unnecessary URL encoding in an internal link');
|
|
90
|
+
e.suggestions = [{ desc: 'decode', range: [e.startIndex, e.endIndex], text: (0, string_1.rawurldecode)(target.text()) }];
|
|
91
|
+
errors.push(e);
|
|
89
92
|
}
|
|
90
93
|
if (type === 'link' || type === 'category') {
|
|
91
94
|
const textNode = linkText?.childNodes.find((c) => c.type === 'text' && c.data.includes('|'));
|
package/dist/src/link/file.js
CHANGED
|
@@ -91,7 +91,11 @@ class FileToken extends base_1.LinkBaseToken {
|
|
|
91
91
|
* @param msg 消息键
|
|
92
92
|
* @param p1 替换$1
|
|
93
93
|
*/
|
|
94
|
-
const generate = (msg, p1) => (arg) =>
|
|
94
|
+
const generate = (msg, p1) => (arg) => {
|
|
95
|
+
const e = (0, lint_1.generateForChild)(arg, rect, 'no-duplicate', index_1.default.msg(`${msg} image $1 parameter`, p1));
|
|
96
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex - 1, e.endIndex], text: '' }];
|
|
97
|
+
return e;
|
|
98
|
+
};
|
|
95
99
|
for (const key of keys) {
|
|
96
100
|
if (key === 'invalid' || key === 'width' && unscaled) {
|
|
97
101
|
continue;
|
|
@@ -46,7 +46,9 @@ class GalleryImageToken extends file_1.FileToken {
|
|
|
46
46
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
47
47
|
const errors = super.lint(start, re), { ns, interwiki } = this.getAttribute('title');
|
|
48
48
|
if (interwiki || ns !== 6) {
|
|
49
|
-
|
|
49
|
+
const e = (0, lint_1.generateForSelf)(this, { start }, 'invalid-gallery', 'invalid gallery image');
|
|
50
|
+
e.suggestions = [{ desc: 'prefix', range: [start, start], text: 'File:' }];
|
|
51
|
+
errors.push(e);
|
|
50
52
|
}
|
|
51
53
|
return errors;
|
|
52
54
|
}
|
package/dist/src/magicLink.js
CHANGED
|
@@ -66,24 +66,10 @@ class MagicLinkToken extends index_2.Token {
|
|
|
66
66
|
if (child) {
|
|
67
67
|
const { data } = child, e = (0, lint_1.generateForChild)(child, rect, 'unterminated-url', index_1.default.msg('$1 in URL', pipe ? '"|"' : 'full-width punctuation'), 'warning'), { index, 0: s } = regex.exec(data), i = e.startIndex + index;
|
|
68
68
|
e.suggestions = pipe
|
|
69
|
-
? [
|
|
70
|
-
{
|
|
71
|
-
desc: 'whitespace',
|
|
72
|
-
range: [i, i + 1],
|
|
73
|
-
text: ' ',
|
|
74
|
-
},
|
|
75
|
-
]
|
|
69
|
+
? [{ desc: 'whitespace', range: [i, i + 1], text: ' ' }]
|
|
76
70
|
: [
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
range: [i, i],
|
|
80
|
-
text: ' ',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
desc: 'escape',
|
|
84
|
-
range: [i, i + s.length],
|
|
85
|
-
text: encodeURI(s),
|
|
86
|
-
},
|
|
71
|
+
{ desc: 'whitespace', range: [i, i], text: ' ' },
|
|
72
|
+
{ desc: 'escape', range: [i, i + s.length], text: encodeURI(s) },
|
|
87
73
|
];
|
|
88
74
|
errors.push(e);
|
|
89
75
|
}
|
package/dist/src/nested.js
CHANGED
|
@@ -68,16 +68,8 @@ class NestedToken extends index_2.Token {
|
|
|
68
68
|
}).map(child => {
|
|
69
69
|
const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', index_1.default.msg('invalid content in <$1>', this.name));
|
|
70
70
|
e.suggestions = [
|
|
71
|
-
{
|
|
72
|
-
|
|
73
|
-
range: [e.startIndex, e.endIndex],
|
|
74
|
-
text: '',
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
desc: 'comment',
|
|
78
|
-
range: [e.startIndex, e.endIndex],
|
|
79
|
-
text: `<!--${child.toString()}-->`,
|
|
80
|
-
},
|
|
71
|
+
{ desc: 'remove', range: [e.startIndex, e.endIndex], text: '' },
|
|
72
|
+
{ desc: 'comment', range: [e.startIndex, e.endIndex], text: `<!--${child.toString()}-->` },
|
|
81
73
|
];
|
|
82
74
|
return e;
|
|
83
75
|
}),
|
|
@@ -74,7 +74,7 @@ let CommentToken = (() => {
|
|
|
74
74
|
return [];
|
|
75
75
|
}
|
|
76
76
|
const e = (0, lint_1.generateForSelf)(this, { start }, 'unclosed-comment', index_1.default.msg('unclosed $1', 'HTML comment'));
|
|
77
|
-
e.
|
|
77
|
+
e.suggestions = [{ range: [e.endIndex, e.endIndex], text: '-->', desc: 'close' }];
|
|
78
78
|
return [e];
|
|
79
79
|
}
|
|
80
80
|
/** @private */
|
package/dist/src/nowiki/quote.js
CHANGED
|
@@ -33,11 +33,10 @@ class QuoteToken extends base_1.NowikiBaseToken {
|
|
|
33
33
|
* @param endIndex 终点
|
|
34
34
|
* @param length 长度
|
|
35
35
|
*/
|
|
36
|
-
const getSuggestion = (startIndex, endIndex, length) =>
|
|
37
|
-
desc: 'escape',
|
|
38
|
-
range: [startIndex, endIndex],
|
|
39
|
-
|
|
40
|
-
});
|
|
36
|
+
const getSuggestion = (startIndex, endIndex, length) => [
|
|
37
|
+
{ desc: 'escape', range: [startIndex, endIndex], text: '''.repeat(length) },
|
|
38
|
+
{ desc: 'remove', range: [startIndex, endIndex], text: '' },
|
|
39
|
+
];
|
|
41
40
|
if (previousSibling?.type === 'text' && previousSibling.data.endsWith(`'`)) {
|
|
42
41
|
refError = (0, lint_1.generateForSelf)(this, rect, 'lonely-apos', message);
|
|
43
42
|
const { startIndex: endIndex, startLine: endLine, startCol: endCol } = refError, [, { length }] = /(?:^|[^'])('+)$/u.exec(previousSibling.data), startIndex = start - length;
|
|
@@ -48,7 +47,7 @@ class QuoteToken extends base_1.NowikiBaseToken {
|
|
|
48
47
|
startCol: endCol - length,
|
|
49
48
|
endLine,
|
|
50
49
|
endCol,
|
|
51
|
-
suggestions:
|
|
50
|
+
suggestions: getSuggestion(startIndex, endIndex, length),
|
|
52
51
|
});
|
|
53
52
|
}
|
|
54
53
|
if (nextSibling?.type === 'text' && nextSibling.data.startsWith(`'`)) {
|
|
@@ -61,11 +60,14 @@ class QuoteToken extends base_1.NowikiBaseToken {
|
|
|
61
60
|
startLine,
|
|
62
61
|
startCol,
|
|
63
62
|
endCol: startCol + length,
|
|
64
|
-
suggestions:
|
|
63
|
+
suggestions: getSuggestion(startIndex, endIndex, length),
|
|
65
64
|
});
|
|
66
65
|
}
|
|
67
66
|
if (bold && this.closest('heading-title')) {
|
|
68
|
-
errors.push(
|
|
67
|
+
errors.push({
|
|
68
|
+
...(0, lint_1.generateForSelf)(this, rect, 'bold-header', 'bold in section header', 'warning'),
|
|
69
|
+
suggestions: [{ desc: 'remove', range: [start, start + 3], text: '' }],
|
|
70
|
+
});
|
|
69
71
|
}
|
|
70
72
|
return errors;
|
|
71
73
|
}
|
|
@@ -52,13 +52,7 @@ class ParamTagToken extends index_2.Token {
|
|
|
52
52
|
const i = grandChildren.findIndex(({ type }) => type !== 'text'), str = grandChildren.slice(0, i === -1 ? undefined : i).map(String).join('');
|
|
53
53
|
if (str && !(i === -1 ? /^[a-z]+(?:\[\])?\s*=/iu : /^[a-z]+(?:\[\])?\s*(?:=|$)/iu).test(str)) {
|
|
54
54
|
const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', msg);
|
|
55
|
-
e.suggestions = [
|
|
56
|
-
{
|
|
57
|
-
desc: 'remove',
|
|
58
|
-
range: [e.startIndex, e.endIndex],
|
|
59
|
-
text: '',
|
|
60
|
-
},
|
|
61
|
-
];
|
|
55
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex, e.endIndex], text: '' }];
|
|
62
56
|
errors.push(e);
|
|
63
57
|
}
|
|
64
58
|
else {
|
|
@@ -80,24 +80,12 @@ let IncludeToken = (() => {
|
|
|
80
80
|
const errors = [], { firstChild, closed, name } = this, rect = new rect_1.BoundingRect(this, start);
|
|
81
81
|
if (firstChild.data.trim()) {
|
|
82
82
|
const e = (0, lint_1.generateForChild)(firstChild, rect, 'no-ignored', 'useless attribute', 'warning');
|
|
83
|
-
e.suggestions = [
|
|
84
|
-
{
|
|
85
|
-
desc: 'remove',
|
|
86
|
-
range: [e.startIndex, e.endIndex],
|
|
87
|
-
text: '',
|
|
88
|
-
},
|
|
89
|
-
];
|
|
83
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex, e.endIndex], text: '' }];
|
|
90
84
|
errors.push(e);
|
|
91
85
|
}
|
|
92
86
|
if (!closed) {
|
|
93
87
|
const e = (0, lint_1.generateForSelf)(this, rect, 'unclosed-comment', index_1.default.msg('unclosed $1', `<${name}>`));
|
|
94
|
-
e.suggestions = [
|
|
95
|
-
{
|
|
96
|
-
desc: 'close',
|
|
97
|
-
range: [e.endIndex, e.endIndex],
|
|
98
|
-
text: `</${name}>`,
|
|
99
|
-
},
|
|
100
|
-
];
|
|
88
|
+
e.suggestions = [{ desc: 'close', range: [e.endIndex, e.endIndex], text: `</${name}>` }];
|
|
101
89
|
errors.push(e);
|
|
102
90
|
}
|
|
103
91
|
return errors;
|
package/dist/src/transclude.js
CHANGED
|
@@ -204,7 +204,11 @@ class TranscludeToken extends index_2.Token {
|
|
|
204
204
|
}
|
|
205
205
|
const duplicatedArgs = this.getDuplicatedArgs().filter(([, parameter]) => !parameter[0].querySelector('ext'));
|
|
206
206
|
if (duplicatedArgs.length > 0) {
|
|
207
|
-
errors.push(...duplicatedArgs.flatMap(([, args]) => args).map(arg =>
|
|
207
|
+
errors.push(...duplicatedArgs.flatMap(([, args]) => args).map(arg => {
|
|
208
|
+
const e = (0, lint_1.generateForChild)(arg, rect, 'no-duplicate', 'duplicated parameter');
|
|
209
|
+
e.suggestions = [{ desc: 'remove', range: [e.startIndex - 1, e.endIndex], text: '' }];
|
|
210
|
+
return e;
|
|
211
|
+
}));
|
|
208
212
|
}
|
|
209
213
|
return errors;
|
|
210
214
|
}
|
package/i18n/zh-hans.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"content to be moved out from the table": "将被移出表格的内容",
|
|
12
12
|
"duplicated $1 attribute": "重复的$1属性",
|
|
13
13
|
"duplicated category": "重复的分类",
|
|
14
|
-
"duplicated id
|
|
14
|
+
"duplicated id": "重复的id",
|
|
15
15
|
"duplicated image $1 parameter": "重复的图片$1参数",
|
|
16
16
|
"duplicated parameter": "重复参数",
|
|
17
17
|
"extension tag in HTML tag attributes": "HTML标签属性中的扩展标签",
|
package/i18n/zh-hant.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"content to be moved out from the table": "將被移出表格的內容",
|
|
12
12
|
"duplicated $1 attribute": "重複的$1屬性",
|
|
13
13
|
"duplicated category": "重複的分類",
|
|
14
|
-
"duplicated id
|
|
14
|
+
"duplicated id": "重複的id",
|
|
15
15
|
"duplicated image $1 parameter": "重複的圖片$1參數",
|
|
16
16
|
"duplicated parameter": "重複參數",
|
|
17
17
|
"extension tag in HTML tag attributes": "HTML標籤屬性中的擴展標籤",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -75,6 +75,6 @@
|
|
|
75
75
|
"v8r": "^4.2.0"
|
|
76
76
|
},
|
|
77
77
|
"engines": {
|
|
78
|
-
"node": ">=
|
|
78
|
+
"node": ">=18.12.0"
|
|
79
79
|
}
|
|
80
80
|
}
|