wikilint 2.41.0 → 2.43.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 +19 -0
- package/dist/bin/config.js +1 -1
- package/dist/lib/document.js +5 -5
- package/dist/lib/element.d.ts +0 -7
- package/dist/lib/element.js +0 -18
- package/dist/lib/lsp.d.ts +2 -0
- package/dist/lib/lsp.js +8 -20
- package/dist/lib/node.d.ts +2 -0
- package/dist/lib/node.js +0 -7
- package/dist/lib/text.js +1 -2
- package/dist/map.d.ts +65 -0
- package/dist/map.js +2 -0
- package/dist/mixin/attributesParent.d.ts +1 -1
- package/dist/mixin/elementLike.d.ts +12 -0
- package/dist/mixin/elementLike.js +32 -19
- package/dist/src/attribute.d.ts +1 -1
- package/dist/src/attribute.js +6 -6
- package/dist/src/attributes.d.ts +1 -1
- package/dist/src/attributes.js +3 -9
- package/dist/src/index.js +3 -4
- package/dist/src/magicLink.js +1 -1
- package/dist/src/nowiki/doubleUnderscore.js +1 -1
- package/dist/src/nowiki/quote.js +1 -3
- package/dist/src/table/td.d.ts +1 -1
- package/dist/src/table/td.js +1 -1
- package/dist/src/tagPair/ext.js +4 -1
- package/dist/src/transclude.js +4 -2
- package/dist/util/debug.js +5 -7
- package/package.json +40 -17
package/README.md
CHANGED
|
@@ -16,6 +16,25 @@ You can also directly lint Wikitext articles in the command line using this pack
|
|
|
16
16
|
npx wikilint --config zhwiki --include --lang zh-hans *.wiki
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm i wikilint
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Optional dependencies
|
|
26
|
+
|
|
27
|
+
You can install any of the following optional packages to enable advanced features:
|
|
28
|
+
|
|
29
|
+
| Package | Purpose |
|
|
30
|
+
| :-: | --- |
|
|
31
|
+
| `mathoid-texvcjs` | Linting `<math>` and `<chem>` extension tags |
|
|
32
|
+
| `vscode-css-languageservice` | Linting `style` attributes |
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm i mathoid-texvcjs vscode-css-languageservice
|
|
36
|
+
```
|
|
37
|
+
|
|
19
38
|
## CLI Options
|
|
20
39
|
|
|
21
40
|
| Option | Argument | Description | Default |
|
package/dist/bin/config.js
CHANGED
|
@@ -40,7 +40,7 @@ const filterGadget = (id) => {
|
|
|
40
40
|
const n = Number(id);
|
|
41
41
|
return n < 2300 || n > 2303; // Gadget, Gadget talk, Gadget definition, Gadget definition talk
|
|
42
42
|
};
|
|
43
|
-
const pkg = "wikilint", version = "2.
|
|
43
|
+
const pkg = "wikilint", version = "2.43.0";
|
|
44
44
|
/**
|
|
45
45
|
* Get the parser configuration for a Wikimedia Foundation project.
|
|
46
46
|
* @param site site nickname
|
package/dist/lib/document.js
CHANGED
|
@@ -7,19 +7,19 @@ exports.EmbeddedCSSDocument = exports.EmbeddedJSONDocument = exports.loadStyleli
|
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const common_1 = require("@bhsd/common");
|
|
9
9
|
const constants_1 = require("../util/constants");
|
|
10
|
-
let
|
|
10
|
+
let texvcjs;
|
|
11
11
|
const loadTexvcjs = () => {
|
|
12
12
|
NPM: {
|
|
13
|
-
if (
|
|
13
|
+
if (texvcjs === undefined) {
|
|
14
14
|
try {
|
|
15
|
-
|
|
15
|
+
texvcjs = require('mathoid-texvcjs');
|
|
16
16
|
}
|
|
17
17
|
catch /* c8 ignore start */ {
|
|
18
|
-
|
|
18
|
+
texvcjs = null;
|
|
19
19
|
}
|
|
20
20
|
/* c8 ignore stop */
|
|
21
21
|
}
|
|
22
|
-
return
|
|
22
|
+
return texvcjs;
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
exports.loadTexvcjs = loadTexvcjs;
|
package/dist/lib/element.d.ts
CHANGED
|
@@ -33,13 +33,6 @@ export declare abstract class AstElement extends AstNode {
|
|
|
33
33
|
* @param i position to be inserted at / 插入位置
|
|
34
34
|
*/
|
|
35
35
|
insertAt<T extends AstNodes>(node: T, i?: number): T;
|
|
36
|
-
/**
|
|
37
|
-
* Get the closest ancestor node that matches the selector
|
|
38
|
-
*
|
|
39
|
-
* 最近的符合选择器的祖先节点
|
|
40
|
-
* @param selector selector / 选择器
|
|
41
|
-
*/
|
|
42
|
-
closest<T = Token>(selector: string): T | undefined;
|
|
43
36
|
/**
|
|
44
37
|
* Insert a batch of child nodes at the end
|
|
45
38
|
*
|
package/dist/lib/element.js
CHANGED
|
@@ -37,7 +37,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
37
37
|
exports.AstElement = void 0;
|
|
38
38
|
const string_1 = require("../util/string");
|
|
39
39
|
const debug_1 = require("../util/debug");
|
|
40
|
-
const selector_1 = require("../util/selector");
|
|
41
40
|
const node_1 = require("./node");
|
|
42
41
|
const elementLike_1 = require("../mixin/elementLike");
|
|
43
42
|
/**
|
|
@@ -88,23 +87,6 @@ let AstElement = (() => {
|
|
|
88
87
|
(0, debug_1.setChildNodes)(this, i, 0, [node]);
|
|
89
88
|
return node;
|
|
90
89
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Get the closest ancestor node that matches the selector
|
|
93
|
-
*
|
|
94
|
-
* 最近的符合选择器的祖先节点
|
|
95
|
-
* @param selector selector / 选择器
|
|
96
|
-
*/
|
|
97
|
-
closest(selector) {
|
|
98
|
-
const condition = (0, selector_1.getCondition)(selector, this);
|
|
99
|
-
let { parentNode } = this;
|
|
100
|
-
while (parentNode) {
|
|
101
|
-
if (condition(parentNode)) {
|
|
102
|
-
return parentNode;
|
|
103
|
-
}
|
|
104
|
-
({ parentNode } = parentNode);
|
|
105
|
-
}
|
|
106
|
-
return undefined;
|
|
107
|
-
}
|
|
108
90
|
/** @private */
|
|
109
91
|
isInside(type) {
|
|
110
92
|
return this.closest(`${type},ext`)?.type === type;
|
package/dist/lib/lsp.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Token } from '../src/index';
|
|
|
3
3
|
import type { Range, Position, ColorInformation, ColorPresentation, FoldingRange, DocumentLink, Location, 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
|
+
import type { TokenTypeMap, SelectedTokenTypes } from '../map';
|
|
6
7
|
export interface QuickFixData extends TextEdit {
|
|
7
8
|
title: string;
|
|
8
9
|
fix: boolean;
|
|
@@ -128,6 +129,7 @@ export declare class LanguageService implements LanguageServiceBase {
|
|
|
128
129
|
* @since v1.16.3
|
|
129
130
|
*/
|
|
130
131
|
provideInlayHints(text: string): Promise<InlayHint[]>;
|
|
132
|
+
querySelectorAll<T = Token>(selector: string): T[];
|
|
131
133
|
/**
|
|
132
134
|
* Provide refactoring actions
|
|
133
135
|
*
|
package/dist/lib/lsp.js
CHANGED
|
@@ -157,15 +157,6 @@ const getRefName = (token) => getRefAttr(token, refTags, nameAttrs);
|
|
|
157
157
|
* @param token `group` attribute token
|
|
158
158
|
*/
|
|
159
159
|
const getRefGroup = (token) => getRefAttr(token, referencesTags, groupAttrs);
|
|
160
|
-
/**
|
|
161
|
-
* Get the attribute of a `<ref>` tag.
|
|
162
|
-
* @param token extension token
|
|
163
|
-
* @param target attribute name
|
|
164
|
-
*/
|
|
165
|
-
const getRefTagAttr = (token, target) => {
|
|
166
|
-
const attr = token?.getAttr(target);
|
|
167
|
-
return attr !== true && attr || false;
|
|
168
|
-
};
|
|
169
160
|
/**
|
|
170
161
|
* Get the effective name of a token.
|
|
171
162
|
* @param token
|
|
@@ -673,8 +664,7 @@ class LanguageService {
|
|
|
673
664
|
}),
|
|
674
665
|
...match.startsWith('#')
|
|
675
666
|
? []
|
|
676
|
-
: getCompletion(root.querySelectorAll('template').filter(token => token !== cur)
|
|
677
|
-
.map(token => {
|
|
667
|
+
: getCompletion(root.querySelectorAll('template').filter(token => token !== cur).map(token => {
|
|
678
668
|
const { name } = token;
|
|
679
669
|
if (colon) {
|
|
680
670
|
return name;
|
|
@@ -1164,8 +1154,7 @@ class LanguageService {
|
|
|
1164
1154
|
* @param position position / 位置
|
|
1165
1155
|
*/
|
|
1166
1156
|
async provideReferences(text, position) {
|
|
1167
|
-
const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0
|
|
1168
|
-
&& (element.is('ext-attr-dirty') || element.is('html-attr-dirty'))
|
|
1157
|
+
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'))
|
|
1169
1158
|
? element.parentNode.parentNode
|
|
1170
1159
|
: element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
|
|
1171
1160
|
if (!refName && !refGroup && !referenceTypes.has(type)) {
|
|
@@ -1192,13 +1181,13 @@ class LanguageService {
|
|
|
1192
1181
|
}
|
|
1193
1182
|
const ext = node.is('ext') && node.name === 'ref'
|
|
1194
1183
|
? node
|
|
1195
|
-
: node.closest('ext#ref'), refName =
|
|
1184
|
+
: node.closest('ext#ref'), refName = ext?.getAttr('name');
|
|
1196
1185
|
if (!refName) {
|
|
1197
1186
|
return undefined;
|
|
1198
1187
|
}
|
|
1199
|
-
const refGroup =
|
|
1200
|
-
&&
|
|
1201
|
-
&&
|
|
1188
|
+
const refGroup = ext.getAttr('group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
|
|
1189
|
+
&& token.getAttr('name') === refName
|
|
1190
|
+
&& token.getAttr('group') === refGroup).reverse().map(({ lastChild }) => ({
|
|
1202
1191
|
range: createNodeRange(lastChild),
|
|
1203
1192
|
}));
|
|
1204
1193
|
return refs.length === 0 ? undefined : refs;
|
|
@@ -1235,7 +1224,7 @@ class LanguageService {
|
|
|
1235
1224
|
if (!node) {
|
|
1236
1225
|
return undefined;
|
|
1237
1226
|
}
|
|
1238
|
-
const { type } = node, refName = getRefName(node), refNameGroup = refName &&
|
|
1227
|
+
const { type } = node, refName = getRefName(node), refNameGroup = refName && node.parentNode.parentNode.getAttr('group'), refGroup = getRefGroup(node), name = getName(node), refs = root.querySelectorAll(type).filter(token => {
|
|
1239
1228
|
const { type: t } = token.parentNode;
|
|
1240
1229
|
if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
|
|
1241
1230
|
return false;
|
|
@@ -1243,7 +1232,7 @@ class LanguageService {
|
|
|
1243
1232
|
return type === 'attr-value'
|
|
1244
1233
|
? getRefGroup(token) === refGroup
|
|
1245
1234
|
|| getRefName(token) === refName
|
|
1246
|
-
&&
|
|
1235
|
+
&& token.parentNode.parentNode.getAttr('group') === refNameGroup
|
|
1247
1236
|
: getName(token) === name;
|
|
1248
1237
|
});
|
|
1249
1238
|
return refs.length === 0
|
|
@@ -1443,7 +1432,6 @@ class LanguageService {
|
|
|
1443
1432
|
}
|
|
1444
1433
|
return hints;
|
|
1445
1434
|
}
|
|
1446
|
-
/** @private */
|
|
1447
1435
|
querySelectorAll(selector) {
|
|
1448
1436
|
return this.#done.querySelectorAll(selector);
|
|
1449
1437
|
}
|
package/dist/lib/node.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AstNode as AstNodeBase, TokenTypes, LintError } from '../base';
|
|
2
2
|
import type { NodeLike } from '../mixin/nodeLike';
|
|
3
3
|
import type { AstText, Token } from '../internal';
|
|
4
|
+
import type { TokenTypeMap, SelectedTokenTypes } from '../map';
|
|
4
5
|
export type AstNodes = AstText | Token;
|
|
5
6
|
export interface Dimension {
|
|
6
7
|
readonly height: number;
|
|
@@ -93,6 +94,7 @@ export declare abstract class AstNode implements AstNodeBase {
|
|
|
93
94
|
* @param type token type / 节点类型
|
|
94
95
|
* @since v1.10.0
|
|
95
96
|
*/
|
|
97
|
+
is<K extends SelectedTokenTypes>(type: K): this is TokenTypeMap[K];
|
|
96
98
|
is<T extends Token>(type: TokenTypes): this is T;
|
|
97
99
|
/**
|
|
98
100
|
* Get the text and the start/end positions of all lines
|
package/dist/lib/node.js
CHANGED
|
@@ -238,13 +238,6 @@ let AstNode = (() => {
|
|
|
238
238
|
...this.getRootNode().posFromIndex(this.getAbsoluteIndex()),
|
|
239
239
|
};
|
|
240
240
|
}
|
|
241
|
-
/**
|
|
242
|
-
* Whether to be of a certain type
|
|
243
|
-
*
|
|
244
|
-
* 是否是某种类型的节点
|
|
245
|
-
* @param type token type / 节点类型
|
|
246
|
-
* @since v1.10.0
|
|
247
|
-
*/
|
|
248
241
|
is(type) {
|
|
249
242
|
return this.type === type;
|
|
250
243
|
}
|
package/dist/lib/text.js
CHANGED
|
@@ -144,8 +144,7 @@ class AstText extends node_1.AstNode {
|
|
|
144
144
|
// Rule & Severity
|
|
145
145
|
let startIndex = start + index, endIndex = startIndex + length, rule, severity, endLine, endCol;
|
|
146
146
|
const nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], leftBracket = lbrace || lbrack, lConverter = error === '{' && previousChar === '-' && variants.length > 0, rConverter = error === '}' && nextChar === '-' && variants.length > 0, brokenExtLink = lbrack && nextType === 'free-ext-link' && !data.slice(index + 1).trim()
|
|
147
|
-
|| rbrack && previousType === 'free-ext-link'
|
|
148
|
-
&& !data.slice(0, index).includes(']');
|
|
147
|
+
|| rbrack && previousType === 'free-ext-link' && index === 0;
|
|
149
148
|
if (magicLink) {
|
|
150
149
|
rule = 'lonely-http';
|
|
151
150
|
error = error.toUpperCase();
|
package/dist/map.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { RedirectToken, RedirectTargetToken, OnlyincludeToken, IncludeToken, CommentToken, ExtToken, AttributesToken, AttributeToken, AtomToken, ArgToken, TranscludeToken, SyntaxToken, ParameterToken, HeadingToken, HtmlToken, TableToken, TrToken, TdToken, DoubleUnderscoreToken, HrToken, LinkToken, CategoryToken, FileToken, ImageParameterToken, QuoteToken, ExtLinkToken, MagicLinkToken, ListToken, DdToken, ConverterToken, ConverterFlagsToken, ConverterRuleToken, TranslateToken, TvarToken, HiddenToken, GalleryImageToken, ParamLineToken, ImagemapLinkToken } from './internal';
|
|
2
|
+
export interface TokenTypeMap {
|
|
3
|
+
redirect: RedirectToken;
|
|
4
|
+
'redirect-syntax': SyntaxToken;
|
|
5
|
+
'redirect-target': RedirectTargetToken;
|
|
6
|
+
translate: TranslateToken;
|
|
7
|
+
'translate-attr': SyntaxToken;
|
|
8
|
+
tvar: TvarToken;
|
|
9
|
+
'tvar-name': SyntaxToken;
|
|
10
|
+
onlyinclude: OnlyincludeToken;
|
|
11
|
+
include: IncludeToken;
|
|
12
|
+
comment: CommentToken;
|
|
13
|
+
ext: ExtToken;
|
|
14
|
+
'ext-attrs': AttributesToken;
|
|
15
|
+
'ext-attr-dirty': AtomToken;
|
|
16
|
+
'ext-attr': AttributeToken;
|
|
17
|
+
'attr-key': AtomToken;
|
|
18
|
+
arg: ArgToken;
|
|
19
|
+
'arg-name': AtomToken;
|
|
20
|
+
hidden: HiddenToken;
|
|
21
|
+
'magic-word': TranscludeToken;
|
|
22
|
+
'magic-word-name': SyntaxToken;
|
|
23
|
+
'invoke-function': AtomToken;
|
|
24
|
+
'invoke-module': AtomToken;
|
|
25
|
+
template: TranscludeToken;
|
|
26
|
+
'template-name': AtomToken;
|
|
27
|
+
parameter: ParameterToken;
|
|
28
|
+
heading: HeadingToken;
|
|
29
|
+
'heading-trail': SyntaxToken;
|
|
30
|
+
html: HtmlToken;
|
|
31
|
+
'html-attrs': AttributesToken;
|
|
32
|
+
'html-attr-dirty': AtomToken;
|
|
33
|
+
'html-attr': AttributeToken;
|
|
34
|
+
table: TableToken;
|
|
35
|
+
tr: TrToken;
|
|
36
|
+
td: TdToken;
|
|
37
|
+
'table-syntax': SyntaxToken;
|
|
38
|
+
'table-attrs': AttributesToken;
|
|
39
|
+
'table-attr-dirty': AtomToken;
|
|
40
|
+
'table-attr': AttributeToken;
|
|
41
|
+
hr: HrToken;
|
|
42
|
+
'double-underscore': DoubleUnderscoreToken;
|
|
43
|
+
link: LinkToken;
|
|
44
|
+
'link-target': AtomToken;
|
|
45
|
+
category: CategoryToken;
|
|
46
|
+
file: FileToken;
|
|
47
|
+
'gallery-image': GalleryImageToken;
|
|
48
|
+
'imagemap-image': GalleryImageToken;
|
|
49
|
+
'image-parameter': ImageParameterToken;
|
|
50
|
+
quote: QuoteToken;
|
|
51
|
+
'ext-link': ExtLinkToken;
|
|
52
|
+
'ext-link-url': MagicLinkToken;
|
|
53
|
+
'free-ext-link': MagicLinkToken;
|
|
54
|
+
'magic-link': MagicLinkToken;
|
|
55
|
+
list: ListToken;
|
|
56
|
+
dd: DdToken;
|
|
57
|
+
converter: ConverterToken;
|
|
58
|
+
'converter-flags': ConverterFlagsToken;
|
|
59
|
+
'converter-flag': AtomToken;
|
|
60
|
+
'converter-rule': ConverterRuleToken;
|
|
61
|
+
'converter-rule-variant': AtomToken;
|
|
62
|
+
'param-line': ParamLineToken;
|
|
63
|
+
'imagemap-link': ImagemapLinkToken;
|
|
64
|
+
}
|
|
65
|
+
export type SelectedTokenTypes = keyof TokenTypeMap;
|
package/dist/map.js
ADDED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import type { AstNodes, Token } from '../internal';
|
|
2
|
+
import type { TokenTypeMap, SelectedTokenTypes } from '../map';
|
|
2
3
|
declare type ElementConstructor = abstract new (...args: any[]) => {
|
|
4
|
+
readonly parentNode: Token | undefined;
|
|
3
5
|
readonly childNodes: readonly AstNodes[];
|
|
4
6
|
};
|
|
5
7
|
export interface ElementLike {
|
|
8
|
+
/**
|
|
9
|
+
* Get the closest ancestor node that matches the selector
|
|
10
|
+
*
|
|
11
|
+
* 最近的符合选择器的祖先节点
|
|
12
|
+
* @param selector selector / 选择器
|
|
13
|
+
*/
|
|
14
|
+
closest<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K] | undefined;
|
|
15
|
+
closest<T = Token>(selector: string): T | undefined;
|
|
6
16
|
/**
|
|
7
17
|
* Get the first descendant that matches the selector
|
|
8
18
|
*
|
|
9
19
|
* 符合选择器的第一个后代节点
|
|
10
20
|
* @param selector selector / 选择器
|
|
11
21
|
*/
|
|
22
|
+
querySelector<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K] | undefined;
|
|
12
23
|
querySelector<T = Token>(selector: string): T | undefined;
|
|
13
24
|
/**
|
|
14
25
|
* Get all descendants that match the selector
|
|
@@ -16,6 +27,7 @@ export interface ElementLike {
|
|
|
16
27
|
* 符合选择器的所有后代节点
|
|
17
28
|
* @param selector selector / 选择器
|
|
18
29
|
*/
|
|
30
|
+
querySelectorAll<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K][];
|
|
19
31
|
querySelectorAll<T = Token>(selector: string): T[];
|
|
20
32
|
/**
|
|
21
33
|
* Escape `=` and `|`
|
|
@@ -5,12 +5,23 @@ const debug_1 = require("../util/debug");
|
|
|
5
5
|
const selector_1 = require("../util/selector");
|
|
6
6
|
/** @ignore */
|
|
7
7
|
const elementLike = (constructor) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
class ElementLike extends constructor {
|
|
9
|
+
#getCondition(selector) {
|
|
10
|
+
return (0, selector_1.getCondition)(selector, this);
|
|
11
|
+
}
|
|
12
|
+
closest(selector) {
|
|
13
|
+
const condition = this.#getCondition(selector);
|
|
14
|
+
let { parentNode } = this;
|
|
15
|
+
while (parentNode) {
|
|
16
|
+
if (condition(parentNode)) {
|
|
17
|
+
return parentNode;
|
|
18
|
+
}
|
|
19
|
+
({ parentNode } = parentNode);
|
|
12
20
|
}
|
|
13
|
-
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
getElementBy(condition) {
|
|
24
|
+
LINT: {
|
|
14
25
|
const stack = [...this.childNodes].reverse();
|
|
15
26
|
while (stack.length > 0) {
|
|
16
27
|
const child = stack.pop(), { type, childNodes } = child;
|
|
@@ -26,10 +37,12 @@ const elementLike = (constructor) => {
|
|
|
26
37
|
}
|
|
27
38
|
return undefined;
|
|
28
39
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
}
|
|
41
|
+
querySelector(selector) {
|
|
42
|
+
LINT: return this.getElementBy(this.#getCondition(selector));
|
|
43
|
+
}
|
|
44
|
+
getElementsBy(condition) {
|
|
45
|
+
LINT: {
|
|
33
46
|
const stack = [...this.childNodes].reverse(), descendants = [];
|
|
34
47
|
while (stack.length > 0) {
|
|
35
48
|
const child = stack.pop(), { type, childNodes } = child;
|
|
@@ -45,19 +58,19 @@ const elementLike = (constructor) => {
|
|
|
45
58
|
}
|
|
46
59
|
return descendants;
|
|
47
60
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
}
|
|
62
|
+
querySelectorAll(selector) {
|
|
63
|
+
LINT: return this.getElementsBy(this.#getCondition(selector));
|
|
64
|
+
}
|
|
65
|
+
escape() {
|
|
66
|
+
LSP: {
|
|
67
|
+
for (const child of this.childNodes) {
|
|
68
|
+
child.escape();
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
|
-
(0, debug_1.mixin)(ElementLike, constructor);
|
|
60
|
-
return ElementLike;
|
|
61
72
|
}
|
|
73
|
+
(0, debug_1.mixin)(ElementLike, constructor);
|
|
74
|
+
return ElementLike;
|
|
62
75
|
};
|
|
63
76
|
exports.elementLike = elementLike;
|
package/dist/src/attribute.d.ts
CHANGED
package/dist/src/attribute.js
CHANGED
|
@@ -151,14 +151,14 @@ class AttributeToken extends index_2.Token {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
else if (name === 'style' &&
|
|
154
|
+
else if (name === 'style' && insecureStyle.test(value)) {
|
|
155
155
|
LINT: {
|
|
156
156
|
rule = 'insecure-style';
|
|
157
157
|
const s = lintConfig.getSeverity(rule);
|
|
158
158
|
return s && (0, lint_1.generateForChild)(lastChild, rect, rule, 'insecure-style', s);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
else if (name === 'tabindex' &&
|
|
161
|
+
else if (name === 'tabindex' && value !== '0') {
|
|
162
162
|
LINT: {
|
|
163
163
|
const s = lintConfig.getSeverity(rule, 'tabindex');
|
|
164
164
|
if (s) {
|
|
@@ -173,18 +173,18 @@ class AttributeToken extends index_2.Token {
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
-
else if (
|
|
176
|
+
else if ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
|
|
177
177
|
|| simple
|
|
178
178
|
&& (name === 'href' || type === 'ext-attr' && tag === 'img' && name === 'src')
|
|
179
179
|
&& !new RegExp(String.raw `^(?:${this.getAttribute('config').protocol}|//)\S+$`, 'iu')
|
|
180
|
-
.test(value))
|
|
180
|
+
.test(value)) {
|
|
181
181
|
LINT: {
|
|
182
182
|
const s = lintConfig.getSeverity(rule, 'value');
|
|
183
183
|
return s && (0, lint_1.generateForChild)(lastChild, rect, rule, 'illegal-attribute-value', s);
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
else if (simple && type !== 'ext-attr') {
|
|
187
|
-
const data = (0, lint_1.provideValues)(tag, name), v =
|
|
187
|
+
const data = (0, lint_1.provideValues)(tag, name), v = value.toLowerCase();
|
|
188
188
|
if (data.length > 0 && data.every(n => n !== v)) {
|
|
189
189
|
LINT: {
|
|
190
190
|
const s = lintConfig.getSeverity(rule, 'value');
|
|
@@ -249,7 +249,7 @@ class AttributeToken extends index_2.Token {
|
|
|
249
249
|
* 获取属性值
|
|
250
250
|
*/
|
|
251
251
|
getValue() {
|
|
252
|
-
return this.#equal ? this.lastChild.text().
|
|
252
|
+
return this.#equal ? this.lastChild.text().replace(/[\t\r\n ]+/gu, ' ').trim() : '';
|
|
253
253
|
}
|
|
254
254
|
/** @private */
|
|
255
255
|
escape() {
|
package/dist/src/attributes.d.ts
CHANGED
package/dist/src/attributes.js
CHANGED
|
@@ -185,11 +185,8 @@ class AttributesToken extends index_2.Token {
|
|
|
185
185
|
const severity = lintConfig.getSeverity(rules[1], tag);
|
|
186
186
|
if (severity) {
|
|
187
187
|
for (const key of required.get(tag)) {
|
|
188
|
-
const keys = typeof key === 'string' ? [key] : key
|
|
189
|
-
|
|
190
|
-
return value === true || !value;
|
|
191
|
-
});
|
|
192
|
-
if (missing) {
|
|
188
|
+
const keys = typeof key === 'string' ? [key] : key;
|
|
189
|
+
if (!keys.some(k => this.getAttr(k))) {
|
|
193
190
|
errors.push((0, lint_1.generateForSelf)(this, rect, rules[1], index_1.default.msg('required-attribute', keys.join('/')), severity));
|
|
194
191
|
}
|
|
195
192
|
}
|
|
@@ -198,10 +195,7 @@ class AttributesToken extends index_2.Token {
|
|
|
198
195
|
const severity = lintConfig.getSeverity(rules[2], 'attribute');
|
|
199
196
|
if (severity && duplicated.size > 0) {
|
|
200
197
|
for (const key of duplicated) {
|
|
201
|
-
const pairs = attrs.get(key).map(attr =>
|
|
202
|
-
const value = attr.getValue();
|
|
203
|
-
return [attr, value === true ? '' : value];
|
|
204
|
-
});
|
|
198
|
+
const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]);
|
|
205
199
|
Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
|
|
206
200
|
const e = (0, lint_1.generateForChild)(attr, rect, rules[2], index_1.default.msg('duplicate-attribute', key), severity);
|
|
207
201
|
if (computeEditInfo || fix) {
|
package/dist/src/index.js
CHANGED
|
@@ -372,9 +372,8 @@ class Token extends element_1.AstElement {
|
|
|
372
372
|
}
|
|
373
373
|
/** @private */
|
|
374
374
|
inTableAttrs() {
|
|
375
|
-
return this.isInside('table-attrs')
|
|
376
|
-
? 2
|
|
377
|
-
: 1);
|
|
375
|
+
return this.isInside('table-attrs')
|
|
376
|
+
&& (this.closest('table-attrs,arg,parameter')?.is('table-attrs') ? 2 : 1);
|
|
378
377
|
}
|
|
379
378
|
/** @private */
|
|
380
379
|
inHtmlAttrs() {
|
|
@@ -395,7 +394,7 @@ class Token extends element_1.AstElement {
|
|
|
395
394
|
}
|
|
396
395
|
else {
|
|
397
396
|
const value = cat.getValue();
|
|
398
|
-
if (value
|
|
397
|
+
if (value) {
|
|
399
398
|
key = `#${value}`;
|
|
400
399
|
}
|
|
401
400
|
}
|
package/dist/src/magicLink.js
CHANGED
|
@@ -142,7 +142,7 @@ class MagicLinkToken extends index_2.Token {
|
|
|
142
142
|
.getUrl(articlePath)
|
|
143
143
|
: new URL(link.startsWith('RFC')
|
|
144
144
|
? `https://datatracker.ietf.org/doc/html/rfc${link.slice(4)}`
|
|
145
|
-
: `https://
|
|
145
|
+
: `https://www.ncbi.nlm.nih.gov/pubmed/${link.slice(5)}?dopt=Abstract`);
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -44,7 +44,7 @@ const base_1 = require("./base");
|
|
|
44
44
|
* 状态开关
|
|
45
45
|
*/
|
|
46
46
|
let DoubleUnderscoreToken = (() => {
|
|
47
|
-
let _classDecorators = [(0, hidden_1.hiddenToken)(), (0, padded_1.padded)('__')];
|
|
47
|
+
let _classDecorators = [(0, hidden_1.hiddenToken)(true, false), (0, padded_1.padded)('__')];
|
|
48
48
|
let _classDescriptor;
|
|
49
49
|
let _classExtraInitializers = [];
|
|
50
50
|
let _classThis;
|
package/dist/src/nowiki/quote.js
CHANGED
|
@@ -46,9 +46,7 @@ class QuoteToken extends base_1.NowikiBaseToken {
|
|
|
46
46
|
/** @private */
|
|
47
47
|
text() {
|
|
48
48
|
const { parentNode, innerText } = this;
|
|
49
|
-
return parentNode?.is('image-parameter') && parentNode.name !== 'caption'
|
|
50
|
-
? ''
|
|
51
|
-
: innerText;
|
|
49
|
+
return parentNode?.is('image-parameter') && parentNode.name !== 'caption' ? '' : innerText;
|
|
52
50
|
}
|
|
53
51
|
/** @private */
|
|
54
52
|
lint(start = this.getAbsoluteIndex()) {
|
package/dist/src/table/td.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface TdSpanAttrs {
|
|
|
7
7
|
rowspan?: number;
|
|
8
8
|
colspan?: number;
|
|
9
9
|
}
|
|
10
|
-
declare type TdAttrGetter<T extends string> = T extends keyof TdSpanAttrs ? number : string |
|
|
10
|
+
declare type TdAttrGetter<T extends string> = T extends keyof TdSpanAttrs ? number : string | undefined;
|
|
11
11
|
/**
|
|
12
12
|
* `<td>`, `<th>` or `<caption>`
|
|
13
13
|
*
|
package/dist/src/table/td.js
CHANGED
|
@@ -184,7 +184,7 @@ let TdToken = (() => {
|
|
|
184
184
|
getAttr(key) {
|
|
185
185
|
LINT: {
|
|
186
186
|
const value = super.getAttr(key);
|
|
187
|
-
return (key === 'rowspan' || key === 'colspan' ? parseInt(value) || 1 : value);
|
|
187
|
+
return (key === 'rowspan' || key === 'colspan' ? parseInt(value || '') || 1 : value);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
/** @private */
|
package/dist/src/tagPair/ext.js
CHANGED
|
@@ -94,6 +94,7 @@ let ExtToken = (() => {
|
|
|
94
94
|
innerToken = new PreToken(inner, newConfig, accum);
|
|
95
95
|
break;
|
|
96
96
|
}
|
|
97
|
+
newConfig.excludes.push('list');
|
|
97
98
|
// fall through
|
|
98
99
|
case 'indicator':
|
|
99
100
|
case 'poem':
|
|
@@ -116,7 +117,9 @@ let ExtToken = (() => {
|
|
|
116
117
|
case 'tab':
|
|
117
118
|
newConfig.ext = newConfig.ext.filter(e => e !== 'tabs');
|
|
118
119
|
break;
|
|
119
|
-
|
|
120
|
+
case 'ref':
|
|
121
|
+
newConfig.ext = newConfig.ext.filter(e => e !== 'references');
|
|
122
|
+
// no default
|
|
120
123
|
}
|
|
121
124
|
innerToken = new index_2.Token(inner, newConfig, accum);
|
|
122
125
|
break;
|
package/dist/src/transclude.js
CHANGED
|
@@ -388,7 +388,7 @@ let TranscludeToken = (() => {
|
|
|
388
388
|
* @throws `Error` 不是可接受的魔术字
|
|
389
389
|
*/
|
|
390
390
|
getPossibleValues() {
|
|
391
|
-
const { type, name, childNodes } = this;
|
|
391
|
+
const { type, name, childNodes, length: l } = this;
|
|
392
392
|
if (type === 'template') {
|
|
393
393
|
throw new Error('TranscludeToken.getPossibleValues method is only for specific magic words!');
|
|
394
394
|
}
|
|
@@ -397,12 +397,14 @@ let TranscludeToken = (() => {
|
|
|
397
397
|
case 'if':
|
|
398
398
|
case 'ifexist':
|
|
399
399
|
case 'ifexpr':
|
|
400
|
-
case 'iferror':
|
|
401
400
|
start = 2;
|
|
402
401
|
break;
|
|
403
402
|
case 'ifeq':
|
|
404
403
|
start = 3;
|
|
405
404
|
break;
|
|
405
|
+
case 'iferror':
|
|
406
|
+
start = l > 3 ? 2 : 1;
|
|
407
|
+
break;
|
|
406
408
|
case 'switch': {
|
|
407
409
|
const parameters = childNodes.slice(2), last = parameters[parameters.length - 1];
|
|
408
410
|
queue = [
|
package/dist/util/debug.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mixin = exports.emptyArray = exports.getMagicWordInfo = exports.setChildNodes = exports.isLink = exports.isRowEnd = exports.
|
|
3
|
+
exports.mixin = exports.emptyArray = exports.getMagicWordInfo = exports.setChildNodes = exports.isLink = exports.isRowEnd = exports.Shadow = void 0;
|
|
4
|
+
exports.isToken = isToken;
|
|
4
5
|
exports.Shadow = {
|
|
5
6
|
running: false,
|
|
6
7
|
/** @private */
|
|
@@ -33,12 +34,9 @@ exports.Shadow = {
|
|
|
33
34
|
},
|
|
34
35
|
rev: 0,
|
|
35
36
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*/
|
|
40
|
-
const isToken = (type) => (node) => node.type === type;
|
|
41
|
-
exports.isToken = isToken;
|
|
37
|
+
function isToken(type) {
|
|
38
|
+
return (node) => node.type === type;
|
|
39
|
+
}
|
|
42
40
|
/**
|
|
43
41
|
* 是否是行尾
|
|
44
42
|
* @param token 节点
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikilint",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.43.0",
|
|
4
4
|
"description": "A Node.js linter for MediaWiki markup",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -74,39 +74,62 @@
|
|
|
74
74
|
]
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@bhsd/cm-util": "^2.0
|
|
77
|
+
"@bhsd/cm-util": "^2.1.0",
|
|
78
78
|
"@bhsd/common": "^2.2.1",
|
|
79
79
|
"@bhsd/stylelint-util": "^1.0.3",
|
|
80
80
|
"binary-search": "^1.3.6",
|
|
81
|
+
"entities": "^8.0.0",
|
|
81
82
|
"vscode-languageserver-types": "^3.17.5"
|
|
82
83
|
},
|
|
83
|
-
"
|
|
84
|
-
"color-name": "
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"vscode-
|
|
89
|
-
"vscode-
|
|
90
|
-
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"color-name": ">=2.0.0",
|
|
86
|
+
"mathoid-texvcjs": ">=0.4.0",
|
|
87
|
+
"stylelint": ">=16.0.0",
|
|
88
|
+
"vscode-css-languageservice": ">=3.0.0",
|
|
89
|
+
"vscode-html-languageservice": ">=3.1.0",
|
|
90
|
+
"vscode-json-languageservice": ">=3.2.0"
|
|
91
|
+
},
|
|
92
|
+
"peerDependenciesMeta": {
|
|
93
|
+
"color-name": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"mathoid-texvcjs": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"stylelint": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"vscode-css-languageservice": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"vscode-html-languageservice": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"vscode-json-languageservice": {
|
|
109
|
+
"optional": true
|
|
110
|
+
}
|
|
91
111
|
},
|
|
92
112
|
"devDependencies": {
|
|
93
|
-
"@bhsd/code-standard": "^2.
|
|
113
|
+
"@bhsd/code-standard": "^2.6.2",
|
|
94
114
|
"@bhsd/nodejs": "^1.0.1",
|
|
95
|
-
"@bhsd/test-util": "^1.
|
|
115
|
+
"@bhsd/test-util": "^1.5.0",
|
|
96
116
|
"@types/color-name": "^2.0.0",
|
|
97
117
|
"@types/color-rgba": "^2.1.3",
|
|
98
|
-
"@types/mocha": "^10.0.10",
|
|
99
|
-
"@types/node": "^25.9.0",
|
|
100
|
-
"@typescript-eslint/parser": "^8.59.4",
|
|
101
118
|
"c8": "^11.0.0",
|
|
119
|
+
"color-name": "~2.0.2",
|
|
102
120
|
"color-rgba": "^3.0.0",
|
|
103
121
|
"diff2html-cli": "^5.2.15",
|
|
104
122
|
"esbuild": "^0.28.0",
|
|
105
|
-
"eslint": "^10.4.
|
|
123
|
+
"eslint": "^10.4.1",
|
|
106
124
|
"markdownlint-cli2": "^0.22.1",
|
|
107
|
-
"
|
|
125
|
+
"mathoid-texvcjs": "^0.6.0",
|
|
126
|
+
"mocha": "^11.7.6",
|
|
127
|
+
"stylelint": "^17.12.0",
|
|
108
128
|
"typescript": "^6.0.3",
|
|
109
129
|
"v8r": "^6.1.0",
|
|
130
|
+
"vscode-css-languageservice": "^6.3.10",
|
|
131
|
+
"vscode-html-languageservice": "^5.6.2",
|
|
132
|
+
"vscode-json-languageservice": "^5.7.2",
|
|
110
133
|
"vscode-languageserver-textdocument": "^1.0.12"
|
|
111
134
|
},
|
|
112
135
|
"engines": {
|