eslint-plugin-svelte 3.3.3 → 3.4.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 +3 -3
- package/lib/main.d.ts +1 -1
- package/lib/meta.d.ts +1 -1
- package/lib/meta.js +1 -1
- package/lib/rules/derived-has-same-inputs-outputs.js +36 -3
- package/lib/rules/no-at-debug-tags.js +10 -2
- package/lib/rules/no-unused-props.js +62 -37
- package/lib/rules/require-store-callbacks-use-set-param.js +40 -2
- package/lib/utils/ast-utils.d.ts +11 -0
- package/lib/utils/ast-utils.js +25 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -272,7 +272,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
|
|
|
272
272
|
| [svelte/no-shorthand-style-property-overrides](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-shorthand-style-property-overrides/) | disallow shorthand style properties that override related longhand properties | :star: |
|
|
273
273
|
| [svelte/no-store-async](https://sveltejs.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 | :star: |
|
|
274
274
|
| [svelte/no-unknown-style-directive-property](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
|
|
275
|
-
| [svelte/require-store-callbacks-use-set-param](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | store callbacks must use `set` param |
|
|
275
|
+
| [svelte/require-store-callbacks-use-set-param](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | store callbacks must use `set` param | :bulb: |
|
|
276
276
|
| [svelte/require-store-reactive-access](https://sveltejs.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. | :star::wrench: |
|
|
277
277
|
| [svelte/valid-compile](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | |
|
|
278
278
|
| [svelte/valid-style-parse](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-style-parse/) | require valid style element parsing | |
|
|
@@ -294,7 +294,7 @@ These rules relate to better ways of doing things to help you avoid problems:
|
|
|
294
294
|
|:--------|:------------|:---|
|
|
295
295
|
| [svelte/block-lang](https://sveltejs.github.io/eslint-plugin-svelte/rules/block-lang/) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | :bulb: |
|
|
296
296
|
| [svelte/button-has-type](https://sveltejs.github.io/eslint-plugin-svelte/rules/button-has-type/) | disallow usage of button without an explicit type attribute | |
|
|
297
|
-
| [svelte/no-at-debug-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-debug-tags/) | disallow the use of `{@debug}` | :star: |
|
|
297
|
+
| [svelte/no-at-debug-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-debug-tags/) | disallow the use of `{@debug}` | :star::bulb: |
|
|
298
298
|
| [svelte/no-ignored-unsubscribe](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-ignored-unsubscribe/) | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores. | |
|
|
299
299
|
| [svelte/no-immutable-reactive-statements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-immutable-reactive-statements/) | disallow reactive statements that don't reference reactive values. | :star: |
|
|
300
300
|
| [svelte/no-inline-styles](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inline-styles/) | disallow attributes and directives that produce inline styles | |
|
|
@@ -323,7 +323,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
|
|
|
323
323
|
| Rule ID | Description | |
|
|
324
324
|
|:--------|:------------|:---|
|
|
325
325
|
| [svelte/consistent-selector-style](https://sveltejs.github.io/eslint-plugin-svelte/rules/consistent-selector-style/) | enforce a consistent style for CSS selectors | |
|
|
326
|
-
| [svelte/derived-has-same-inputs-outputs](https://sveltejs.github.io/eslint-plugin-svelte/rules/derived-has-same-inputs-outputs/) | derived store should use same variable names between values and callback |
|
|
326
|
+
| [svelte/derived-has-same-inputs-outputs](https://sveltejs.github.io/eslint-plugin-svelte/rules/derived-has-same-inputs-outputs/) | derived store should use same variable names between values and callback | :bulb: |
|
|
327
327
|
| [svelte/first-attribute-linebreak](https://sveltejs.github.io/eslint-plugin-svelte/rules/first-attribute-linebreak/) | enforce the location of first attribute | :wrench: |
|
|
328
328
|
| [svelte/html-closing-bracket-new-line](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-new-line/) | Require or disallow a line break before tag's closing brackets | :wrench: |
|
|
329
329
|
| [svelte/html-closing-bracket-spacing](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-spacing/) | require or disallow a space before tag's closing brackets | :wrench: |
|
package/lib/main.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare const configs: {
|
|
|
14
14
|
export declare const rules: Record<string, Rule.RuleModule>;
|
|
15
15
|
export declare const meta: {
|
|
16
16
|
name: "eslint-plugin-svelte";
|
|
17
|
-
version: "3.
|
|
17
|
+
version: "3.4.0";
|
|
18
18
|
};
|
|
19
19
|
export declare const processors: {
|
|
20
20
|
'.svelte': typeof processor;
|
package/lib/meta.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const name = "eslint-plugin-svelte";
|
|
2
|
-
export declare const version = "3.
|
|
2
|
+
export declare const version = "3.4.0";
|
package/lib/meta.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { createRule } from '../utils/index.js';
|
|
2
2
|
import { extractStoreReferences } from './reference-helpers/svelte-store.js';
|
|
3
|
+
import { findVariableForReplacement } from '../utils/ast-utils.js';
|
|
4
|
+
function createFixer(node, variable, name) {
|
|
5
|
+
return function* fix(fixer) {
|
|
6
|
+
yield fixer.replaceText(node, name);
|
|
7
|
+
if (variable) {
|
|
8
|
+
for (const ref of variable.references) {
|
|
9
|
+
yield fixer.replaceText(ref.identifier, name);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
3
14
|
export default createRule('derived-has-same-inputs-outputs', {
|
|
4
15
|
meta: {
|
|
5
16
|
docs: {
|
|
@@ -8,9 +19,11 @@ export default createRule('derived-has-same-inputs-outputs', {
|
|
|
8
19
|
recommended: false,
|
|
9
20
|
conflictWithPrettier: false
|
|
10
21
|
},
|
|
22
|
+
hasSuggestions: true,
|
|
11
23
|
schema: [],
|
|
12
24
|
messages: {
|
|
13
|
-
unexpected: "The argument name should be '{{name}}'."
|
|
25
|
+
unexpected: "The argument name should be '{{name}}'.",
|
|
26
|
+
renameParam: 'Rename the parameter from {{oldName}} to {{newName}}.'
|
|
14
27
|
},
|
|
15
28
|
type: 'suggestion'
|
|
16
29
|
},
|
|
@@ -33,11 +46,21 @@ export default createRule('derived-has-same-inputs-outputs', {
|
|
|
33
46
|
return;
|
|
34
47
|
const expectedName = `$${args.name}`;
|
|
35
48
|
if (expectedName !== fnParam.name) {
|
|
49
|
+
const { hasConflict, variable } = findVariableForReplacement(context, fn.body, fnParam.name, expectedName);
|
|
36
50
|
context.report({
|
|
37
51
|
node: fn,
|
|
38
52
|
loc: fnParam.loc,
|
|
39
53
|
messageId: 'unexpected',
|
|
40
|
-
data: { name: expectedName }
|
|
54
|
+
data: { name: expectedName },
|
|
55
|
+
suggest: hasConflict
|
|
56
|
+
? undefined
|
|
57
|
+
: [
|
|
58
|
+
{
|
|
59
|
+
messageId: 'renameParam',
|
|
60
|
+
data: { oldName: fnParam.name, newName: expectedName },
|
|
61
|
+
fix: createFixer(fnParam, variable, expectedName)
|
|
62
|
+
}
|
|
63
|
+
]
|
|
41
64
|
});
|
|
42
65
|
}
|
|
43
66
|
}
|
|
@@ -57,11 +80,21 @@ export default createRule('derived-has-same-inputs-outputs', {
|
|
|
57
80
|
if (element && element.type === 'Identifier' && argName) {
|
|
58
81
|
const expectedName = `$${argName}`;
|
|
59
82
|
if (expectedName !== element.name) {
|
|
83
|
+
const { hasConflict, variable } = findVariableForReplacement(context, fn.body, element.name, expectedName);
|
|
60
84
|
context.report({
|
|
61
85
|
node: fn,
|
|
62
86
|
loc: element.loc,
|
|
63
87
|
messageId: 'unexpected',
|
|
64
|
-
data: { name: expectedName }
|
|
88
|
+
data: { name: expectedName },
|
|
89
|
+
suggest: hasConflict
|
|
90
|
+
? undefined
|
|
91
|
+
: [
|
|
92
|
+
{
|
|
93
|
+
messageId: 'renameParam',
|
|
94
|
+
data: { oldName: element.name, newName: expectedName },
|
|
95
|
+
fix: createFixer(element, variable, expectedName)
|
|
96
|
+
}
|
|
97
|
+
]
|
|
65
98
|
});
|
|
66
99
|
}
|
|
67
100
|
}
|
|
@@ -7,9 +7,11 @@ export default createRule('no-at-debug-tags', {
|
|
|
7
7
|
recommended: true,
|
|
8
8
|
default: 'warn'
|
|
9
9
|
},
|
|
10
|
+
hasSuggestions: true,
|
|
10
11
|
schema: [],
|
|
11
12
|
messages: {
|
|
12
|
-
unexpected: 'Unexpected `{@debug}`.'
|
|
13
|
+
unexpected: 'Unexpected `{@debug}`.',
|
|
14
|
+
suggestRemove: 'Remove `{@debug}` from the source'
|
|
13
15
|
},
|
|
14
16
|
type: 'problem'
|
|
15
17
|
},
|
|
@@ -18,7 +20,13 @@ export default createRule('no-at-debug-tags', {
|
|
|
18
20
|
SvelteDebugTag(node) {
|
|
19
21
|
context.report({
|
|
20
22
|
node,
|
|
21
|
-
messageId: 'unexpected'
|
|
23
|
+
messageId: 'unexpected',
|
|
24
|
+
suggest: [
|
|
25
|
+
{
|
|
26
|
+
messageId: 'suggestRemove',
|
|
27
|
+
fix: (fixer) => fixer.remove(node)
|
|
28
|
+
}
|
|
29
|
+
]
|
|
22
30
|
});
|
|
23
31
|
}
|
|
24
32
|
};
|
|
@@ -127,21 +127,21 @@ export default createRule('no-unused-props', {
|
|
|
127
127
|
/**
|
|
128
128
|
* Finds all property access paths for a given variable.
|
|
129
129
|
*/
|
|
130
|
-
function
|
|
130
|
+
function getUsedNestedPropertyPathsArray(node) {
|
|
131
131
|
const variable = findVariable(context, node);
|
|
132
132
|
if (!variable)
|
|
133
133
|
return [];
|
|
134
|
-
const
|
|
134
|
+
const pathsArray = [];
|
|
135
135
|
for (const reference of variable.references) {
|
|
136
136
|
if ('identifier' in reference &&
|
|
137
137
|
reference.identifier.type === 'Identifier' &&
|
|
138
138
|
(reference.identifier.range[0] !== node.range[0] ||
|
|
139
139
|
reference.identifier.range[1] !== node.range[1])) {
|
|
140
140
|
const referencePath = getPropertyPath(reference.identifier);
|
|
141
|
-
|
|
141
|
+
pathsArray.push(referencePath);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
return
|
|
144
|
+
return pathsArray;
|
|
145
145
|
}
|
|
146
146
|
/**
|
|
147
147
|
* Checks if a property is from TypeScript's built-in type definitions.
|
|
@@ -157,7 +157,7 @@ export default createRule('no-unused-props', {
|
|
|
157
157
|
return false;
|
|
158
158
|
return sourceFile.fileName.includes('node_modules/typescript/lib/');
|
|
159
159
|
}
|
|
160
|
-
function
|
|
160
|
+
function getUsedPropertyNamesFromPattern(pattern) {
|
|
161
161
|
const usedProps = new Set();
|
|
162
162
|
for (const prop of pattern.properties) {
|
|
163
163
|
if (prop.type === 'Property' && prop.key.type === 'Identifier') {
|
|
@@ -192,24 +192,32 @@ export default createRule('no-unused-props', {
|
|
|
192
192
|
/**
|
|
193
193
|
* Recursively checks for unused properties in a type.
|
|
194
194
|
*/
|
|
195
|
-
function checkUnusedProperties(
|
|
195
|
+
function checkUnusedProperties({ propsType, usedPropertyPaths, declaredPropertyNames, reportNode, parentPath, checkedPropsTypes, reportedPropertyPaths }) {
|
|
196
196
|
// Skip checking if the type itself is a class
|
|
197
|
-
if (isClassType(
|
|
197
|
+
if (isClassType(propsType))
|
|
198
198
|
return;
|
|
199
|
-
const typeStr = typeChecker.typeToString(
|
|
200
|
-
if (
|
|
199
|
+
const typeStr = typeChecker.typeToString(propsType);
|
|
200
|
+
if (checkedPropsTypes.has(typeStr))
|
|
201
201
|
return;
|
|
202
|
-
|
|
203
|
-
if (shouldIgnoreType(
|
|
202
|
+
checkedPropsTypes.add(typeStr);
|
|
203
|
+
if (shouldIgnoreType(propsType))
|
|
204
204
|
return;
|
|
205
|
-
const properties = typeChecker.getPropertiesOfType(
|
|
206
|
-
const
|
|
207
|
-
if (!properties.length && (!
|
|
205
|
+
const properties = typeChecker.getPropertiesOfType(propsType);
|
|
206
|
+
const propsBaseTypes = propsType.getBaseTypes();
|
|
207
|
+
if (!properties.length && (!propsBaseTypes || propsBaseTypes.length === 0)) {
|
|
208
208
|
return;
|
|
209
209
|
}
|
|
210
|
-
if (
|
|
211
|
-
for (const
|
|
212
|
-
checkUnusedProperties(
|
|
210
|
+
if (propsBaseTypes) {
|
|
211
|
+
for (const propsBaseType of propsBaseTypes) {
|
|
212
|
+
checkUnusedProperties({
|
|
213
|
+
propsType: propsBaseType,
|
|
214
|
+
usedPropertyPaths,
|
|
215
|
+
declaredPropertyNames,
|
|
216
|
+
reportNode,
|
|
217
|
+
parentPath,
|
|
218
|
+
checkedPropsTypes,
|
|
219
|
+
reportedPropertyPaths
|
|
220
|
+
});
|
|
213
221
|
}
|
|
214
222
|
}
|
|
215
223
|
for (const prop of properties) {
|
|
@@ -222,20 +230,19 @@ export default createRule('no-unused-props', {
|
|
|
222
230
|
continue;
|
|
223
231
|
const currentPath = [...parentPath, propName];
|
|
224
232
|
const currentPathStr = [...parentPath, propName].join('.');
|
|
225
|
-
if (
|
|
233
|
+
if (reportedPropertyPaths.has(currentPathStr))
|
|
226
234
|
continue;
|
|
227
235
|
const propType = typeChecker.getTypeOfSymbol(prop);
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
const isUsedInPath = joinedUsedPaths.some((path) => {
|
|
236
|
+
const isUsedThisInPath = usedPropertyPaths.includes(currentPathStr);
|
|
237
|
+
const isUsedInPath = usedPropertyPaths.some((path) => {
|
|
231
238
|
return path.startsWith(`${currentPathStr}.`);
|
|
232
239
|
});
|
|
233
240
|
if (isUsedThisInPath && !isUsedInPath) {
|
|
234
241
|
continue;
|
|
235
242
|
}
|
|
236
|
-
const isUsedInProps =
|
|
243
|
+
const isUsedInProps = declaredPropertyNames.has(propName);
|
|
237
244
|
if (!isUsedInPath && !isUsedInProps) {
|
|
238
|
-
|
|
245
|
+
reportedPropertyPaths.add(currentPathStr);
|
|
239
246
|
context.report({
|
|
240
247
|
node: reportNode,
|
|
241
248
|
messageId: parentPath.length ? 'unusedNestedProp' : 'unusedProp',
|
|
@@ -246,19 +253,27 @@ export default createRule('no-unused-props', {
|
|
|
246
253
|
});
|
|
247
254
|
continue;
|
|
248
255
|
}
|
|
249
|
-
const isUsedNested =
|
|
256
|
+
const isUsedNested = usedPropertyPaths.some((path) => {
|
|
250
257
|
return path.startsWith(`${currentPathStr}.`);
|
|
251
258
|
});
|
|
252
259
|
if (isUsedNested || isUsedInProps) {
|
|
253
|
-
checkUnusedProperties(
|
|
260
|
+
checkUnusedProperties({
|
|
261
|
+
propsType: propType,
|
|
262
|
+
usedPropertyPaths,
|
|
263
|
+
declaredPropertyNames,
|
|
264
|
+
reportNode,
|
|
265
|
+
parentPath: currentPath,
|
|
266
|
+
checkedPropsTypes,
|
|
267
|
+
reportedPropertyPaths
|
|
268
|
+
});
|
|
254
269
|
}
|
|
255
270
|
}
|
|
256
271
|
// Check for unused index signatures only at the root level
|
|
257
272
|
if (parentPath.length === 0) {
|
|
258
|
-
const indexType =
|
|
259
|
-
const numberIndexType =
|
|
273
|
+
const indexType = propsType.getStringIndexType();
|
|
274
|
+
const numberIndexType = propsType.getNumberIndexType();
|
|
260
275
|
const hasIndexSignature = Boolean(indexType) || Boolean(numberIndexType);
|
|
261
|
-
if (hasIndexSignature && !hasRestElement(
|
|
276
|
+
if (hasIndexSignature && !hasRestElement(declaredPropertyNames)) {
|
|
262
277
|
context.report({
|
|
263
278
|
node: reportNode,
|
|
264
279
|
messageId: 'unusedIndexSignature'
|
|
@@ -296,12 +311,12 @@ export default createRule('no-unused-props', {
|
|
|
296
311
|
const tsNode = tools.service.esTreeNodeToTSNodeMap.get(node);
|
|
297
312
|
if (!tsNode || !tsNode.type)
|
|
298
313
|
return;
|
|
299
|
-
const
|
|
300
|
-
let
|
|
301
|
-
let
|
|
314
|
+
const propsType = typeChecker.getTypeFromTypeNode(tsNode.type);
|
|
315
|
+
let usedPropertyPathsArray = [];
|
|
316
|
+
let declaredPropertyNames = new Set();
|
|
302
317
|
if (node.id.type === 'ObjectPattern') {
|
|
303
|
-
|
|
304
|
-
if (
|
|
318
|
+
declaredPropertyNames = getUsedPropertyNamesFromPattern(node.id);
|
|
319
|
+
if (declaredPropertyNames.size === 0)
|
|
305
320
|
return;
|
|
306
321
|
const identifiers = [];
|
|
307
322
|
for (const p of node.id.properties) {
|
|
@@ -316,14 +331,24 @@ export default createRule('no-unused-props', {
|
|
|
316
331
|
}
|
|
317
332
|
}
|
|
318
333
|
for (const identifier of identifiers) {
|
|
319
|
-
const paths =
|
|
320
|
-
|
|
334
|
+
const paths = getUsedNestedPropertyPathsArray(identifier);
|
|
335
|
+
usedPropertyPathsArray.push(...paths.map((path) => [identifier.name, ...path]));
|
|
321
336
|
}
|
|
322
337
|
}
|
|
323
338
|
else if (node.id.type === 'Identifier') {
|
|
324
|
-
|
|
339
|
+
usedPropertyPathsArray = getUsedNestedPropertyPathsArray(node.id);
|
|
325
340
|
}
|
|
326
|
-
checkUnusedProperties(
|
|
341
|
+
checkUnusedProperties({
|
|
342
|
+
propsType,
|
|
343
|
+
usedPropertyPaths: normalizeUsedPaths(usedPropertyPathsArray).map((pathArray) => {
|
|
344
|
+
return pathArray.join('.');
|
|
345
|
+
}),
|
|
346
|
+
declaredPropertyNames,
|
|
347
|
+
reportNode: node.id,
|
|
348
|
+
parentPath: [],
|
|
349
|
+
checkedPropsTypes: new Set(),
|
|
350
|
+
reportedPropertyPaths: new Set()
|
|
351
|
+
});
|
|
327
352
|
}
|
|
328
353
|
};
|
|
329
354
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { findVariableForReplacement } from '../utils/ast-utils.js';
|
|
1
2
|
import { createRule } from '../utils/index.js';
|
|
2
3
|
import { extractStoreReferences } from './reference-helpers/svelte-store.js';
|
|
4
|
+
import { getSourceCode } from '../utils/compat.js';
|
|
3
5
|
export default createRule('require-store-callbacks-use-set-param', {
|
|
4
6
|
meta: {
|
|
5
7
|
docs: {
|
|
@@ -7,9 +9,12 @@ export default createRule('require-store-callbacks-use-set-param', {
|
|
|
7
9
|
category: 'Possible Errors',
|
|
8
10
|
recommended: false
|
|
9
11
|
},
|
|
12
|
+
hasSuggestions: true,
|
|
10
13
|
schema: [],
|
|
11
14
|
messages: {
|
|
12
|
-
unexpected: 'Store callbacks must use `set` param.'
|
|
15
|
+
unexpected: 'Store callbacks must use `set` param.',
|
|
16
|
+
updateParam: 'Rename parameter from {{oldName}} to `set`.',
|
|
17
|
+
addParam: 'Add a `set` parameter.'
|
|
13
18
|
},
|
|
14
19
|
type: 'suggestion'
|
|
15
20
|
},
|
|
@@ -23,10 +28,43 @@ export default createRule('require-store-callbacks-use-set-param', {
|
|
|
23
28
|
}
|
|
24
29
|
const param = fn.params[0];
|
|
25
30
|
if (!param || (param.type === 'Identifier' && param.name !== 'set')) {
|
|
31
|
+
const { hasConflict, variable } = findVariableForReplacement(context, fn.body, param ? param.name : null, 'set');
|
|
32
|
+
const suggest = [];
|
|
33
|
+
if (!hasConflict) {
|
|
34
|
+
if (param) {
|
|
35
|
+
suggest.push({
|
|
36
|
+
messageId: 'updateParam',
|
|
37
|
+
data: { oldName: param.name },
|
|
38
|
+
*fix(fixer) {
|
|
39
|
+
yield fixer.replaceText(param, 'set');
|
|
40
|
+
if (variable) {
|
|
41
|
+
for (const ref of variable.references) {
|
|
42
|
+
yield fixer.replaceText(ref.identifier, 'set');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const token = getSourceCode(context).getTokenBefore(fn.body, {
|
|
50
|
+
filter: (token) => token.type === 'Punctuator' && token.value === '(',
|
|
51
|
+
includeComments: false
|
|
52
|
+
});
|
|
53
|
+
if (token) {
|
|
54
|
+
suggest.push({
|
|
55
|
+
messageId: 'addParam',
|
|
56
|
+
fix(fixer) {
|
|
57
|
+
return fixer.insertTextAfter(token, 'set');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
26
63
|
context.report({
|
|
27
64
|
node: fn,
|
|
28
65
|
loc: fn.loc,
|
|
29
|
-
messageId: 'unexpected'
|
|
66
|
+
messageId: 'unexpected',
|
|
67
|
+
suggest
|
|
30
68
|
});
|
|
31
69
|
}
|
|
32
70
|
}
|
package/lib/utils/ast-utils.d.ts
CHANGED
|
@@ -113,3 +113,14 @@ export declare function isSvgElement(node: SvAST.SvelteElement): boolean;
|
|
|
113
113
|
export declare function isMathMLElement(node: SvAST.SvelteElement): boolean;
|
|
114
114
|
/** Checks whether the given identifier node is used as an expression. */
|
|
115
115
|
export declare function isExpressionIdentifier(node: TSESTree.Identifier): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Finds the variable for a given name in the specified node's scope.
|
|
118
|
+
* Also determines if the replacement name is already in use.
|
|
119
|
+
*
|
|
120
|
+
* If the `name` is set to null, this assumes you're adding a new variable
|
|
121
|
+
* and reports if it is already in use.
|
|
122
|
+
*/
|
|
123
|
+
export declare function findVariableForReplacement(context: RuleContext, node: TSESTree.Node, name: string | null, replacementName: string): {
|
|
124
|
+
hasConflict: boolean;
|
|
125
|
+
variable: Variable | null;
|
|
126
|
+
};
|
package/lib/utils/ast-utils.js
CHANGED
|
@@ -471,3 +471,28 @@ function getSimpleNameFromNode(node, context) {
|
|
|
471
471
|
}
|
|
472
472
|
return getSourceCode(context).getText(node);
|
|
473
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* Finds the variable for a given name in the specified node's scope.
|
|
476
|
+
* Also determines if the replacement name is already in use.
|
|
477
|
+
*
|
|
478
|
+
* If the `name` is set to null, this assumes you're adding a new variable
|
|
479
|
+
* and reports if it is already in use.
|
|
480
|
+
*/
|
|
481
|
+
export function findVariableForReplacement(context, node, name, replacementName) {
|
|
482
|
+
const scope = getScope(context, node);
|
|
483
|
+
let variable = null;
|
|
484
|
+
for (const ref of scope.references) {
|
|
485
|
+
if (ref.identifier.name === replacementName) {
|
|
486
|
+
return { hasConflict: true, variable: null };
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
for (const v of scope.variables) {
|
|
490
|
+
if (v.name === replacementName) {
|
|
491
|
+
return { hasConflict: true, variable: null };
|
|
492
|
+
}
|
|
493
|
+
if (v.name === name) {
|
|
494
|
+
variable = v;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return { hasConflict: false, variable };
|
|
498
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-svelte",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "ESLint plugin for Svelte using AST",
|
|
5
5
|
"repository": "git+https://github.com/sveltejs/eslint-plugin-svelte.git",
|
|
6
6
|
"homepage": "https://sveltejs.github.io/eslint-plugin-svelte",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"postcss-load-config": "^3.1.4",
|
|
42
42
|
"postcss-safe-parser": "^7.0.0",
|
|
43
43
|
"semver": "^7.6.3",
|
|
44
|
-
"svelte-eslint-parser": "^1.
|
|
44
|
+
"svelte-eslint-parser": "^1.1.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@babel/core": "^7.26.0",
|