eslint-plugin-svelte 2.12.0 → 2.13.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/README.md +1 -0
- package/lib/rules/html-self-closing.js +12 -6
- package/lib/rules/indent-helpers/ast.d.ts +1 -1
- package/lib/rules/indent-helpers/commons.d.ts +4 -4
- package/lib/rules/indent-helpers/es.d.ts +1 -1
- package/lib/rules/indent-helpers/offset-context.d.ts +1 -1
- package/lib/rules/indent-helpers/svelte.d.ts +1 -1
- package/lib/rules/indent-helpers/ts.d.ts +1 -1
- package/lib/rules/no-dom-manipulating.d.ts +2 -0
- package/lib/rules/no-dom-manipulating.js +109 -0
- package/lib/rules/prefer-destructured-store-props.js +4 -2
- package/lib/rules/reference-helpers/svelte-store.d.ts +2 -2
- package/lib/rules/sort-attributes.js +1 -1
- package/lib/shared/comment-directives.d.ts +1 -1
- package/lib/shared/svelte-compile-warns/ignore-comment.d.ts +2 -2
- package/lib/shared/svelte-compile-warns/index.d.ts +3 -3
- package/lib/shared/svelte-compile-warns/transform/types.d.ts +1 -1
- package/lib/types-for-node.d.ts +8 -6
- package/lib/types.d.ts +13 -12
- package/lib/utils/ast-utils.d.ts +5 -5
- package/lib/utils/ast-utils.js +16 -15
- package/lib/utils/css-utils/style-attribute.d.ts +2 -2
- package/lib/utils/css-utils/template-tokenize.d.ts +1 -1
- package/lib/utils/get-package-json.d.ts +1 -1
- package/lib/utils/rules.js +2 -0
- package/lib/utils/ts-utils/index.d.ts +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -298,6 +298,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
|
|
|
298
298
|
|
|
299
299
|
| Rule ID | Description | |
|
|
300
300
|
|:--------|:------------|:---|
|
|
301
|
+
| [svelte/no-dom-manipulating](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/) | disallow DOM manipulating | |
|
|
301
302
|
| [svelte/no-dupe-else-if-blocks](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks/) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
|
|
302
303
|
| [svelte/no-dupe-style-properties](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-style-properties/) | disallow duplicate style properties | :star: |
|
|
303
304
|
| [svelte/no-dynamic-slot-name](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dynamic-slot-name/) | disallow dynamic slot name | :star::wrench: |
|
|
@@ -49,14 +49,14 @@ exports.default = (0, utils_1.createRule)("html-self-closing", {
|
|
|
49
49
|
},
|
|
50
50
|
],
|
|
51
51
|
},
|
|
52
|
-
create(
|
|
52
|
+
create(context) {
|
|
53
53
|
let options = {
|
|
54
54
|
void: "always",
|
|
55
55
|
normal: "always",
|
|
56
56
|
component: "always",
|
|
57
57
|
svelte: "always",
|
|
58
58
|
};
|
|
59
|
-
const option =
|
|
59
|
+
const option = context.options?.[0];
|
|
60
60
|
switch (option) {
|
|
61
61
|
case "none":
|
|
62
62
|
options = {
|
|
@@ -103,16 +103,22 @@ exports.default = (0, utils_1.createRule)("html-self-closing", {
|
|
|
103
103
|
}
|
|
104
104
|
return true;
|
|
105
105
|
}
|
|
106
|
-
function report(node,
|
|
106
|
+
function report(node, shouldBeClosed) {
|
|
107
107
|
const elementType = getElementType(node);
|
|
108
|
-
|
|
108
|
+
context.report({
|
|
109
109
|
node,
|
|
110
|
-
|
|
110
|
+
loc: {
|
|
111
|
+
start: context
|
|
112
|
+
.getSourceCode()
|
|
113
|
+
.getLocFromIndex(node.startTag.range[1] - (node.startTag.selfClosing ? 2 : 1)),
|
|
114
|
+
end: node.loc.end,
|
|
115
|
+
},
|
|
116
|
+
messageId: shouldBeClosed ? "requireClosing" : "disallowClosing",
|
|
111
117
|
data: {
|
|
112
118
|
type: TYPE_MESSAGES[elementType],
|
|
113
119
|
},
|
|
114
120
|
*fix(fixer) {
|
|
115
|
-
if (
|
|
121
|
+
if (shouldBeClosed) {
|
|
116
122
|
for (const child of node.children) {
|
|
117
123
|
yield fixer.removeRange(child.range);
|
|
118
124
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
2
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
3
|
-
|
|
3
|
+
type AnyToken = AST.Token | AST.Comment;
|
|
4
4
|
export declare function isWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
|
|
5
5
|
export declare function isNotWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
|
|
6
6
|
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { ASTNode, SourceCode } from "../../types";
|
|
2
2
|
import type { AST } from "svelte-eslint-parser";
|
|
3
3
|
import type { OffsetContext } from "./offset-context";
|
|
4
|
-
export
|
|
5
|
-
export
|
|
4
|
+
export type AnyToken = AST.Token | AST.Comment;
|
|
5
|
+
export type MaybeNode = {
|
|
6
6
|
type: string;
|
|
7
7
|
range: [number, number];
|
|
8
8
|
loc: AST.SourceLocation;
|
|
9
9
|
};
|
|
10
|
-
export
|
|
10
|
+
export type IndentOptions = {
|
|
11
11
|
indentChar: " " | "\t";
|
|
12
12
|
indentScript: boolean;
|
|
13
13
|
indentSize: number;
|
|
@@ -15,7 +15,7 @@ export declare type IndentOptions = {
|
|
|
15
15
|
alignAttributesVertically: boolean;
|
|
16
16
|
ignoredNodes: string[];
|
|
17
17
|
};
|
|
18
|
-
export
|
|
18
|
+
export type IndentContext = {
|
|
19
19
|
sourceCode: SourceCode;
|
|
20
20
|
options: IndentOptions;
|
|
21
21
|
offsets: OffsetContext;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IndentContext } from "./commons";
|
|
2
2
|
import type { ESNodeListener } from "../../types-for-node";
|
|
3
|
-
|
|
3
|
+
type NodeListener = ESNodeListener;
|
|
4
4
|
export declare function defineVisitor(context: IndentContext): NodeListener;
|
|
5
5
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SvelteNodeListener } from "../../types-for-node";
|
|
2
2
|
import type { IndentContext } from "./commons";
|
|
3
|
-
|
|
3
|
+
type NodeListener = SvelteNodeListener;
|
|
4
4
|
export declare function defineVisitor(context: IndentContext): NodeListener;
|
|
5
5
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IndentContext } from "./commons";
|
|
2
2
|
import type { TSNodeListener } from "../../types-for-node";
|
|
3
|
-
|
|
3
|
+
type NodeListener = TSNodeListener;
|
|
4
4
|
export declare function defineVisitor(context: IndentContext): NodeListener;
|
|
5
5
|
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const ast_utils_1 = require("../utils/ast-utils");
|
|
5
|
+
const eslint_utils_1 = require("eslint-utils");
|
|
6
|
+
const DOM_MANIPULATING_METHODS = new Set([
|
|
7
|
+
"appendChild",
|
|
8
|
+
"insertBefore",
|
|
9
|
+
"normalize",
|
|
10
|
+
"removeChild",
|
|
11
|
+
"replaceChild",
|
|
12
|
+
"after",
|
|
13
|
+
"append",
|
|
14
|
+
"before",
|
|
15
|
+
"insertAdjacentElement",
|
|
16
|
+
"insertAdjacentHTML",
|
|
17
|
+
"insertAdjacentText",
|
|
18
|
+
"prepend",
|
|
19
|
+
"remove",
|
|
20
|
+
"replaceChildren",
|
|
21
|
+
"replaceWith",
|
|
22
|
+
]);
|
|
23
|
+
const DOM_MANIPULATING_PROPERTIES = new Set([
|
|
24
|
+
"textContent",
|
|
25
|
+
"innerHTML",
|
|
26
|
+
"outerHTML",
|
|
27
|
+
"innerText",
|
|
28
|
+
"outerText",
|
|
29
|
+
]);
|
|
30
|
+
exports.default = (0, utils_1.createRule)("no-dom-manipulating", {
|
|
31
|
+
meta: {
|
|
32
|
+
docs: {
|
|
33
|
+
description: "disallow DOM manipulating",
|
|
34
|
+
category: "Possible Errors",
|
|
35
|
+
recommended: false,
|
|
36
|
+
},
|
|
37
|
+
schema: [],
|
|
38
|
+
messages: {
|
|
39
|
+
disallowManipulateDOM: "Don't manipulate the DOM directly. The Svelte runtime can get confused if there is a difference between the actual DOM and the DOM expected by the Svelte runtime.",
|
|
40
|
+
},
|
|
41
|
+
type: "problem",
|
|
42
|
+
},
|
|
43
|
+
create(context) {
|
|
44
|
+
const domVariables = new Set();
|
|
45
|
+
function verifyIdentifier(node) {
|
|
46
|
+
const member = node.parent;
|
|
47
|
+
if (member?.type !== "MemberExpression" || member.object !== node) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const name = (0, eslint_utils_1.getPropertyName)(member);
|
|
51
|
+
if (!name) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let target = member;
|
|
55
|
+
let parent = target.parent;
|
|
56
|
+
while (parent?.type === "ChainExpression") {
|
|
57
|
+
target = parent;
|
|
58
|
+
parent = parent.parent;
|
|
59
|
+
}
|
|
60
|
+
if (!parent) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (parent.type === "CallExpression") {
|
|
64
|
+
if (parent.callee !== target || !DOM_MANIPULATING_METHODS.has(name)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (parent.type === "AssignmentExpression") {
|
|
69
|
+
if (parent.left !== target || !DOM_MANIPULATING_PROPERTIES.has(name)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
context.report({
|
|
74
|
+
node: member,
|
|
75
|
+
messageId: "disallowManipulateDOM",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
"SvelteDirective[kind='Binding']"(node) {
|
|
80
|
+
if (node.key.name.name !== "this" ||
|
|
81
|
+
!node.expression ||
|
|
82
|
+
node.expression.type !== "Identifier") {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const element = node.parent.parent;
|
|
86
|
+
if (element.type !== "SvelteElement" || !isHTMLElement(element)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const variable = (0, ast_utils_1.findVariable)(context, node.expression);
|
|
90
|
+
if (!variable ||
|
|
91
|
+
(variable.scope.type !== "module" && variable.scope.type !== "global")) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
domVariables.add(variable);
|
|
95
|
+
},
|
|
96
|
+
"Program:exit"() {
|
|
97
|
+
for (const variable of domVariables) {
|
|
98
|
+
for (const reference of variable.references) {
|
|
99
|
+
verifyIdentifier(reference.identifier);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
function isHTMLElement(node) {
|
|
105
|
+
return (node.kind === "html" ||
|
|
106
|
+
(node.kind === "special" && (0, ast_utils_1.getNodeName)(node) === "svelte:element"));
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
});
|
|
@@ -47,7 +47,8 @@ exports.default = (0, utils_1.createRule)("prefer-destructured-store-props", {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
function isReactiveVariableDefinitionWithMemberExpression(node) {
|
|
50
|
-
return (node.
|
|
50
|
+
return (node.type === "Identifier" &&
|
|
51
|
+
node.parent?.type === "MemberExpression" &&
|
|
51
52
|
node.parent.object === node &&
|
|
52
53
|
(0, eslint_utils_1.getPropertyName)(node.parent) === propName &&
|
|
53
54
|
node.parent.parent?.type === "AssignmentExpression" &&
|
|
@@ -58,7 +59,8 @@ exports.default = (0, utils_1.createRule)("prefer-destructured-store-props", {
|
|
|
58
59
|
.parent?.type === "SvelteReactiveStatement");
|
|
59
60
|
}
|
|
60
61
|
function isReactiveVariableDefinitionWithDestructuring(node) {
|
|
61
|
-
return (node.
|
|
62
|
+
return (node.type === "Identifier" &&
|
|
63
|
+
node.parent?.type === "AssignmentExpression" &&
|
|
62
64
|
node.parent.right === node &&
|
|
63
65
|
node.parent.left.type === "ObjectPattern" &&
|
|
64
66
|
node.parent.parent?.type === "ExpressionStatement" &&
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
|
-
|
|
3
|
+
type StoreName = "writable" | "readable" | "derived";
|
|
4
4
|
export declare function extractStoreReferences(context: RuleContext, storeNames?: StoreName[]): Generator<{
|
|
5
5
|
node: TSESTree.CallExpression;
|
|
6
6
|
name: string;
|
|
7
7
|
}, void>;
|
|
8
|
-
export
|
|
8
|
+
export type StoreChecker = (node: TSESTree.Expression, options?: {
|
|
9
9
|
consistent?: boolean;
|
|
10
10
|
}) => boolean;
|
|
11
11
|
export declare function createStoreChecker(context: RuleContext): StoreChecker;
|
|
@@ -176,7 +176,7 @@ exports.default = (0, utils_1.createRule)("sort-attributes", {
|
|
|
176
176
|
const k = cacheKeyText.get(node);
|
|
177
177
|
if (k != null)
|
|
178
178
|
return k;
|
|
179
|
-
const result = (0, ast_utils_1.getAttributeKeyText)(node);
|
|
179
|
+
const result = (0, ast_utils_1.getAttributeKeyText)(node, context);
|
|
180
180
|
cacheKeyText.set(node, result);
|
|
181
181
|
return result;
|
|
182
182
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
|
-
export
|
|
3
|
+
export type IgnoreItemWithoutCode = {
|
|
4
4
|
range: [number, number];
|
|
5
5
|
code: null;
|
|
6
6
|
token: AST.Token | AST.Comment;
|
|
7
7
|
};
|
|
8
|
-
export
|
|
8
|
+
export type IgnoreItem = {
|
|
9
9
|
range: [number, number];
|
|
10
10
|
code: string;
|
|
11
11
|
token: AST.Token | AST.Comment;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
3
|
import type { IgnoreItem } from "./ignore-comment";
|
|
4
|
-
export
|
|
4
|
+
export type SvelteCompileWarnings = {
|
|
5
5
|
warnings: Warning[];
|
|
6
6
|
unusedIgnores: IgnoreItem[];
|
|
7
7
|
kind: "warn" | "error";
|
|
8
8
|
stripStyleElements: AST.SvelteStyleElement[];
|
|
9
9
|
};
|
|
10
|
-
export
|
|
10
|
+
export type Loc = {
|
|
11
11
|
start?: {
|
|
12
12
|
line: number;
|
|
13
13
|
column: number;
|
|
@@ -17,7 +17,7 @@ export declare type Loc = {
|
|
|
17
17
|
column: number;
|
|
18
18
|
};
|
|
19
19
|
};
|
|
20
|
-
export
|
|
20
|
+
export type Warning = {
|
|
21
21
|
code?: string;
|
|
22
22
|
message: string;
|
|
23
23
|
} & Loc;
|
package/lib/types-for-node.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { TSESTree, AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
2
2
|
import type { AST } from "svelte-eslint-parser";
|
|
3
|
-
export
|
|
3
|
+
export type ASTNode = AST.SvelteNode | Exclude<Omit<TSESTree.Node, "parent">, {
|
|
4
4
|
type: AST.SvelteNode["type"];
|
|
5
5
|
}>;
|
|
6
|
-
export
|
|
6
|
+
export type ASTNodeWithParent = (Exclude<ASTNode, AST.SvelteProgram> & {
|
|
7
7
|
parent: ASTNodeWithParent;
|
|
8
8
|
}) | AST.SvelteProgram;
|
|
9
|
-
export
|
|
9
|
+
export type ASTNodeListener = {
|
|
10
10
|
ArrayExpression?: (node: TSESTree.ArrayExpression & ASTNodeWithParent) => void;
|
|
11
11
|
ArrayPattern?: (node: TSESTree.ArrayPattern & ASTNodeWithParent) => void;
|
|
12
12
|
ArrowFunctionExpression?: (node: TSESTree.ArrowFunctionExpression & ASTNodeWithParent) => void;
|
|
@@ -151,6 +151,7 @@ export declare type ASTNodeListener = {
|
|
|
151
151
|
TSQualifiedName?: (node: TSESTree.TSQualifiedName & ASTNodeWithParent) => void;
|
|
152
152
|
TSReadonlyKeyword?: (node: TSESTree.TSReadonlyKeyword & ASTNodeWithParent) => void;
|
|
153
153
|
TSRestType?: (node: TSESTree.TSRestType & ASTNodeWithParent) => void;
|
|
154
|
+
TSSatisfiesExpression?: (node: TSESTree.TSSatisfiesExpression & ASTNodeWithParent) => void;
|
|
154
155
|
TSStaticKeyword?: (node: TSESTree.TSStaticKeyword & ASTNodeWithParent) => void;
|
|
155
156
|
TSStringKeyword?: (node: TSESTree.TSStringKeyword & ASTNodeWithParent) => void;
|
|
156
157
|
TSSymbolKeyword?: (node: TSESTree.TSSymbolKeyword & ASTNodeWithParent) => void;
|
|
@@ -204,7 +205,7 @@ export declare type ASTNodeListener = {
|
|
|
204
205
|
SvelteHTMLComment?: (node: AST.SvelteHTMLComment & ASTNodeWithParent) => void;
|
|
205
206
|
SvelteReactiveStatement?: (node: AST.SvelteReactiveStatement & ASTNodeWithParent) => void;
|
|
206
207
|
};
|
|
207
|
-
export
|
|
208
|
+
export type ESNodeListener = {
|
|
208
209
|
ArrayExpression?: (node: TSESTree.ArrayExpression & ASTNodeWithParent) => void;
|
|
209
210
|
ArrayPattern?: (node: TSESTree.ArrayPattern & ASTNodeWithParent) => void;
|
|
210
211
|
ArrowFunctionExpression?: (node: TSESTree.ArrowFunctionExpression & ASTNodeWithParent) => void;
|
|
@@ -277,7 +278,7 @@ export declare type ESNodeListener = {
|
|
|
277
278
|
Program?: (node: AST.SvelteProgram & ASTNodeWithParent) => void;
|
|
278
279
|
SvelteReactiveStatement?: (node: AST.SvelteReactiveStatement & ASTNodeWithParent) => void;
|
|
279
280
|
};
|
|
280
|
-
export
|
|
281
|
+
export type TSNodeListener = {
|
|
281
282
|
Decorator?: (node: TSESTree.Decorator & ASTNodeWithParent) => void;
|
|
282
283
|
ImportAttribute?: (node: TSESTree.ImportAttribute & ASTNodeWithParent) => void;
|
|
283
284
|
StaticBlock?: (node: TSESTree.StaticBlock & ASTNodeWithParent) => void;
|
|
@@ -338,6 +339,7 @@ export declare type TSNodeListener = {
|
|
|
338
339
|
TSQualifiedName?: (node: TSESTree.TSQualifiedName & ASTNodeWithParent) => void;
|
|
339
340
|
TSReadonlyKeyword?: (node: TSESTree.TSReadonlyKeyword & ASTNodeWithParent) => void;
|
|
340
341
|
TSRestType?: (node: TSESTree.TSRestType & ASTNodeWithParent) => void;
|
|
342
|
+
TSSatisfiesExpression?: (node: TSESTree.TSSatisfiesExpression & ASTNodeWithParent) => void;
|
|
341
343
|
TSStaticKeyword?: (node: TSESTree.TSStaticKeyword & ASTNodeWithParent) => void;
|
|
342
344
|
TSStringKeyword?: (node: TSESTree.TSStringKeyword & ASTNodeWithParent) => void;
|
|
343
345
|
TSSymbolKeyword?: (node: TSESTree.TSSymbolKeyword & ASTNodeWithParent) => void;
|
|
@@ -360,7 +362,7 @@ export declare type TSNodeListener = {
|
|
|
360
362
|
TSUnknownKeyword?: (node: TSESTree.TSUnknownKeyword & ASTNodeWithParent) => void;
|
|
361
363
|
TSVoidKeyword?: (node: TSESTree.TSVoidKeyword & ASTNodeWithParent) => void;
|
|
362
364
|
};
|
|
363
|
-
export
|
|
365
|
+
export type SvelteNodeListener = {
|
|
364
366
|
SvelteScriptElement?: (node: AST.SvelteScriptElement & ASTNodeWithParent) => void;
|
|
365
367
|
SvelteStyleElement?: (node: AST.SvelteStyleElement & ASTNodeWithParent) => void;
|
|
366
368
|
SvelteElement?: (node: AST.SvelteElement & ASTNodeWithParent) => void;
|
package/lib/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { JSONSchema4 } from "json-schema";
|
|
2
|
-
import type { Linter, Rule,
|
|
2
|
+
import type { Linter, Rule, SourceCode as ESLintSourceCode } from "eslint";
|
|
3
3
|
import type { AST } from "svelte-eslint-parser";
|
|
4
4
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
5
|
+
import type { ScopeManager, Scope, Variable } from "@typescript-eslint/scope-manager";
|
|
5
6
|
import type { ASTNode, ASTNodeWithParent, ASTNodeListener } from "./types-for-node";
|
|
6
7
|
export type { ASTNode, ASTNodeWithParent, ASTNodeListener };
|
|
7
8
|
export interface RuleListener extends ASTNodeListener {
|
|
@@ -16,7 +17,7 @@ export interface RuleModule {
|
|
|
16
17
|
meta: RuleMetaData;
|
|
17
18
|
create: (context: RuleContext) => RuleListener;
|
|
18
19
|
}
|
|
19
|
-
export
|
|
20
|
+
export type RuleCategory = "Possible Errors" | "Security Vulnerability" | "Best Practices" | "Stylistic Issues" | "Extension Rules" | "System";
|
|
20
21
|
export interface RuleMetaData {
|
|
21
22
|
docs: {
|
|
22
23
|
description: string;
|
|
@@ -76,7 +77,7 @@ export interface PartialRuleMetaData {
|
|
|
76
77
|
};
|
|
77
78
|
type: "problem" | "suggestion" | "layout";
|
|
78
79
|
}
|
|
79
|
-
export
|
|
80
|
+
export type RuleContext = {
|
|
80
81
|
id: string;
|
|
81
82
|
options: any[];
|
|
82
83
|
settings?: {
|
|
@@ -99,15 +100,15 @@ export declare type RuleContext = {
|
|
|
99
100
|
parserOptions: Linter.ParserOptions;
|
|
100
101
|
parserServices: ESLintSourceCode.ParserServices;
|
|
101
102
|
getAncestors(): ASTNode[];
|
|
102
|
-
getDeclaredVariables(node: TSESTree.Node):
|
|
103
|
+
getDeclaredVariables(node: TSESTree.Node): Variable[];
|
|
103
104
|
getFilename(): string;
|
|
104
|
-
getScope(): Scope
|
|
105
|
+
getScope(): Scope;
|
|
105
106
|
getSourceCode(): SourceCode;
|
|
106
107
|
markVariableAsUsed(name: string): boolean;
|
|
107
108
|
report(descriptor: ReportDescriptor): void;
|
|
108
109
|
getCwd?: () => string;
|
|
109
110
|
};
|
|
110
|
-
export
|
|
111
|
+
export type NodeOrToken = {
|
|
111
112
|
type: string;
|
|
112
113
|
loc?: AST.SourceLocation | null;
|
|
113
114
|
range?: [number, number];
|
|
@@ -118,22 +119,22 @@ interface ReportDescriptorOptionsBase {
|
|
|
118
119
|
};
|
|
119
120
|
fix?: null | ((fixer: RuleFixer) => null | Rule.Fix | IterableIterator<Rule.Fix> | Rule.Fix[]);
|
|
120
121
|
}
|
|
121
|
-
|
|
122
|
+
type SuggestionDescriptorMessage = {
|
|
122
123
|
desc: string;
|
|
123
124
|
} | {
|
|
124
125
|
messageId: string;
|
|
125
126
|
};
|
|
126
|
-
export
|
|
127
|
+
export type SuggestionReportDescriptor = SuggestionDescriptorMessage & ReportDescriptorOptionsBase;
|
|
127
128
|
interface ReportDescriptorOptions extends ReportDescriptorOptionsBase {
|
|
128
129
|
suggest?: SuggestionReportDescriptor[] | null;
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions;
|
|
132
|
+
type ReportDescriptorMessage = {
|
|
132
133
|
message: string;
|
|
133
134
|
} | {
|
|
134
135
|
messageId: string;
|
|
135
136
|
};
|
|
136
|
-
|
|
137
|
+
type ReportDescriptorLocation = {
|
|
137
138
|
node: NodeOrToken;
|
|
138
139
|
} | {
|
|
139
140
|
loc: AST.SourceLocation | {
|
|
@@ -160,7 +161,7 @@ export interface SourceCode {
|
|
|
160
161
|
lines: string[];
|
|
161
162
|
hasBOM: boolean;
|
|
162
163
|
parserServices: ESLintSourceCode.ParserServices;
|
|
163
|
-
scopeManager:
|
|
164
|
+
scopeManager: ScopeManager;
|
|
164
165
|
visitorKeys: ESLintSourceCode.VisitorKeys;
|
|
165
166
|
getText(node?: NodeOrToken, beforeCount?: number, afterCount?: number): string;
|
|
166
167
|
getLines(): string[];
|
package/lib/utils/ast-utils.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ASTNode, RuleContext, SourceCode } from "../types";
|
|
2
2
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
3
|
+
import type { Scope, Variable } from "@typescript-eslint/scope-manager";
|
|
3
4
|
import type { AST as SvAST } from "svelte-eslint-parser";
|
|
4
|
-
import type { Scope } from "eslint";
|
|
5
5
|
export declare function equalTokens(left: ASTNode, right: ASTNode, sourceCode: SourceCode): boolean;
|
|
6
6
|
export declare function getStringIfConstant(node: TSESTree.Expression | TSESTree.PrivateIdentifier): string | null;
|
|
7
7
|
export declare function needParentheses(node: TSESTree.Expression, kind: "not" | "logical"): boolean;
|
|
@@ -29,10 +29,10 @@ export declare function findBindDirective<N extends string>(node: SvAST.SvelteEl
|
|
|
29
29
|
}) | null;
|
|
30
30
|
export declare function getStaticAttributeValue(node: SvAST.SvelteAttribute): string | null;
|
|
31
31
|
export declare function getLangValue(node: SvAST.SvelteScriptElement | SvAST.SvelteStyleElement): string | null;
|
|
32
|
-
export declare function findVariable(context: RuleContext, node: TSESTree.Identifier):
|
|
33
|
-
export declare function getScope(context: RuleContext, currentNode: TSESTree.Node): Scope
|
|
32
|
+
export declare function findVariable(context: RuleContext, node: TSESTree.Identifier): Variable | null;
|
|
33
|
+
export declare function getScope(context: RuleContext, currentNode: TSESTree.Node): Scope;
|
|
34
34
|
export declare function getParent(node: TSESTree.Node): TSESTree.Node | null;
|
|
35
|
-
export
|
|
35
|
+
export type QuoteAndRange = {
|
|
36
36
|
quote: "unquoted" | "double" | "single";
|
|
37
37
|
range: [number, number];
|
|
38
38
|
firstToken: SvAST.Token | SvAST.Comment;
|
|
@@ -47,7 +47,7 @@ export declare function getMustacheTokens(node: SvAST.SvelteDirective | SvAST.Sv
|
|
|
47
47
|
openToken: SvAST.Token;
|
|
48
48
|
closeToken: SvAST.Token;
|
|
49
49
|
} | null;
|
|
50
|
-
export declare function getAttributeKeyText(node: SvAST.SvelteAttribute | SvAST.SvelteShorthandAttribute | SvAST.SvelteStyleDirective | SvAST.SvelteDirective | SvAST.SvelteSpecialDirective): string;
|
|
50
|
+
export declare function getAttributeKeyText(node: SvAST.SvelteAttribute | SvAST.SvelteShorthandAttribute | SvAST.SvelteStyleDirective | SvAST.SvelteDirective | SvAST.SvelteSpecialDirective, context: RuleContext): string;
|
|
51
51
|
export declare function getDirectiveName(node: SvAST.SvelteDirective): string;
|
|
52
52
|
export declare function getNodeName(node: SvAST.SvelteElement): string;
|
|
53
53
|
export declare function isVoidHtmlElement(node: SvAST.SvelteElement): boolean;
|
package/lib/utils/ast-utils.js
CHANGED
|
@@ -276,7 +276,7 @@ function getMustacheTokens(node, sourceCode) {
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
exports.getMustacheTokens = getMustacheTokens;
|
|
279
|
-
function getAttributeKeyText(node) {
|
|
279
|
+
function getAttributeKeyText(node, context) {
|
|
280
280
|
switch (node.type) {
|
|
281
281
|
case "SvelteAttribute":
|
|
282
282
|
case "SvelteShorthandAttribute":
|
|
@@ -287,7 +287,7 @@ function getAttributeKeyText(node) {
|
|
|
287
287
|
return node.kind;
|
|
288
288
|
case "SvelteDirective": {
|
|
289
289
|
const dir = getDirectiveName(node);
|
|
290
|
-
return `${dir}:${node.key.name
|
|
290
|
+
return `${dir}:${getSimpleNameFromNode(node.key.name, context)}${node.key.modifiers.length ? `|${node.key.modifiers.join("|")}` : ""}`;
|
|
291
291
|
}
|
|
292
292
|
default:
|
|
293
293
|
throw new Error(`Unknown node type: ${node.type}`);
|
|
@@ -339,19 +339,7 @@ function getAttributeValueRangeTokens(attr, sourceCode) {
|
|
|
339
339
|
};
|
|
340
340
|
}
|
|
341
341
|
function getNodeName(node) {
|
|
342
|
-
|
|
343
|
-
return node.name.name;
|
|
344
|
-
}
|
|
345
|
-
let object = "";
|
|
346
|
-
let currentObject = node.name.object;
|
|
347
|
-
while ("object" in currentObject) {
|
|
348
|
-
object = `${currentObject.property.name}.${object}`;
|
|
349
|
-
currentObject = currentObject.object;
|
|
350
|
-
}
|
|
351
|
-
if ("name" in currentObject) {
|
|
352
|
-
object = `${currentObject.name}.${object}`;
|
|
353
|
-
}
|
|
354
|
-
return object + node.name.property.name;
|
|
342
|
+
return getSimpleNameFromNode(node.name);
|
|
355
343
|
}
|
|
356
344
|
exports.getNodeName = getNodeName;
|
|
357
345
|
function isVoidHtmlElement(node) {
|
|
@@ -394,3 +382,16 @@ function isExpressionIdentifier(node) {
|
|
|
394
382
|
return true;
|
|
395
383
|
}
|
|
396
384
|
exports.isExpressionIdentifier = isExpressionIdentifier;
|
|
385
|
+
function getSimpleNameFromNode(node, context) {
|
|
386
|
+
if (node.type === "Identifier" || node.type === "SvelteName") {
|
|
387
|
+
return node.name;
|
|
388
|
+
}
|
|
389
|
+
if (node.type === "SvelteMemberExpressionName" ||
|
|
390
|
+
(node.type === "MemberExpression" && !node.computed)) {
|
|
391
|
+
return `${getSimpleNameFromNode(node.object, context)}.${getSimpleNameFromNode(node.property, context)}`;
|
|
392
|
+
}
|
|
393
|
+
if (!context) {
|
|
394
|
+
throw new Error("Rule context is required");
|
|
395
|
+
}
|
|
396
|
+
return context.getSourceCode().getText(node);
|
|
397
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { AST } from "svelte-eslint-parser";
|
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
3
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
4
4
|
export declare function parseStyleAttributeValue(node: AST.SvelteAttribute, context: RuleContext): SvelteStyleRoot<AST.SvelteMustacheTagText> | null;
|
|
5
|
-
export
|
|
5
|
+
export type SvelteStyleInterpolation = AST.SvelteMustacheTagText | TSESTree.Expression;
|
|
6
6
|
export interface SvelteStyleNode<E extends SvelteStyleInterpolation> {
|
|
7
7
|
nodes?: SvelteStyleChildNode<E>[];
|
|
8
8
|
range: AST.Range;
|
|
@@ -40,4 +40,4 @@ export interface SvelteStyleComment extends SvelteStyleNode<never> {
|
|
|
40
40
|
type: "comment";
|
|
41
41
|
addInterpolation: (tagOrExpr: SvelteStyleInterpolation) => void;
|
|
42
42
|
}
|
|
43
|
-
export
|
|
43
|
+
export type SvelteStyleChildNode<E extends SvelteStyleInterpolation = SvelteStyleInterpolation> = SvelteStyleDeclaration<E> | SvelteStyleComment;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Tokenizer } from "postcss/lib/tokenize";
|
|
2
2
|
import tokenize from "postcss/lib/tokenize";
|
|
3
|
-
|
|
3
|
+
type Tokenize = typeof tokenize;
|
|
4
4
|
declare function templateTokenize(...args: Parameters<Tokenize>): Tokenizer;
|
|
5
5
|
export default templateTokenize;
|
package/lib/utils/rules.js
CHANGED
|
@@ -17,6 +17,7 @@ const max_attributes_per_line_1 = __importDefault(require("../rules/max-attribut
|
|
|
17
17
|
const mustache_spacing_1 = __importDefault(require("../rules/mustache-spacing"));
|
|
18
18
|
const no_at_debug_tags_1 = __importDefault(require("../rules/no-at-debug-tags"));
|
|
19
19
|
const no_at_html_tags_1 = __importDefault(require("../rules/no-at-html-tags"));
|
|
20
|
+
const no_dom_manipulating_1 = __importDefault(require("../rules/no-dom-manipulating"));
|
|
20
21
|
const no_dupe_else_if_blocks_1 = __importDefault(require("../rules/no-dupe-else-if-blocks"));
|
|
21
22
|
const no_dupe_style_properties_1 = __importDefault(require("../rules/no-dupe-style-properties"));
|
|
22
23
|
const no_dynamic_slot_name_1 = __importDefault(require("../rules/no-dynamic-slot-name"));
|
|
@@ -63,6 +64,7 @@ exports.rules = [
|
|
|
63
64
|
mustache_spacing_1.default,
|
|
64
65
|
no_at_debug_tags_1.default,
|
|
65
66
|
no_at_html_tags_1.default,
|
|
67
|
+
no_dom_manipulating_1.default,
|
|
66
68
|
no_dupe_else_if_blocks_1.default,
|
|
67
69
|
no_dupe_style_properties_1.default,
|
|
68
70
|
no_dynamic_slot_name_1.default,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { RuleContext, ASTNode } from "../../types";
|
|
2
2
|
import type * as TS from "typescript";
|
|
3
|
-
export
|
|
3
|
+
export type TypeScript = typeof TS;
|
|
4
4
|
export type { TS };
|
|
5
|
-
export
|
|
5
|
+
export type TSTools = {
|
|
6
6
|
service: {
|
|
7
7
|
esTreeNodeToTSNodeMap: ReadonlyMap<unknown, TS.Node>;
|
|
8
8
|
tsNodeToESTreeNodeMap: ReadonlyMap<TS.Node, ASTNode>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-svelte",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.1",
|
|
4
4
|
"description": "ESLint plugin for Svelte using AST",
|
|
5
5
|
"repository": "git+https://github.com/ota-meshi/eslint-plugin-svelte.git",
|
|
6
6
|
"homepage": "https://ota-meshi.github.io/eslint-plugin-svelte",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"postcss-load-config": "^3.1.4",
|
|
74
74
|
"postcss-safe-parser": "^6.0.0",
|
|
75
75
|
"sourcemap-codec": "^1.4.8",
|
|
76
|
-
"svelte-eslint-parser": "^0.
|
|
76
|
+
"svelte-eslint-parser": "^0.22.0"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@1stg/browserslist-config": "^1.2.3",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"access": "public"
|
|
175
175
|
},
|
|
176
176
|
"typeCoverage": {
|
|
177
|
-
"atLeast":
|
|
177
|
+
"atLeast": 99.04,
|
|
178
178
|
"cache": true,
|
|
179
179
|
"detail": true,
|
|
180
180
|
"ignoreAsAssertion": true,
|