wikilint 2.45.0 → 2.46.1
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.mts +9 -1
- package/dist/base.d.ts +9 -1
- package/dist/bin/config.js +1 -1
- package/dist/lib/lsp.d.ts +10 -1
- package/dist/lib/lsp.js +74 -18
- package/dist/mixin/paramLineParent.d.ts +3 -0
- package/dist/mixin/paramLineParent.js +2 -2
- package/dist/src/attributes.js +6 -5
- package/dist/src/converterFlags.js +10 -17
- package/dist/src/link/file.js +5 -4
- package/dist/src/multiLine/charinsert.js +17 -17
- package/dist/src/multiLine/imagemap.js +6 -5
- package/dist/src/nested.js +22 -24
- package/dist/src/paramLine.d.ts +7 -1
- package/dist/src/paramLine.js +7 -1
- package/dist/src/table/td.js +5 -4
- package/dist/src/tag/index.js +13 -1
- package/dist/src/transclude.js +4 -4
- package/package.json +12 -12
package/dist/base.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Range, Position, ColorInformation, ColorPresentation, CompletionItem as CompletionItemBase, CompletionItemKind, FoldingRange, DocumentLink, Location, WorkspaceEdit, Diagnostic, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
|
|
1
|
+
import type { Range, Position, ColorInformation, ColorPresentation, CompletionItem as CompletionItemBase, CompletionItemKind, FoldingRange, DocumentLink, DocumentHighlight, Location, WorkspaceEdit, Diagnostic, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
|
|
2
2
|
export interface Config {
|
|
3
3
|
ext: string[];
|
|
4
4
|
readonly html: [string[], string[], string[]];
|
|
@@ -177,6 +177,14 @@ export interface LanguageService {
|
|
|
177
177
|
* @param text source Wikitext / 源代码
|
|
178
178
|
*/
|
|
179
179
|
provideLinks(text: string): Promise<DocumentLink[]>;
|
|
180
|
+
/**
|
|
181
|
+
* Provide document highlights
|
|
182
|
+
*
|
|
183
|
+
* 提供文档高亮
|
|
184
|
+
* @param text source Wikitext / 源代码
|
|
185
|
+
* @param position position / 位置
|
|
186
|
+
*/
|
|
187
|
+
provideDocumentHighlights(text: string, position: Position): Promise<DocumentHighlight[] | undefined>;
|
|
180
188
|
/**
|
|
181
189
|
* Provide references
|
|
182
190
|
*
|
package/dist/base.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Range, Position, ColorInformation, ColorPresentation, CompletionItem as CompletionItemBase, CompletionItemKind, FoldingRange, DocumentLink, Location, WorkspaceEdit, Diagnostic, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
|
|
1
|
+
import type { Range, Position, ColorInformation, ColorPresentation, CompletionItem as CompletionItemBase, CompletionItemKind, FoldingRange, DocumentLink, DocumentHighlight, Location, WorkspaceEdit, Diagnostic, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
|
|
2
2
|
export interface Config {
|
|
3
3
|
ext: string[];
|
|
4
4
|
readonly html: [string[], string[], string[]];
|
|
@@ -177,6 +177,14 @@ export interface LanguageService {
|
|
|
177
177
|
* @param text source Wikitext / 源代码
|
|
178
178
|
*/
|
|
179
179
|
provideLinks(text: string): Promise<DocumentLink[]>;
|
|
180
|
+
/**
|
|
181
|
+
* Provide document highlights
|
|
182
|
+
*
|
|
183
|
+
* 提供文档高亮
|
|
184
|
+
* @param text source Wikitext / 源代码
|
|
185
|
+
* @param position position / 位置
|
|
186
|
+
*/
|
|
187
|
+
provideDocumentHighlights(text: string, position: Position): Promise<DocumentHighlight[] | undefined>;
|
|
180
188
|
/**
|
|
181
189
|
* Provide references
|
|
182
190
|
*
|
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 =
|
|
44
|
+
const pkg = 'wikilint', version = '2.46.1';
|
|
45
45
|
/**
|
|
46
46
|
* Get the parser configuration for a Wikimedia Foundation project.
|
|
47
47
|
* @param site site nickname
|
package/dist/lib/lsp.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Parser from '../index';
|
|
2
2
|
import { Token } from '../src/index';
|
|
3
|
-
import type { Range, Position, ColorInformation, ColorPresentation, FoldingRange, DocumentLink, Location, WorkspaceEdit, Diagnostic as DiagnosticBase, TextEdit, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
|
|
3
|
+
import type { Range, Position, ColorInformation, ColorPresentation, FoldingRange, DocumentLink, Location, DocumentHighlight, WorkspaceEdit, Diagnostic as DiagnosticBase, TextEdit, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
|
|
4
4
|
import type { Config, LanguageService as LanguageServiceBase, CompletionItem, SignatureData } from '../base';
|
|
5
5
|
import type { AttributeToken } from '../internal';
|
|
6
6
|
import type { TokenTypeMap, SelectedTokenTypes } from '../map';
|
|
@@ -71,6 +71,15 @@ export declare class LanguageService implements LanguageServiceBase {
|
|
|
71
71
|
* @param text source Wikitext / 源代码
|
|
72
72
|
*/
|
|
73
73
|
provideLinks(text: string): Promise<DocumentLink[]>;
|
|
74
|
+
/**
|
|
75
|
+
* Provide document highlights
|
|
76
|
+
*
|
|
77
|
+
* 提供文档高亮
|
|
78
|
+
* @param text source Wikitext / 源代码
|
|
79
|
+
* @param position position / 位置
|
|
80
|
+
* @since v1.46.1
|
|
81
|
+
*/
|
|
82
|
+
provideDocumentHighlights(text: string, position: Position): Promise<DocumentHighlight[] | undefined>;
|
|
74
83
|
/**
|
|
75
84
|
* Provide references
|
|
76
85
|
*
|
package/dist/lib/lsp.js
CHANGED
|
@@ -21,6 +21,7 @@ const util_1 = __importDefault(require("util"));
|
|
|
21
21
|
const child_process_1 = require("child_process");
|
|
22
22
|
const crypto_1 = require("crypto");
|
|
23
23
|
const stylelint_util_1 = require("@bhsd/stylelint-util");
|
|
24
|
+
const color_1 = require("@bhsd/common/color");
|
|
24
25
|
const search_1 = __importDefault(require("../vendor/search"));
|
|
25
26
|
const constants_2 = require("../util/constants");
|
|
26
27
|
const document_1 = require("./document");
|
|
@@ -30,15 +31,17 @@ const refTags = new Set(['ref']), referencesTags = new Set(['ref', 'references']
|
|
|
30
31
|
'template-name',
|
|
31
32
|
'link-target',
|
|
32
33
|
'parameter-key',
|
|
33
|
-
]),
|
|
34
|
+
]), highlightTypes = new Set([
|
|
34
35
|
'ext',
|
|
35
36
|
'html',
|
|
36
37
|
'attr-key',
|
|
38
|
+
'magic-word-name',
|
|
39
|
+
...renameTypes,
|
|
40
|
+
]), referenceTypes = new Set([
|
|
37
41
|
'image-parameter',
|
|
38
42
|
'heading-title',
|
|
39
43
|
'heading',
|
|
40
|
-
|
|
41
|
-
...renameTypes,
|
|
44
|
+
...highlightTypes,
|
|
42
45
|
]), plainTypes = new Set(['text', 'comment', 'noinclude', 'include']), rawLilyPondCommands = new Set(['paper', 'book', 'bookpart', 'score', 'markuplist'].map(c => `\\${c}`)), cssSelector = ['ext', 'html', 'table'].map(s => `${s}-attr#style`).join();
|
|
43
46
|
const getLinkRegex = (0, common_1.getRegex)(protocol => new RegExp(`^(?:${protocol}|//)`, 'iu'));
|
|
44
47
|
/**
|
|
@@ -168,8 +171,10 @@ const getName = (token) => {
|
|
|
168
171
|
return token.level;
|
|
169
172
|
case 'heading-title':
|
|
170
173
|
return parentNode.level;
|
|
171
|
-
case 'parameter-key':
|
|
172
|
-
|
|
174
|
+
case 'parameter-key': {
|
|
175
|
+
const { type: t, name: n } = parentNode.parentNode;
|
|
176
|
+
return n + (t === 'template' ? '|' : '#') + parentNode.name;
|
|
177
|
+
}
|
|
173
178
|
case 'ext':
|
|
174
179
|
case 'html':
|
|
175
180
|
case 'image-parameter':
|
|
@@ -178,6 +183,22 @@ const getName = (token) => {
|
|
|
178
183
|
return parentNode.name;
|
|
179
184
|
}
|
|
180
185
|
};
|
|
186
|
+
/**
|
|
187
|
+
* Get the tokens that match the given token.
|
|
188
|
+
* @param root
|
|
189
|
+
* @param node the token to match
|
|
190
|
+
* @param types accepted token types
|
|
191
|
+
*/
|
|
192
|
+
const getMatchingTokens = (root, node, types) => {
|
|
193
|
+
const { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
194
|
+
if (!refName && !refGroup && !types.has(type)) {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
const name = getName(node), refs = root.querySelectorAll(type === 'heading-title' ? 'heading' : type).filter(token => type === 'attr-value'
|
|
198
|
+
? getRefName(token) === refName || getRefGroup(token) === refGroup
|
|
199
|
+
: getName(token) === name);
|
|
200
|
+
return refs.length === 0 ? undefined : refs.reverse();
|
|
201
|
+
};
|
|
181
202
|
/**
|
|
182
203
|
* Get the quick fix data.
|
|
183
204
|
* @param root root token
|
|
@@ -272,7 +293,7 @@ const partialParse = async (wikitext, watch, include, config = index_1.default.g
|
|
|
272
293
|
};
|
|
273
294
|
/* NOT FOR BROWSER ONLY */
|
|
274
295
|
/** @see https://www.npmjs.com/package/stylelint-config-recommended */
|
|
275
|
-
const cssRules = { 'block-no-empty': null }, colors = Object.keys(
|
|
296
|
+
const cssRules = { 'block-no-empty': null }, colors = Object.keys(color_1.colorsNamed), sources = { 'invalid-css': 'css', 'invalid-math': 'texvc' }, jsonSelector = constants_2.jsonTags.map(s => `ext#${s}`).join(), scores = new Map();
|
|
276
297
|
/**
|
|
277
298
|
* Correct the position of an error.
|
|
278
299
|
* @param height
|
|
@@ -911,7 +932,8 @@ class LanguageService {
|
|
|
911
932
|
catch (e) {
|
|
912
933
|
const { stderr } = e;
|
|
913
934
|
if (stderr) {
|
|
914
|
-
const re = new RegExp(String.raw `^${file}:(\d+):(\d+): error: (.+)$`, 'gmu'), lilypondErrors = [...stderr.matchAll(re)]
|
|
935
|
+
const re = new RegExp(String.raw `^${file}:(\d+):(\d+): error: (.+)$`, 'gmu'), lilypondErrors = [...stderr.matchAll(re)]
|
|
936
|
+
.map(([, line, col, msg]) => {
|
|
915
937
|
const { offsetHeight, offsetWidth } = token.lastChild, pos = adjustPos(offsetHeight, offsetWidth, Number(line) - 1, Number(col) - 1);
|
|
916
938
|
return {
|
|
917
939
|
line: pos[0],
|
|
@@ -1122,6 +1144,37 @@ class LanguageService {
|
|
|
1122
1144
|
})
|
|
1123
1145
|
.filter(link => link !== false);
|
|
1124
1146
|
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Provide document highlights
|
|
1149
|
+
*
|
|
1150
|
+
* 提供文档高亮
|
|
1151
|
+
* @param text source Wikitext / 源代码
|
|
1152
|
+
* @param position position / 位置
|
|
1153
|
+
* @since v1.46.1
|
|
1154
|
+
*/
|
|
1155
|
+
async provideDocumentHighlights(text, position) {
|
|
1156
|
+
const root = await this.#queue(text), index = root.indexFromPos(position.line, position.character), node = root.elementFromIndex(index), type = node?.type;
|
|
1157
|
+
if (!node || (type === 'ext' || type === 'html') && !/\w/u.test(text.charAt(index))) {
|
|
1158
|
+
return undefined;
|
|
1159
|
+
}
|
|
1160
|
+
return getMatchingTokens(root, node, highlightTypes)?.map((token) => {
|
|
1161
|
+
const range = createNodeRange(token);
|
|
1162
|
+
if (type === 'ext' || type === 'html') {
|
|
1163
|
+
const { start } = range;
|
|
1164
|
+
start.character += token.closing ? 2 : 1;
|
|
1165
|
+
return {
|
|
1166
|
+
range: {
|
|
1167
|
+
start,
|
|
1168
|
+
end: {
|
|
1169
|
+
line: start.line,
|
|
1170
|
+
character: start.character + token.name.length,
|
|
1171
|
+
},
|
|
1172
|
+
},
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
return { range };
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1125
1178
|
/**
|
|
1126
1179
|
* Provide references
|
|
1127
1180
|
*
|
|
@@ -1132,16 +1185,19 @@ class LanguageService {
|
|
|
1132
1185
|
async provideReferences(text, position) {
|
|
1133
1186
|
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0 && (element.is('ext-attr-dirty') || element.is('html-attr-dirty'))
|
|
1134
1187
|
? element.parentNode.parentNode
|
|
1135
|
-
: element
|
|
1136
|
-
|
|
1137
|
-
return undefined;
|
|
1138
|
-
}
|
|
1139
|
-
const name = getName(node), refs = root.querySelectorAll(type === 'heading-title' ? 'heading' : type).filter(token => type === 'attr-value'
|
|
1140
|
-
? getRefName(token) === refName || getRefGroup(token) === refGroup
|
|
1141
|
-
: getName(token) === name).reverse().map((token) => ({
|
|
1188
|
+
: element;
|
|
1189
|
+
return getMatchingTokens(root, node, referenceTypes)?.map((token) => ({
|
|
1142
1190
|
range: createNodeRange(token.type === 'parameter-key' ? token.parentNode : token),
|
|
1143
1191
|
}));
|
|
1144
|
-
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* 获取根节点和当前节点
|
|
1195
|
+
* @param text 源代码
|
|
1196
|
+
* @param position 位置
|
|
1197
|
+
*/
|
|
1198
|
+
async #getRootAndNode(text, position) {
|
|
1199
|
+
const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.line);
|
|
1200
|
+
return [root, node];
|
|
1145
1201
|
}
|
|
1146
1202
|
/**
|
|
1147
1203
|
* Provide definitions
|
|
@@ -1151,7 +1207,7 @@ class LanguageService {
|
|
|
1151
1207
|
* @param position position / 位置
|
|
1152
1208
|
*/
|
|
1153
1209
|
async provideDefinition(text, position) {
|
|
1154
|
-
const root = await this.#
|
|
1210
|
+
const [root, node] = await this.#getRootAndNode(text, position);
|
|
1155
1211
|
if (!node) {
|
|
1156
1212
|
return undefined;
|
|
1157
1213
|
}
|
|
@@ -1176,7 +1232,7 @@ class LanguageService {
|
|
|
1176
1232
|
* @param position position / 位置
|
|
1177
1233
|
*/
|
|
1178
1234
|
async resolveRenameLocation(text, position) {
|
|
1179
|
-
const
|
|
1235
|
+
const [, node] = await this.#getRootAndNode(text, position);
|
|
1180
1236
|
if (!node) {
|
|
1181
1237
|
return undefined;
|
|
1182
1238
|
}
|
|
@@ -1196,7 +1252,7 @@ class LanguageService {
|
|
|
1196
1252
|
* @param newName new name / 新名称
|
|
1197
1253
|
*/
|
|
1198
1254
|
async provideRenameEdits(text, position, newName) {
|
|
1199
|
-
const root = await this.#
|
|
1255
|
+
const [root, node] = await this.#getRootAndNode(text, position);
|
|
1200
1256
|
if (!node) {
|
|
1201
1257
|
return undefined;
|
|
1202
1258
|
}
|
|
@@ -4,6 +4,7 @@ export interface ParamLineParentBase {
|
|
|
4
4
|
* Get all parameter keys
|
|
5
5
|
*
|
|
6
6
|
* 获取所有参数键
|
|
7
|
+
* @since v1.45.0
|
|
7
8
|
*/
|
|
8
9
|
getKeys(): Set<string>;
|
|
9
10
|
/**
|
|
@@ -11,12 +12,14 @@ export interface ParamLineParentBase {
|
|
|
11
12
|
*
|
|
12
13
|
* 获取指定参数
|
|
13
14
|
* @param key parameter key / 参数键
|
|
15
|
+
* @since v1.45.0
|
|
14
16
|
*/
|
|
15
17
|
getParams(key: string): ParamLineToken[];
|
|
16
18
|
/**
|
|
17
19
|
* Get duplicated parameters
|
|
18
20
|
*
|
|
19
21
|
* 获取重复参数
|
|
22
|
+
* @since v1.45.0
|
|
20
23
|
*/
|
|
21
24
|
getDuplicatedParams(): [string, ParamLineToken[]][];
|
|
22
25
|
}
|
|
@@ -30,8 +30,8 @@ const paramLineParent = (constructor) => {
|
|
|
30
30
|
if (s) {
|
|
31
31
|
const msg = index_1.default.msg('duplicate-ext-parameter', name), rect = new rect_1.BoundingRect(this, start), { computeEditInfo } = lintConfig;
|
|
32
32
|
for (const [, params] of this.getDuplicatedParams()) {
|
|
33
|
-
const duplication = Array.from({ length
|
|
34
|
-
for (let i =
|
|
33
|
+
const { length } = params, duplication = Array.from({ length });
|
|
34
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
35
35
|
const param = params[i], e = (0, lint_1.generateForChild)(param, rect, rule, msg, s);
|
|
36
36
|
if (computeEditInfo) {
|
|
37
37
|
e.suggestions = [(0, lint_1.fixByRemove)(e, param === firstChild ? 0 : -1)];
|
package/dist/src/attributes.js
CHANGED
|
@@ -159,7 +159,7 @@ class AttributesToken extends index_2.Token {
|
|
|
159
159
|
/** @private */
|
|
160
160
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
161
161
|
LINT: {
|
|
162
|
-
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', 'invalid-ref', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
|
|
162
|
+
const errors = super.lint(start, re), { parentNode, childNodes, length: l, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'required-attr', 'invalid-ref', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
|
|
163
163
|
.map(k => lintConfig.getSeverity(rules[0], k));
|
|
164
164
|
if (s[0] && this.#lint()) {
|
|
165
165
|
const e = (0, lint_1.generateForSelf)(this, rect, rules[0], 'attributes-of-closing-tag', s[0]);
|
|
@@ -172,7 +172,8 @@ class AttributesToken extends index_2.Token {
|
|
|
172
172
|
}
|
|
173
173
|
errors.push(e);
|
|
174
174
|
}
|
|
175
|
-
for (
|
|
175
|
+
for (let i = l - 1; i >= 0; i--) {
|
|
176
|
+
const attr = childNodes[i];
|
|
176
177
|
if (attr instanceof attribute_1.AttributeToken) {
|
|
177
178
|
const { name } = attr;
|
|
178
179
|
if (attrs.has(name)) {
|
|
@@ -217,8 +218,8 @@ class AttributesToken extends index_2.Token {
|
|
|
217
218
|
const severity = lintConfig.getSeverity(rules[3], 'attribute');
|
|
218
219
|
if (severity && duplicated.size > 0) {
|
|
219
220
|
for (const key of duplicated) {
|
|
220
|
-
const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]), duplication = Array.from({ length
|
|
221
|
-
for (let i =
|
|
221
|
+
const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]), { length } = pairs, duplication = Array.from({ length }), values = new Set();
|
|
222
|
+
for (let i = 0; i < length; i++) {
|
|
222
223
|
const [attr, value] = pairs[i], e = (0, lint_1.generateForChild)(attr, rect, rules[3], index_1.default.msg('duplicate-attribute', key), severity);
|
|
223
224
|
if (computeEditInfo || fix) {
|
|
224
225
|
const remove = (0, lint_1.fixByRemove)(e);
|
|
@@ -232,7 +233,7 @@ class AttributesToken extends index_2.Token {
|
|
|
232
233
|
}
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
|
-
duplication[i] = e;
|
|
236
|
+
duplication[length - i - 1] = e;
|
|
236
237
|
}
|
|
237
238
|
Array.prototype.push.apply(errors, duplication);
|
|
238
239
|
}
|
|
@@ -100,11 +100,7 @@ let ConverterFlagsToken = (() => {
|
|
|
100
100
|
* 获取未知的转换类型标记
|
|
101
101
|
*/
|
|
102
102
|
getUnknownFlags() {
|
|
103
|
-
return new Set(this.#flags.filter(flag => /\{{3}[^{}]+\}{3}/u.test(flag)));
|
|
104
|
-
}
|
|
105
|
-
/** 从解析设置中获取语言变体 */
|
|
106
|
-
#getVariants() {
|
|
107
|
-
return new Set((0, string_1.toLowerCase)(this.getAttribute('config').variants));
|
|
103
|
+
LINT: return new Set(this.#flags.filter(flag => /\{{3}[^{}]+\}{3}/u.test(flag)));
|
|
108
104
|
}
|
|
109
105
|
/**
|
|
110
106
|
* Get language coversion flags that specify a language variant
|
|
@@ -112,16 +108,10 @@ let ConverterFlagsToken = (() => {
|
|
|
112
108
|
* 获取指定语言变体的转换标记
|
|
113
109
|
*/
|
|
114
110
|
getVariantFlags() {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
120
|
-
isInvalidFlag(flag, variant, unknown) {
|
|
121
|
-
return Boolean(flag)
|
|
122
|
-
&& !variant.has(flag.toLowerCase())
|
|
123
|
-
&& !unknown.has(flag)
|
|
124
|
-
&& (variant.size > 0 || !definedFlags.has(flag));
|
|
111
|
+
LINT: {
|
|
112
|
+
const variants = new Set((0, string_1.toLowerCase)(this.getAttribute('config').variants));
|
|
113
|
+
return new Set((0, string_1.toLowerCase)(this.#flags).filter(flag => variants.has(flag)));
|
|
114
|
+
}
|
|
125
115
|
}
|
|
126
116
|
/** @private */
|
|
127
117
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
@@ -134,9 +124,12 @@ let ConverterFlagsToken = (() => {
|
|
|
134
124
|
const rule = 'no-ignored', s = lintConfig.getSeverity(rule, 'conversionFlag');
|
|
135
125
|
if (s) {
|
|
136
126
|
const rect = new rect_1.BoundingRect(this, start), { childNodes, length } = this;
|
|
137
|
-
for (let i =
|
|
127
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
138
128
|
const child = childNodes[i], flag = child.text().trim();
|
|
139
|
-
if (
|
|
129
|
+
if (flag
|
|
130
|
+
&& !variantFlags.has(flag.toLowerCase())
|
|
131
|
+
&& !unknownFlags.has(flag)
|
|
132
|
+
&& (variantFlags.size > 0 || !definedFlags.has(flag))) {
|
|
140
133
|
const e = (0, lint_1.generateForChild)(child, rect, rule, 'invalid-conversion-flag', s);
|
|
141
134
|
if (computeEditInfo || fix) {
|
|
142
135
|
if (variantFlags.size === 0 && definedFlags.has(flag.toUpperCase())) {
|
package/dist/src/link/file.js
CHANGED
|
@@ -111,8 +111,9 @@ class FileToken extends base_1.LinkBaseToken {
|
|
|
111
111
|
}
|
|
112
112
|
s = lintConfig.getSeverity(rule, 'parameter');
|
|
113
113
|
if (s && unscaled) {
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
const widths = args.filter(({ name }) => name === 'width');
|
|
115
|
+
for (let i = widths.length - 1; i >= 0; i--) {
|
|
116
|
+
const e = (0, lint_1.generateForChild)(widths[i], rect, rule, 'invalid-image-parameter', s);
|
|
116
117
|
if (computeEditInfo || fix) {
|
|
117
118
|
e.fix = (0, lint_1.fixByRemove)(e, -1);
|
|
118
119
|
}
|
|
@@ -147,8 +148,8 @@ class FileToken extends base_1.LinkBaseToken {
|
|
|
147
148
|
* @param severity 错误等级
|
|
148
149
|
*/
|
|
149
150
|
const generate = (tokens, msg, p1, severity = true) => {
|
|
150
|
-
const duplication = Array.from({ length
|
|
151
|
-
for (let i =
|
|
151
|
+
const { length } = tokens, duplication = Array.from({ length });
|
|
152
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
152
153
|
const arg = tokens[i];
|
|
153
154
|
s = severities[Number(typeof severity === 'function' ? severity(arg) : severity)];
|
|
154
155
|
if (!s) {
|
|
@@ -30,21 +30,21 @@ class CharinsertToken extends index_2.MultiLineToken {
|
|
|
30
30
|
/** @private */
|
|
31
31
|
lint(start = this.getAbsoluteIndex()) {
|
|
32
32
|
LINT: {
|
|
33
|
-
const { name, childNodes } = this, rule = 'no-ignored', { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, s = lintConfig.getSeverity(rule, name);
|
|
33
|
+
const { name, childNodes, length: l } = this, rule = 'no-ignored', { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, s = lintConfig.getSeverity(rule, name);
|
|
34
34
|
if (!s) {
|
|
35
35
|
return [];
|
|
36
36
|
}
|
|
37
|
-
const rect = new rect_1.BoundingRect(this, start), msg = index_1.default.msg('invalid-space', name),
|
|
38
|
-
let
|
|
39
|
-
for (
|
|
40
|
-
const str =
|
|
37
|
+
const rect = new rect_1.BoundingRect(this, start), msg = index_1.default.msg('invalid-space', name), leading = [], errors = super.lint(start);
|
|
38
|
+
let begin = false;
|
|
39
|
+
for (let i = l - 1; i >= 0; i--) {
|
|
40
|
+
const child = childNodes[i], str = child.toString(), trimmed = str.trim();
|
|
41
41
|
if (trimmed) {
|
|
42
42
|
if (begin) {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
43
|
+
const [, { length }] = /(?:^|\S)(\s*)$/u.exec(str);
|
|
44
|
+
if (length) {
|
|
45
45
|
const e = (0, lint_1.generateForChild)(child, rect, rule, msg, s);
|
|
46
|
-
e.
|
|
47
|
-
e.
|
|
46
|
+
e.startIndex = e.endIndex - length;
|
|
47
|
+
e.startCol = e.endCol - length;
|
|
48
48
|
if (computeEditInfo) {
|
|
49
49
|
e.fix = (0, lint_1.fixByRemove)(e);
|
|
50
50
|
}
|
|
@@ -54,21 +54,21 @@ class CharinsertToken extends index_2.MultiLineToken {
|
|
|
54
54
|
else {
|
|
55
55
|
begin = true;
|
|
56
56
|
}
|
|
57
|
-
if (
|
|
58
|
-
errors
|
|
59
|
-
|
|
57
|
+
if (leading.length > 0) {
|
|
58
|
+
Array.prototype.push.apply(errors, leading);
|
|
59
|
+
leading.length = 0;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
if (begin) {
|
|
63
|
-
const
|
|
64
|
-
if (
|
|
63
|
+
const n = (0, common_1.numLeadingSpaces)(str);
|
|
64
|
+
if (n) {
|
|
65
65
|
const e = (0, lint_1.generateForChild)(child, rect, rule, msg, s);
|
|
66
|
-
e.
|
|
67
|
-
e.
|
|
66
|
+
e.endIndex = e.startIndex + n;
|
|
67
|
+
e.endCol = e.startCol + n;
|
|
68
68
|
if (computeEditInfo) {
|
|
69
69
|
e.fix = (0, lint_1.fixByRemove)(e);
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
leading.push(e);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -83,20 +83,21 @@ class ImagemapToken extends index_2.MultiLineToken {
|
|
|
83
83
|
const errors = super.lint(start, re), rect = new rect_1.BoundingRect(this, start), { childNodes, image } = this, rule = 'invalid-imagemap', { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, s = lintConfig.getSeverity(rule, image ? 'link' : 'image');
|
|
84
84
|
if (s) {
|
|
85
85
|
if (image) {
|
|
86
|
-
|
|
86
|
+
const comments = childNodes.filter(child => {
|
|
87
87
|
const str = child.toString().trim();
|
|
88
88
|
return child.is('noinclude')
|
|
89
89
|
&& str && !str.startsWith('#');
|
|
90
|
-
})
|
|
91
|
-
|
|
90
|
+
});
|
|
91
|
+
for (let i = comments.length - 1; i >= 0; i--) {
|
|
92
|
+
const e = (0, lint_1.generateForChild)(comments[i], rect, rule, 'invalid-imagemap-link', s);
|
|
92
93
|
if (computeEditInfo) {
|
|
93
94
|
e.suggestions = [
|
|
94
95
|
(0, lint_1.fixByRemove)(e, -1),
|
|
95
96
|
(0, lint_1.fixBy)(e, 'comment', '# '),
|
|
96
97
|
];
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
-
}
|
|
99
|
+
errors.push(e);
|
|
100
|
+
}
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
103
|
errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'imagemap-without-image', s));
|
package/dist/src/nested.js
CHANGED
|
@@ -64,30 +64,28 @@ class NestedToken extends index_2.Token {
|
|
|
64
64
|
if (!s) {
|
|
65
65
|
return errors;
|
|
66
66
|
}
|
|
67
|
-
const rect = new rect_1.BoundingRect(this, start), msg = index_1.default.msg('invalid-content', name), regex = typeof this.#regex === 'boolean' ? lintRegex[this.#regex ? 1 : 0] : /^<!--[\s\S]*-->$/u
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
e.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}),
|
|
90
|
-
];
|
|
67
|
+
const rect = new rect_1.BoundingRect(this, start), msg = index_1.default.msg('invalid-content', name), regex = typeof this.#regex === 'boolean' ? lintRegex[this.#regex ? 1 : 0] : /^<!--[\s\S]*-->$/u, ignored = childNodes.filter(child => {
|
|
68
|
+
const { type, name: n } = child;
|
|
69
|
+
if (type === 'ext') {
|
|
70
|
+
return !this.#tags.includes(n);
|
|
71
|
+
}
|
|
72
|
+
else if (childTypes.has(type)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const str = child.toString().trim();
|
|
76
|
+
return str && !regex.test(str);
|
|
77
|
+
}), { length } = ignored, ignoredErrors = Array.from({ length });
|
|
78
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
79
|
+
const child = ignored[i], e = (0, lint_1.generateForChild)(child, rect, rule, msg, s);
|
|
80
|
+
if (computeEditInfo) {
|
|
81
|
+
e.suggestions = [
|
|
82
|
+
(0, lint_1.fixByRemove)(e),
|
|
83
|
+
(0, lint_1.fixByComment)(e, child.toString()),
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
ignoredErrors[i] = e;
|
|
87
|
+
}
|
|
88
|
+
return [...errors, ...ignoredErrors];
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
}
|
package/dist/src/paramLine.d.ts
CHANGED
|
@@ -17,7 +17,12 @@ export declare abstract class ParamLineToken extends Token {
|
|
|
17
17
|
abstract get nextSibling(): this | undefined;
|
|
18
18
|
abstract get previousSibling(): this | undefined;
|
|
19
19
|
get type(): 'param-line';
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* A reasonable parameter name
|
|
22
|
+
*
|
|
23
|
+
* 合理的参数名
|
|
24
|
+
* @since v1.45.0
|
|
25
|
+
*/
|
|
21
26
|
get key(): string | undefined;
|
|
22
27
|
/** @param name 扩展标签名 */
|
|
23
28
|
constructor(name: string, wikitext: string, config: Config, accum: Token[], acceptable?: WikiParserAcceptable);
|
|
@@ -25,6 +30,7 @@ export declare abstract class ParamLineToken extends Token {
|
|
|
25
30
|
* Get a reasonable parameter name
|
|
26
31
|
*
|
|
27
32
|
* 获取合理的参数名
|
|
33
|
+
* @since v1.45.0
|
|
28
34
|
*/
|
|
29
35
|
getKey(): string | undefined;
|
|
30
36
|
}
|
package/dist/src/paramLine.js
CHANGED
|
@@ -69,7 +69,12 @@ let ParamLineToken = (() => {
|
|
|
69
69
|
get type() {
|
|
70
70
|
return 'param-line';
|
|
71
71
|
}
|
|
72
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* A reasonable parameter name
|
|
74
|
+
*
|
|
75
|
+
* 合理的参数名
|
|
76
|
+
* @since v1.45.0
|
|
77
|
+
*/
|
|
73
78
|
get key() {
|
|
74
79
|
LINT: return this.getKey();
|
|
75
80
|
}
|
|
@@ -131,6 +136,7 @@ let ParamLineToken = (() => {
|
|
|
131
136
|
* Get a reasonable parameter name
|
|
132
137
|
*
|
|
133
138
|
* 获取合理的参数名
|
|
139
|
+
* @since v1.45.0
|
|
134
140
|
*/
|
|
135
141
|
getKey() {
|
|
136
142
|
LINT: {
|
package/dist/src/table/td.js
CHANGED
|
@@ -148,8 +148,9 @@ let TdToken = (() => {
|
|
|
148
148
|
/** @private */
|
|
149
149
|
lint(start = this.getAbsoluteIndex(), re) {
|
|
150
150
|
LINT: {
|
|
151
|
-
const errors = super.lint(start, re), rect = new rect_1.BoundingRect(this, start + this.getRelativeIndex(this.length - 1)), rule = 'pipe-like', { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, severities = ['td', 'double'].map(key => lintConfig.getSeverity(rule, key));
|
|
152
|
-
for (
|
|
151
|
+
const errors = super.lint(start, re), rect = new rect_1.BoundingRect(this, start + this.getRelativeIndex(this.length - 1)), rule = 'pipe-like', { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, severities = ['td', 'double'].map(key => lintConfig.getSeverity(rule, key)), { childNodes, length } = this.lastChild, pipes = [];
|
|
152
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
153
|
+
const child = childNodes[i];
|
|
153
154
|
if (child.type === 'text') {
|
|
154
155
|
const { data } = child;
|
|
155
156
|
if (data.includes('|')) {
|
|
@@ -165,12 +166,12 @@ let TdToken = (() => {
|
|
|
165
166
|
e.suggestions = [(0, lint_1.fixByPipe)(e.startIndex, data)];
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
|
-
|
|
169
|
+
pipes.push(e);
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
|
-
return errors;
|
|
174
|
+
return [...errors, ...pipes.reverse()];
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
/**
|
package/dist/src/tag/index.js
CHANGED
|
@@ -62,11 +62,16 @@ class TagToken extends index_1.Token {
|
|
|
62
62
|
return undefined;
|
|
63
63
|
}
|
|
64
64
|
const { childNodes } = parentNode, i = childNodes.indexOf(this), siblings = closing ? childNodes.slice(0, i) : childNodes.slice(i + 1).reverse(), stack = [this], { rev } = debug_1.Shadow;
|
|
65
|
-
let cur = siblings.pop();
|
|
65
|
+
let cur = siblings.pop(), until;
|
|
66
66
|
while (cur) {
|
|
67
67
|
// eslint-disable-next-line no-empty, @typescript-eslint/no-unnecessary-condition
|
|
68
68
|
if (!cur) {
|
|
69
69
|
}
|
|
70
|
+
else if (until) {
|
|
71
|
+
if (cur === until) {
|
|
72
|
+
until = undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
70
75
|
else if (!cur.is(type)
|
|
71
76
|
|| type === 'html' && (cur.name !== name || isFlexible && cur.selfClosing)) {
|
|
72
77
|
//
|
|
@@ -76,6 +81,13 @@ class TagToken extends index_1.Token {
|
|
|
76
81
|
if (type === 'tvar') {
|
|
77
82
|
return undefined;
|
|
78
83
|
}
|
|
84
|
+
else if (cur.#match?.[0] === rev) {
|
|
85
|
+
const [, matched] = cur.#match;
|
|
86
|
+
if (!matched) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
until = matched;
|
|
90
|
+
}
|
|
79
91
|
stack.push(cur);
|
|
80
92
|
}
|
|
81
93
|
else {
|
package/dist/src/transclude.js
CHANGED
|
@@ -278,7 +278,7 @@ let TranscludeToken = (() => {
|
|
|
278
278
|
if (!this.isTemplate()) {
|
|
279
279
|
return errors;
|
|
280
280
|
}
|
|
281
|
-
const { type, childNodes, length } = this, rect = new rect_1.BoundingRect(this, start), { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, invoke = type === 'magic-word';
|
|
281
|
+
const { type, childNodes, length: l } = this, rect = new rect_1.BoundingRect(this, start), { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, invoke = type === 'magic-word';
|
|
282
282
|
let rule = 'no-ignored', s = lintConfig.getSeverity(rule, 'fragment');
|
|
283
283
|
if (invoke && !this.#getTitle().valid) {
|
|
284
284
|
rule = 'invalid-invoke';
|
|
@@ -302,7 +302,7 @@ let TranscludeToken = (() => {
|
|
|
302
302
|
}
|
|
303
303
|
rule = 'invalid-invoke';
|
|
304
304
|
s = lintConfig.getSeverity(rule, 'function');
|
|
305
|
-
if (s && invoke &&
|
|
305
|
+
if (s && invoke && l === 2) {
|
|
306
306
|
errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'missing-function', s));
|
|
307
307
|
return errors;
|
|
308
308
|
}
|
|
@@ -312,8 +312,8 @@ let TranscludeToken = (() => {
|
|
|
312
312
|
const duplicatedArgs = this.getDuplicatedArgs()
|
|
313
313
|
.filter(([, parameter]) => !parameter[0].querySelector('ext'));
|
|
314
314
|
for (const [, args] of duplicatedArgs) {
|
|
315
|
-
const duplication = Array.from({ length
|
|
316
|
-
for (let i =
|
|
315
|
+
const { length } = args, duplication = Array.from({ length });
|
|
316
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
317
317
|
const arg = args[i], e = (0, lint_1.generateForChild)(arg, rect, rule, 'duplicate-parameter', s);
|
|
318
318
|
if (computeEditInfo) {
|
|
319
319
|
e.suggestions = [(0, lint_1.fixByRemove)(e, -1)];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.46.1",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
"ls": "npm i --package-lock-only && npm ls --package-lock-only --all --include=peer --omit=dev",
|
|
43
43
|
"prepublishOnly": "npm run build:core",
|
|
44
44
|
"build:core": "bash build.sh",
|
|
45
|
-
"build:define": "bash sed.sh -i \"s/pkg = \\$PKG/pkg = $(npm pkg get name)/; s/version = \\$VERSION/version = $(npm pkg get version)/\" dist/bin/config.js",
|
|
45
|
+
"build:define": "bash sed.sh -i \"s/pkg = \\$PKG/pkg = '$(npm pkg get name)'/; s/version = \\$VERSION/version = '$(npm pkg get version)'/\" dist/bin/config.js",
|
|
46
46
|
"build": "npm run build:core",
|
|
47
47
|
"diff": "bash diff.sh",
|
|
48
48
|
"diff:stat": "f() { git diff --stat -w --color=always $1 $2 -- . | grep '\\.ts'; }; f",
|
|
49
49
|
"lint:ts": "tsc --noEmit && eslint --cache .",
|
|
50
|
-
"lint:json": "v8r -s config/.schema.json config/*.json && v8r -s data/.schema.json data/*.json &&
|
|
50
|
+
"lint:json": "v8r -s config/.schema.json config/*.json && v8r -s data/.schema.json data/*.json && testUtil dist/test/json.js",
|
|
51
51
|
"lint:md": "markdownlint-cli2 '*.md'",
|
|
52
52
|
"lint": "npm run lint:ts && npm run lint:json && npm run lint:md",
|
|
53
53
|
"prof": "node dist/test/prof.js",
|
|
54
54
|
"coverage": "tsc --declaration false --target es2024 && npm run build:define && c8 npm run test:ci && node dist/script/coverage.js && open coverage/index.html",
|
|
55
|
-
"test:unit": "
|
|
56
|
-
"test:parser": "LC_ALL=en.UTF-8
|
|
57
|
-
"test:perf": "
|
|
55
|
+
"test:unit": "testUtil dist/test/test.js",
|
|
56
|
+
"test:parser": "LC_ALL=en.UTF-8 testUtil dist/test/parserTests.js",
|
|
57
|
+
"test:perf": "testUtil --test-reporter=spec dist/test/perf.js",
|
|
58
58
|
"test": "npm run test:unit && npm run test:parser",
|
|
59
59
|
"test:parseronly": "LSP=0 npm run test:parser",
|
|
60
60
|
"test:ci": "LSP=0 npm test",
|
|
@@ -98,23 +98,23 @@
|
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
|
-
"@bhsd/cm-util": "^2.
|
|
102
|
-
"@bhsd/common": "^
|
|
101
|
+
"@bhsd/cm-util": "^2.3.0",
|
|
102
|
+
"@bhsd/common": "^4.0.0",
|
|
103
103
|
"@bhsd/stylelint-util": "^1.1.0",
|
|
104
|
+
"culori": "^4.0.2",
|
|
104
105
|
"entities": "^8.0.0",
|
|
105
106
|
"vscode-languageserver-types": "^3.18.0"
|
|
106
107
|
},
|
|
107
108
|
"devDependencies": {
|
|
108
109
|
"@bhsd/code-standard": "^3.1.0",
|
|
109
|
-
"@bhsd/nodejs": "^1.1
|
|
110
|
-
"@bhsd/test-util": "^
|
|
110
|
+
"@bhsd/nodejs": "^1.2.1",
|
|
111
|
+
"@bhsd/test-util": "^3.1.0",
|
|
111
112
|
"c8": "^11.0.0",
|
|
112
113
|
"diff2html-cli": "^5.2.15",
|
|
113
114
|
"esbuild": "^0.28.1",
|
|
114
|
-
"eslint": "^10.
|
|
115
|
+
"eslint": "^10.7.0",
|
|
115
116
|
"markdownlint-cli2": "^0.23.0",
|
|
116
117
|
"mathoid-texvcjs": "^0.6.0",
|
|
117
|
-
"mocha": "^11.7.6",
|
|
118
118
|
"stylelint": "^17.14.0",
|
|
119
119
|
"typescript": "^6.0.3",
|
|
120
120
|
"v8r": "^6.1.0",
|