eslint-plugin-svelte 2.10.0 → 2.12.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 +54 -7
- package/lib/rules/@typescript-eslint/no-unnecessary-condition.js +4 -0
- package/lib/rules/indent-helpers/ast.d.ts +3 -3
- package/lib/rules/indent-helpers/es.js +7 -9
- package/lib/rules/no-export-load-in-svelte-module-in-kit-pages.d.ts +2 -0
- package/lib/rules/no-export-load-in-svelte-module-in-kit-pages.js +41 -0
- package/lib/rules/reference-helpers/svelte-store.d.ts +6 -2
- package/lib/rules/reference-helpers/svelte-store.js +99 -1
- package/lib/rules/require-store-callbacks-use-set-param.d.ts +2 -0
- package/lib/rules/require-store-callbacks-use-set-param.js +43 -0
- package/lib/rules/require-store-reactive-access.d.ts +2 -0
- package/lib/rules/require-store-reactive-access.js +205 -0
- package/lib/rules/valid-prop-names-in-kit-pages.d.ts +2 -0
- package/lib/rules/valid-prop-names-in-kit-pages.js +61 -0
- package/lib/types-for-node.d.ts +72 -73
- package/lib/types.d.ts +14 -5
- package/lib/utils/ast-utils.d.ts +5 -5
- package/lib/utils/ast-utils.js +5 -1
- package/lib/utils/cache.d.ts +4 -0
- package/lib/utils/cache.js +32 -0
- package/lib/utils/css-utils/style-attribute.d.ts +4 -4
- package/lib/utils/eslint-core.d.ts +3 -3
- package/lib/utils/get-package-json.d.ts +5 -0
- package/lib/utils/get-package-json.js +55 -0
- package/lib/utils/rules.js +8 -0
- package/lib/utils/svelte-kit.d.ts +2 -0
- package/lib/utils/svelte-kit.js +48 -0
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -188,12 +188,6 @@ See also <https://github.com/ota-meshi/svelte-eslint-parser#readme>.
|
|
|
188
188
|
|
|
189
189
|
You can change the behavior of this plugin with some settings.
|
|
190
190
|
|
|
191
|
-
- `ignoreWarnings` (optional) ... Specifies an array of rules that ignore reports in the template.
|
|
192
|
-
For example, set rules on the template that cannot avoid false positives.
|
|
193
|
-
- `compileOptions` (optional) ... Specifies options for Svelte compile. Effects rules that use Svelte compile. The target rules are [svelte/valid-compile](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-compile/) and [svelte/no-unused-svelte-ignore](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/). **Note that it has no effect on ESLint's custom parser**.
|
|
194
|
-
- `postcss` (optional) ... Specifies options related to PostCSS. You can disable the PostCSS process by specifying `false`.
|
|
195
|
-
- `configFilePath` (optional) ... Specifies the path of the directory containing the PostCSS configuration.
|
|
196
|
-
|
|
197
191
|
e.g.
|
|
198
192
|
|
|
199
193
|
```js
|
|
@@ -210,6 +204,47 @@ module.exports = {
|
|
|
210
204
|
configFilePath: "./path/to/my/postcss.config.js",
|
|
211
205
|
},
|
|
212
206
|
},
|
|
207
|
+
kit: {
|
|
208
|
+
files: {
|
|
209
|
+
routes: "src/routes",
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
// ...
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### settings.svelte.ignoreWarnings
|
|
219
|
+
|
|
220
|
+
Specifies an array of rules that ignore reports in the template.
|
|
221
|
+
For example, set rules on the template that cannot avoid false positives.
|
|
222
|
+
|
|
223
|
+
#### settings.svelte.compileOptions
|
|
224
|
+
|
|
225
|
+
Specifies options for Svelte compile. Effects rules that use Svelte compile. The target rules are [svelte/valid-compile](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-compile/) and [svelte/no-unused-svelte-ignore](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/). **Note that it has no effect on ESLint's custom parser**.
|
|
226
|
+
|
|
227
|
+
- `postcss` ... Specifies options related to PostCSS. You can disable the PostCSS process by specifying `false`.
|
|
228
|
+
- `configFilePath` ... Specifies the path of the directory containing the PostCSS configuration.
|
|
229
|
+
|
|
230
|
+
#### settings.svelte.kit
|
|
231
|
+
|
|
232
|
+
If you use SvelteKit with not default configuration, you need to set below configurations.
|
|
233
|
+
The schema is subset of SvelteKit's configuration.
|
|
234
|
+
Therefore please check [SvelteKit docs](https://kit.svelte.dev/docs/configuration) for more details.
|
|
235
|
+
|
|
236
|
+
e.g.
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
module.exports = {
|
|
240
|
+
// ...
|
|
241
|
+
settings: {
|
|
242
|
+
svelte: {
|
|
243
|
+
kit: {
|
|
244
|
+
files: {
|
|
245
|
+
routes: "src/routes",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
213
248
|
},
|
|
214
249
|
},
|
|
215
250
|
// ...
|
|
@@ -266,12 +301,16 @@ These rules relate to possible syntax or logic errors in Svelte code:
|
|
|
266
301
|
| [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: |
|
|
267
302
|
| [svelte/no-dupe-style-properties](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-style-properties/) | disallow duplicate style properties | :star: |
|
|
268
303
|
| [svelte/no-dynamic-slot-name](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dynamic-slot-name/) | disallow dynamic slot name | :star::wrench: |
|
|
304
|
+
| [svelte/no-export-load-in-svelte-module-in-kit-pages](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-export-load-in-svelte-module-in-kit-pages/) | disallow exporting load functions in `*.svelte` module in Svelte Kit page components. | |
|
|
269
305
|
| [svelte/no-not-function-handler](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-not-function-handler/) | disallow use of not function in event handler | :star: |
|
|
270
306
|
| [svelte/no-object-in-text-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-object-in-text-mustaches/) | disallow objects in text mustache interpolation | :star: |
|
|
271
307
|
| [svelte/no-shorthand-style-property-overrides](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-shorthand-style-property-overrides/) | disallow shorthand style properties that override related longhand properties | :star: |
|
|
272
308
|
| [svelte/no-store-async](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-store-async/) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | |
|
|
273
309
|
| [svelte/no-unknown-style-directive-property](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
|
|
310
|
+
| [svelte/require-store-callbacks-use-set-param](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | store callbacks must use `set` param | |
|
|
311
|
+
| [svelte/require-store-reactive-access](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-store-reactive-access/) | disallow to use of the store itself as an operand. Need to use $ prefix or get function. | :wrench: |
|
|
274
312
|
| [svelte/valid-compile](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | :star: |
|
|
313
|
+
| [svelte/valid-prop-names-in-kit-pages](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-prop-names-in-kit-pages/) | disallow props other than data or errors in Svelte Kit page components. | |
|
|
275
314
|
|
|
276
315
|
## Security Vulnerability
|
|
277
316
|
|
|
@@ -327,7 +366,6 @@ These rules extend the rules provided by ESLint itself, or other plugins to work
|
|
|
327
366
|
|
|
328
367
|
| Rule ID | Description | |
|
|
329
368
|
|:--------|:------------|:---|
|
|
330
|
-
| [svelte/@typescript-eslint/no-unnecessary-condition](https://ota-meshi.github.io/eslint-plugin-svelte/rules/@typescript-eslint/no-unnecessary-condition/) | disallow conditionals where the type is always truthy or always falsy | :wrench: |
|
|
331
369
|
| [svelte/no-inner-declarations](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-inner-declarations/) | disallow variable or `function` declarations in nested blocks | :star: |
|
|
332
370
|
| [svelte/no-trailing-spaces](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-trailing-spaces/) | disallow trailing whitespace at the end of lines | :wrench: |
|
|
333
371
|
|
|
@@ -340,6 +378,15 @@ These rules relate to this plugin works:
|
|
|
340
378
|
| [svelte/comment-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/comment-directive/) | support comment-directives in HTML template | :star: |
|
|
341
379
|
| [svelte/system](https://ota-meshi.github.io/eslint-plugin-svelte/rules/system/) | system rule for working this plugin | :star: |
|
|
342
380
|
|
|
381
|
+
## Deprecated
|
|
382
|
+
|
|
383
|
+
- :warning: We're going to remove deprecated rules in the next major release. Please migrate to successor/new rules.
|
|
384
|
+
- :innocent: We don't fix bugs which are in deprecated rules since we don't have enough resources.
|
|
385
|
+
|
|
386
|
+
| Rule ID | Replaced by |
|
|
387
|
+
|:--------|:------------|
|
|
388
|
+
| [svelte/@typescript-eslint/no-unnecessary-condition](https://ota-meshi.github.io/eslint-plugin-svelte/rules/@typescript-eslint/no-unnecessary-condition/) | This rule is no longer needed when using svelte-eslint-parser>=v0.19.0. |
|
|
389
|
+
|
|
343
390
|
<!--RULES_TABLE_END-->
|
|
344
391
|
<!--RULES_SECTION_END-->
|
|
345
392
|
<!-- prettier-ignore-end -->
|
|
@@ -76,6 +76,10 @@ exports.default = (0, utils_1.createRule)("@typescript-eslint/no-unnecessary-con
|
|
|
76
76
|
noStrictNullCheck: "This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.",
|
|
77
77
|
},
|
|
78
78
|
type: "suggestion",
|
|
79
|
+
deprecated: true,
|
|
80
|
+
replacedBy: {
|
|
81
|
+
note: "This rule is no longer needed when using svelte-eslint-parser>=v0.19.0.",
|
|
82
|
+
},
|
|
79
83
|
},
|
|
80
84
|
create(context) {
|
|
81
85
|
const { allowConstantLoopConditions = false, allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing = false, } = (context.options[0] || {});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AST } from "svelte-eslint-parser";
|
|
2
|
-
import type
|
|
2
|
+
import type { TSESTree } from "@typescript-eslint/types";
|
|
3
3
|
declare type AnyToken = AST.Token | AST.Comment;
|
|
4
|
-
export declare function isWhitespace(token: AnyToken |
|
|
5
|
-
export declare function isNotWhitespace(token: AnyToken |
|
|
4
|
+
export declare function isWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
|
|
5
|
+
export declare function isNotWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
|
|
6
6
|
export {};
|
|
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.defineVisitor = void 0;
|
|
4
4
|
const commons_1 = require("./commons");
|
|
5
5
|
const eslint_utils_1 = require("eslint-utils");
|
|
6
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
6
7
|
function defineVisitor(context) {
|
|
7
8
|
const { sourceCode, offsets, options } = context;
|
|
8
9
|
function getRootLeft(node) {
|
|
9
10
|
let target = node;
|
|
10
|
-
let parent = getParent(target);
|
|
11
|
+
let parent = (0, ast_utils_1.getParent)(target);
|
|
11
12
|
while (parent &&
|
|
12
13
|
(parent.type === "AssignmentExpression" ||
|
|
13
14
|
parent.type === "AssignmentPattern" ||
|
|
@@ -18,7 +19,7 @@ function defineVisitor(context) {
|
|
|
18
19
|
break;
|
|
19
20
|
}
|
|
20
21
|
target = parent;
|
|
21
|
-
parent = getParent(target);
|
|
22
|
+
parent = (0, ast_utils_1.getParent)(target);
|
|
22
23
|
}
|
|
23
24
|
return target.left;
|
|
24
25
|
}
|
|
@@ -161,12 +162,12 @@ function defineVisitor(context) {
|
|
|
161
162
|
});
|
|
162
163
|
const alternateToken = sourceCode.getTokenAfter(colonToken);
|
|
163
164
|
let baseNode = node;
|
|
164
|
-
let parent = getParent(baseNode);
|
|
165
|
+
let parent = (0, ast_utils_1.getParent)(baseNode);
|
|
165
166
|
while (parent &&
|
|
166
167
|
parent.type === "ConditionalExpression" &&
|
|
167
168
|
parent.alternate === baseNode) {
|
|
168
169
|
baseNode = parent;
|
|
169
|
-
parent = getParent(baseNode);
|
|
170
|
+
parent = (0, ast_utils_1.getParent)(baseNode);
|
|
170
171
|
}
|
|
171
172
|
const baseToken = sourceCode.getFirstToken(baseNode);
|
|
172
173
|
offsets.setOffsetToken([questionToken, colonToken], 1, baseToken);
|
|
@@ -335,9 +336,9 @@ function defineVisitor(context) {
|
|
|
335
336
|
filter: eslint_utils_1.isOpeningParenToken,
|
|
336
337
|
includeComments: false,
|
|
337
338
|
});
|
|
338
|
-
let bodyBaseToken;
|
|
339
|
+
let bodyBaseToken = null;
|
|
339
340
|
if (firstToken.type === "Punctuator") {
|
|
340
|
-
bodyBaseToken = sourceCode.getFirstToken(getParent(node));
|
|
341
|
+
bodyBaseToken = sourceCode.getFirstToken((0, ast_utils_1.getParent)(node));
|
|
341
342
|
}
|
|
342
343
|
else {
|
|
343
344
|
let tokenOffset = 0;
|
|
@@ -735,9 +736,6 @@ function defineVisitor(context) {
|
|
|
735
736
|
};
|
|
736
737
|
}
|
|
737
738
|
exports.defineVisitor = defineVisitor;
|
|
738
|
-
function getParent(node) {
|
|
739
|
-
return node.parent || null;
|
|
740
|
-
}
|
|
741
739
|
function isOptionalToken(token) {
|
|
742
740
|
return token.type === "Punctuator" && token.value === "?.";
|
|
743
741
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const svelte_kit_1 = require("../utils/svelte-kit");
|
|
5
|
+
exports.default = (0, utils_1.createRule)("no-export-load-in-svelte-module-in-kit-pages", {
|
|
6
|
+
meta: {
|
|
7
|
+
docs: {
|
|
8
|
+
description: "disallow exporting load functions in `*.svelte` module in Svelte Kit page components.",
|
|
9
|
+
category: "Possible Errors",
|
|
10
|
+
recommended: false,
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
unexpected: "disallow exporting load functions in `*.svelte` module in Svelte Kit page components.",
|
|
15
|
+
},
|
|
16
|
+
type: "problem",
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
if (!(0, svelte_kit_1.isKitPageComponent)(context)) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
let isModule = false;
|
|
23
|
+
return {
|
|
24
|
+
[`Program > SvelteScriptElement > SvelteStartTag > SvelteAttribute[key.name="context"] > SvelteLiteral[value="module"]`]: () => {
|
|
25
|
+
isModule = true;
|
|
26
|
+
},
|
|
27
|
+
"Program > SvelteScriptElement:exit": () => {
|
|
28
|
+
isModule = false;
|
|
29
|
+
},
|
|
30
|
+
[`:matches(ExportNamedDeclaration > FunctionDeclaration, ExportNamedDeclaration > VariableDeclaration > VariableDeclarator) > Identifier.id[name="load"]`]: (node) => {
|
|
31
|
+
if (!isModule)
|
|
32
|
+
return {};
|
|
33
|
+
return context.report({
|
|
34
|
+
node,
|
|
35
|
+
loc: node.loc,
|
|
36
|
+
messageId: "unexpected",
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { TSESTree } from "@typescript-eslint/types";
|
|
2
2
|
import type { RuleContext } from "../../types";
|
|
3
3
|
declare type StoreName = "writable" | "readable" | "derived";
|
|
4
4
|
export declare function extractStoreReferences(context: RuleContext, storeNames?: StoreName[]): Generator<{
|
|
5
|
-
node:
|
|
5
|
+
node: TSESTree.CallExpression;
|
|
6
6
|
name: string;
|
|
7
7
|
}, void>;
|
|
8
|
+
export declare type StoreChecker = (node: TSESTree.Expression, options?: {
|
|
9
|
+
consistent?: boolean;
|
|
10
|
+
}) => boolean;
|
|
11
|
+
export declare function createStoreChecker(context: RuleContext): StoreChecker;
|
|
8
12
|
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractStoreReferences = void 0;
|
|
3
|
+
exports.createStoreChecker = exports.extractStoreReferences = void 0;
|
|
4
4
|
const eslint_utils_1 = require("eslint-utils");
|
|
5
|
+
const ts_utils_1 = require("../../utils/ts-utils");
|
|
6
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
5
7
|
function* extractStoreReferences(context, storeNames = ["writable", "readable", "derived"]) {
|
|
6
8
|
const referenceTracker = new eslint_utils_1.ReferenceTracker(context.getScope());
|
|
7
9
|
for (const { node, path } of referenceTracker.iterateEsmReferences({
|
|
@@ -25,3 +27,99 @@ function* extractStoreReferences(context, storeNames = ["writable", "readable",
|
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
exports.extractStoreReferences = extractStoreReferences;
|
|
30
|
+
function createStoreChecker(context) {
|
|
31
|
+
const tools = (0, ts_utils_1.getTypeScriptTools)(context);
|
|
32
|
+
const checker = tools
|
|
33
|
+
? createStoreCheckerForTS(tools)
|
|
34
|
+
: createStoreCheckerForES(context);
|
|
35
|
+
return (node, options) => checker(node, {
|
|
36
|
+
consistent: options?.consistent ?? false,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
exports.createStoreChecker = createStoreChecker;
|
|
40
|
+
function createStoreCheckerForES(context) {
|
|
41
|
+
const storeVariables = new Map();
|
|
42
|
+
for (const { node } of extractStoreReferences(context)) {
|
|
43
|
+
const parent = (0, ast_utils_1.getParent)(node);
|
|
44
|
+
if (!parent ||
|
|
45
|
+
parent.type !== "VariableDeclarator" ||
|
|
46
|
+
parent.id.type !== "Identifier") {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const decl = (0, ast_utils_1.getParent)(parent);
|
|
50
|
+
if (!decl || decl.type !== "VariableDeclaration") {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const variable = (0, ast_utils_1.findVariable)(context, parent.id);
|
|
54
|
+
if (variable) {
|
|
55
|
+
storeVariables.set(variable, { const: decl.kind === "const" });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return (node, options) => {
|
|
59
|
+
if (node.type !== "Identifier" || node.name.startsWith("$")) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const variable = (0, ast_utils_1.findVariable)(context, node);
|
|
63
|
+
if (!variable) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const info = storeVariables.get(variable);
|
|
67
|
+
if (!info) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return options.consistent ? info.const : true;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function createStoreCheckerForTS(tools) {
|
|
74
|
+
const { service } = tools;
|
|
75
|
+
const checker = service.program.getTypeChecker();
|
|
76
|
+
const tsNodeMap = service.esTreeNodeToTSNodeMap;
|
|
77
|
+
return (node, options) => {
|
|
78
|
+
const tsNode = tsNodeMap.get(node);
|
|
79
|
+
if (!tsNode) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const type = checker.getTypeAtLocation(tsNode);
|
|
83
|
+
return isStoreType(checker.getApparentType(type));
|
|
84
|
+
function isStoreType(type) {
|
|
85
|
+
return eachTypeCheck(type, options, (type) => {
|
|
86
|
+
const subscribe = type.getProperty("subscribe");
|
|
87
|
+
if (!subscribe) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const subscribeType = checker.getTypeOfSymbolAtLocation(subscribe, tsNode);
|
|
91
|
+
return isStoreSubscribeSignatureType(subscribeType);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function isStoreSubscribeSignatureType(type) {
|
|
95
|
+
return eachTypeCheck(type, options, (type) => {
|
|
96
|
+
for (const signature of type.getCallSignatures()) {
|
|
97
|
+
if (signature.parameters.length >= 2 &&
|
|
98
|
+
maybeFunctionSymbol(signature.parameters[0]) &&
|
|
99
|
+
maybeFunctionSymbol(signature.parameters[1])) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function maybeFunctionSymbol(param) {
|
|
107
|
+
const type = checker.getApparentType(checker.getTypeOfSymbolAtLocation(param, tsNode));
|
|
108
|
+
return maybeFunctionType(type);
|
|
109
|
+
}
|
|
110
|
+
function maybeFunctionType(type) {
|
|
111
|
+
return eachTypeCheck(type, { consistent: false }, (type) => {
|
|
112
|
+
return type.getCallSignatures().length > 0;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function eachTypeCheck(type, options, check) {
|
|
118
|
+
if (type.isUnion()) {
|
|
119
|
+
if (options.consistent) {
|
|
120
|
+
return type.types.every((t) => eachTypeCheck(t, options, check));
|
|
121
|
+
}
|
|
122
|
+
return type.types.some((t) => eachTypeCheck(t, options, check));
|
|
123
|
+
}
|
|
124
|
+
return check(type);
|
|
125
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const svelte_store_1 = require("./reference-helpers/svelte-store");
|
|
5
|
+
exports.default = (0, utils_1.createRule)("require-store-callbacks-use-set-param", {
|
|
6
|
+
meta: {
|
|
7
|
+
docs: {
|
|
8
|
+
description: "store callbacks must use `set` param",
|
|
9
|
+
category: "Possible Errors",
|
|
10
|
+
recommended: false,
|
|
11
|
+
},
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
unexpected: "Store callbacks must use `set` param.",
|
|
15
|
+
},
|
|
16
|
+
type: "suggestion",
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
return {
|
|
20
|
+
Program() {
|
|
21
|
+
for (const { node } of (0, svelte_store_1.extractStoreReferences)(context, [
|
|
22
|
+
"readable",
|
|
23
|
+
"writable",
|
|
24
|
+
])) {
|
|
25
|
+
const [_, fn] = node.arguments;
|
|
26
|
+
if (!fn ||
|
|
27
|
+
(fn.type !== "ArrowFunctionExpression" &&
|
|
28
|
+
fn.type !== "FunctionExpression")) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const param = fn.params[0];
|
|
32
|
+
if (!param || (param.type === "Identifier" && param.name !== "set")) {
|
|
33
|
+
context.report({
|
|
34
|
+
node: fn,
|
|
35
|
+
loc: fn.loc,
|
|
36
|
+
messageId: "unexpected",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../utils");
|
|
4
|
+
const svelte_store_1 = require("./reference-helpers/svelte-store");
|
|
5
|
+
exports.default = (0, utils_1.createRule)("require-store-reactive-access", {
|
|
6
|
+
meta: {
|
|
7
|
+
docs: {
|
|
8
|
+
description: "disallow to use of the store itself as an operand. Need to use $ prefix or get function.",
|
|
9
|
+
category: "Possible Errors",
|
|
10
|
+
recommended: false,
|
|
11
|
+
},
|
|
12
|
+
fixable: "code",
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
usingRawStoreInText: "Use the $ prefix or the get function to access reactive values instead of accessing the raw store.",
|
|
16
|
+
},
|
|
17
|
+
type: "problem",
|
|
18
|
+
},
|
|
19
|
+
create(context) {
|
|
20
|
+
if (!context.parserServices.isSvelte) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
const isStore = (0, svelte_store_1.createStoreChecker)(context);
|
|
24
|
+
function verifyExpression(node, options) {
|
|
25
|
+
if (!node)
|
|
26
|
+
return;
|
|
27
|
+
if (isStore(node, { consistent: options?.consistent })) {
|
|
28
|
+
context.report({
|
|
29
|
+
node,
|
|
30
|
+
messageId: "usingRawStoreInText",
|
|
31
|
+
fix: node.type === "Identifier" && !options?.disableFix
|
|
32
|
+
? (fixer) => fixer.insertTextBefore(node, "$")
|
|
33
|
+
: null,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
SvelteMustacheTag(node) {
|
|
39
|
+
if (canAcceptStoreMustache(node)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
verifyExpression(node.expression);
|
|
43
|
+
},
|
|
44
|
+
SvelteShorthandAttribute(node) {
|
|
45
|
+
if (canAcceptStoreAttributeElement(node.parent.parent)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
verifyExpression(node.value, { disableFix: true });
|
|
49
|
+
},
|
|
50
|
+
SvelteSpreadAttribute(node) {
|
|
51
|
+
verifyExpression(node.argument);
|
|
52
|
+
},
|
|
53
|
+
SvelteDirective(node) {
|
|
54
|
+
if (node.kind === "Action" ||
|
|
55
|
+
node.kind === "Animation" ||
|
|
56
|
+
node.kind === "Transition") {
|
|
57
|
+
if (node.key.name.type !== "Identifier") {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
verifyExpression(node.key.name);
|
|
61
|
+
}
|
|
62
|
+
else if (node.kind === "Binding") {
|
|
63
|
+
if (node.key.name.name !== "this" &&
|
|
64
|
+
canAcceptStoreAttributeElement(node.parent.parent)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
verifyExpression(node.expression, {
|
|
68
|
+
disableFix: node.shorthand,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else if (node.kind === "Class") {
|
|
72
|
+
verifyExpression(node.expression, {
|
|
73
|
+
disableFix: node.shorthand,
|
|
74
|
+
consistent: true,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else if (node.kind === "EventHandler") {
|
|
78
|
+
verifyExpression(node.expression);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
SvelteStyleDirective(node) {
|
|
82
|
+
if (node.shorthand && node.key.name.type === "Identifier") {
|
|
83
|
+
verifyExpression(node.key.name, {
|
|
84
|
+
disableFix: true,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
SvelteSpecialDirective(node) {
|
|
89
|
+
if (node.kind === "this") {
|
|
90
|
+
verifyExpression(node.expression);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"SvelteIfBlock, SvelteAwaitBlock"(node) {
|
|
94
|
+
verifyExpression(node.expression, {
|
|
95
|
+
consistent: true,
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
SvelteEachBlock(node) {
|
|
99
|
+
verifyExpression(node.expression);
|
|
100
|
+
},
|
|
101
|
+
["IfStatement, WhileStatement, DoWhileStatement, " +
|
|
102
|
+
"ConditionalExpression, ForStatement"](node) {
|
|
103
|
+
verifyExpression(node.test, {
|
|
104
|
+
consistent: true,
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
"ForInStatement, ForOfStatement"(node) {
|
|
108
|
+
verifyExpression(node.right);
|
|
109
|
+
},
|
|
110
|
+
SwitchStatement(node) {
|
|
111
|
+
verifyExpression(node.discriminant);
|
|
112
|
+
},
|
|
113
|
+
"CallExpression, NewExpression"(node) {
|
|
114
|
+
if (node.callee.type === "Super") {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
verifyExpression(node.callee);
|
|
118
|
+
},
|
|
119
|
+
UnaryExpression(node) {
|
|
120
|
+
verifyExpression(node.argument, {
|
|
121
|
+
consistent: node.operator === "!" || node.operator === "typeof",
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
"UpdateExpression, SpreadElement"(node) {
|
|
125
|
+
verifyExpression(node.argument);
|
|
126
|
+
},
|
|
127
|
+
AssignmentExpression(node) {
|
|
128
|
+
if (node.operator !== "=") {
|
|
129
|
+
if (node.left.type !== "ObjectPattern" &&
|
|
130
|
+
node.left.type !== "ArrayPattern") {
|
|
131
|
+
verifyExpression(node.left);
|
|
132
|
+
}
|
|
133
|
+
verifyExpression(node.right);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
BinaryExpression(node) {
|
|
137
|
+
if (node.left.type !== "PrivateIdentifier") {
|
|
138
|
+
verifyExpression(node.left, {
|
|
139
|
+
consistent: node.operator === "==" ||
|
|
140
|
+
node.operator === "!=" ||
|
|
141
|
+
node.operator === "===" ||
|
|
142
|
+
node.operator === "!==",
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
verifyExpression(node.right, {
|
|
146
|
+
consistent: node.operator === "==" ||
|
|
147
|
+
node.operator === "!=" ||
|
|
148
|
+
node.operator === "===" ||
|
|
149
|
+
node.operator === "!==",
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
LogicalExpression(node) {
|
|
153
|
+
verifyExpression(node.left, {
|
|
154
|
+
consistent: true,
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
TemplateLiteral(node) {
|
|
158
|
+
for (const expr of node.expressions) {
|
|
159
|
+
verifyExpression(expr);
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
TaggedTemplateExpression(node) {
|
|
163
|
+
verifyExpression(node.tag);
|
|
164
|
+
},
|
|
165
|
+
"Property, PropertyDefinition, MethodDefinition"(node) {
|
|
166
|
+
if (node.key.type === "PrivateIdentifier" || !node.computed) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
verifyExpression(node.key);
|
|
170
|
+
},
|
|
171
|
+
ImportExpression(node) {
|
|
172
|
+
verifyExpression(node.source);
|
|
173
|
+
},
|
|
174
|
+
AwaitExpression(node) {
|
|
175
|
+
verifyExpression(node.argument, {
|
|
176
|
+
consistent: true,
|
|
177
|
+
});
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
function canAcceptStoreMustache(node) {
|
|
181
|
+
if (node.parent.type !== "SvelteAttribute") {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const attr = node.parent;
|
|
185
|
+
if (attr.value.length > 1) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (attr.key.name.startsWith("--")) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
const element = attr.parent.parent;
|
|
192
|
+
return canAcceptStoreAttributeElement(element);
|
|
193
|
+
}
|
|
194
|
+
function canAcceptStoreAttributeElement(node) {
|
|
195
|
+
if (node.type !== "SvelteElement") {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
if (node.kind === "html" ||
|
|
199
|
+
(node.kind === "special" && node.name.name === "svelte:element")) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
});
|