diff --git a/.changeset/long-ghosts-prove.md b/.changeset/long-ghosts-prove.md new file mode 100644 index 000000000..da44ed049 --- /dev/null +++ b/.changeset/long-ghosts-prove.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-svelte': minor +--- + +feat(prefer-svelte-reactivity): ignoring variables encapsulated in functions diff --git a/.changeset/lovely-carpets-clean.md b/.changeset/lovely-carpets-clean.md new file mode 100644 index 000000000..1eea7e559 --- /dev/null +++ b/.changeset/lovely-carpets-clean.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-svelte': minor +--- + +feat(prefer-svelte-reactivity): reporting public properties diff --git a/.changeset/lovely-moments-kneel.md b/.changeset/lovely-moments-kneel.md new file mode 100644 index 000000000..b05d01385 --- /dev/null +++ b/.changeset/lovely-moments-kneel.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-svelte': minor +--- + +feat(prefer-svelte-reactivity): reporting returned variables diff --git a/docs/rules/prefer-svelte-reactivity.md b/docs/rules/prefer-svelte-reactivity.md index 4a5edf986..22b191ba7 100644 --- a/docs/rules/prefer-svelte-reactivity.md +++ b/docs/rules/prefer-svelte-reactivity.md @@ -105,7 +105,18 @@ export default e; ## :wrench: Options -Nothing. +```json +{ + "svelte/prefer-svelte-reactivity": [ + "error", + { + "ignoreEncapsulatedLocalVariables": true + } + ] +} +``` + +- `ignoreEncapsulatedLocalVariables` ... Whether to ignore variables that are defined inside a function and aren't returned, thus being encapsulated in the function. Default `true`. ## :books: Further Reading diff --git a/packages/eslint-plugin-svelte/src/rule-types.ts b/packages/eslint-plugin-svelte/src/rule-types.ts index f4fd5c81d..81ba9c8fd 100644 --- a/packages/eslint-plugin-svelte/src/rule-types.ts +++ b/packages/eslint-plugin-svelte/src/rule-types.ts @@ -320,7 +320,7 @@ export interface RuleOptions { * disallow using mutable instances of built-in classes where a reactive alternative is provided by svelte/reactivity * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-svelte-reactivity/ */ - 'svelte/prefer-svelte-reactivity'?: Linter.RuleEntry<[]> + 'svelte/prefer-svelte-reactivity'?: Linter.RuleEntry /** * Prefer using writable $derived instead of $state and $effect * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-writable-derived/ @@ -580,6 +580,10 @@ type SveltePreferConst = []|[{ excludedRunes?: string[] [k: string]: unknown | undefined }] +// ----- svelte/prefer-svelte-reactivity ----- +type SveltePreferSvelteReactivity = []|[{ + ignoreEncapsulatedLocalVariables?: boolean +}] // ----- svelte/require-event-prefix ----- type SvelteRequireEventPrefix = []|[{ checkAsyncFunctions?: boolean diff --git a/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts b/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts index 7118b054d..8a192eb08 100644 --- a/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts +++ b/packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts @@ -4,6 +4,13 @@ import type { TSESTree } from '@typescript-eslint/types'; import { findVariable, isIn } from '../utils/ast-utils.js'; import { getSvelteContext } from '../utils/svelte-context.js'; +type FunctionLike = + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionDeclaration + | TSESTree.MethodDefinition; + +type VariableLike = TSESTree.VariableDeclarator | TSESTree.PropertyDefinition; + export default createRule('prefer-svelte-reactivity', { meta: { docs: { @@ -12,7 +19,18 @@ export default createRule('prefer-svelte-reactivity', { category: 'Possible Errors', recommended: true }, - schema: [], + schema: [ + { + type: 'object', + properties: { + ignoreEncapsulatedLocalVariables: { + type: 'boolean', + default: true + } + }, + additionalProperties: false + } + ], messages: { mutableDateUsed: 'Found a mutable instance of the built-in Date class. Use SvelteDate instead.', @@ -31,7 +49,162 @@ export default createRule('prefer-svelte-reactivity', { ] }, create(context) { + const ignoreEncapsulatedLocalVariables = + context.options[0]?.ignoreEncapsulatedLocalVariables ?? true; + const returnedFunctionCalls: Map = new Map(); + const returnedVariables: Map = new Map(); const exportedVars: TSESTree.Node[] = []; + + function recordReturnedIdentifiers(node: TSESTree.Identifier | TSESTree.PrivateIdentifier) { + function recordVariable(enclosingFunction: FunctionLike, variable: VariableLike): void { + if (variable === null) { + return; + } + if (!returnedVariables.has(enclosingFunction)) { + returnedVariables.set(enclosingFunction, []); + } + returnedVariables.get(enclosingFunction)?.push(variable); + } + + function recordFunctionCall( + enclosingFunction: FunctionLike, + functionCall: TSESTree.MethodDefinition + ): void { + if (functionCall === null) { + return; + } + if (!returnedFunctionCalls.has(enclosingFunction)) { + returnedFunctionCalls.set(enclosingFunction, []); + } + returnedFunctionCalls.get(enclosingFunction)?.push(functionCall); + } + + const enclosingReturn = findEnclosingReturn(node); + if (enclosingReturn === null) { + return; + } + const enclosingFunction = findEnclosingFunction(enclosingReturn); + if (enclosingFunction === null) { + return; + } + if (node.parent.type === 'MemberExpression') { + const enclosingClassBody = findEnclosingClassBody(node); + for (const classElement of enclosingClassBody?.body ?? []) { + if ( + classElement.type === 'PropertyDefinition' && + (classElement.key.type === 'Identifier' || + classElement.key.type === 'PrivateIdentifier') && + node.name === classElement.key.name + ) { + recordVariable(enclosingFunction, classElement); + } + if ( + classElement.type === 'MethodDefinition' && + (classElement.key.type === 'Identifier' || + classElement.key.type === 'PrivateIdentifier') && + node.name === classElement.key.name + ) { + recordFunctionCall(enclosingFunction, classElement); + } + } + } else if (node.type === 'Identifier') { + const variable = findVariable(context, node); + if ( + variable !== null && + variable.identifiers.length > 0 && + variable.identifiers[0].parent.type === 'VariableDeclarator' + ) { + recordVariable(enclosingFunction, variable.identifiers[0].parent); + } + } + } + + function checkNonReactiveUsage( + node: TSESTree.Node, + objectType: 'Date' | 'Map' | 'Set' | 'URL' | 'URLSearchParams', + referenceTracker: ReferenceTracker + ) { + const messageId = `mutable${objectType}Used`; + + function report() { + context.report({ + messageId, + node + }); + } + + // Report all values directly returned from functions + if (findEnclosingReturn(node) !== null) { + report(); + return; + } + + // Report all exported variables + for (const exportedVar of exportedVars) { + if (isIn(node, exportedVar)) { + report(); + return; + } + } + + // Report all returned variables + for (const [fn, fnReturnVars] of returnedVariables.entries()) { + for (const returnedVar of fnReturnVars) { + if (fn.type === 'MethodDefinition' && returnedVar.type === 'PropertyDefinition') { + continue; + } + if (isIn(node, returnedVar)) { + report(); + return; + } + } + } + + // Report all encapsulated class properties + const enclosingPropertyDefinition = findEnclosingPropertyDefinition(node); + if ( + enclosingPropertyDefinition !== null && + (!ignoreEncapsulatedLocalVariables || + !isPropertyEncapsulated( + enclosingPropertyDefinition, + returnedFunctionCalls, + returnedVariables + )) + ) { + report(); + return; + } + + // Ignore all variables encapsulated in functions + if (ignoreEncapsulatedLocalVariables && isLocalVarEncapsulated(returnedVariables, node)) { + return; + } + + // Report all other mutable variables + if (objectType === 'Date' && isDateMutable(referenceTracker, node as TSESTree.Expression)) { + report(); + return; + } + if (objectType === 'Map' && isMapMutable(referenceTracker, node as TSESTree.Expression)) { + report(); + return; + } + if (objectType === 'Set' && isSetMutable(referenceTracker, node as TSESTree.Expression)) { + report(); + return; + } + if (objectType === 'URL' && isURLMutable(referenceTracker, node as TSESTree.Expression)) { + report(); + return; + } + if ( + objectType === 'URLSearchParams' && + isURLSearchParamsMutable(referenceTracker, node as TSESTree.Expression) + ) { + report(); + } + } + return { ...(getSvelteContext(context)?.svelteFileType === '.svelte.[js|ts]' && { ExportNamedDeclaration(node) { @@ -59,6 +232,8 @@ export default createRule('prefer-svelte-reactivity', { } } }), + Identifier: recordReturnedIdentifiers, + PrivateIdentifier: recordReturnedIdentifiers, 'Program:exit'() { const referenceTracker = new ReferenceTracker(context.sourceCode.scopeManager.globalScope!); for (const { node, path } of referenceTracker.iterateGlobalReferences({ @@ -78,63 +253,109 @@ export default createRule('prefer-svelte-reactivity', { [ReferenceTracker.CONSTRUCT]: true } })) { - const messageId = - path[0] === 'Date' - ? 'mutableDateUsed' - : path[0] === 'Map' - ? 'mutableMapUsed' - : path[0] === 'Set' - ? 'mutableSetUsed' - : path[0] === 'URL' - ? 'mutableURLUsed' - : 'mutableURLSearchParamsUsed'; - for (const exportedVar of exportedVars) { - if (isIn(node, exportedVar)) { - context.report({ - messageId, - node - }); - } - } - if (path[0] === 'Date' && isDateMutable(referenceTracker, node as TSESTree.Expression)) { - context.report({ - messageId: 'mutableDateUsed', - node - }); - } - if (path[0] === 'Map' && isMapMutable(referenceTracker, node as TSESTree.Expression)) { - context.report({ - messageId: 'mutableMapUsed', - node - }); - } - if (path[0] === 'Set' && isSetMutable(referenceTracker, node as TSESTree.Expression)) { - context.report({ - messageId: 'mutableSetUsed', - node - }); - } - if (path[0] === 'URL' && isURLMutable(referenceTracker, node as TSESTree.Expression)) { - context.report({ - messageId: 'mutableURLUsed', - node - }); - } - if ( - path[0] === 'URLSearchParams' && - isURLSearchParamsMutable(referenceTracker, node as TSESTree.Expression) - ) { - context.report({ - messageId: 'mutableURLSearchParamsUsed', - node - }); - } + checkNonReactiveUsage( + node, + path[0] as 'Date' | 'Map' | 'Set' | 'URL' | 'URLSearchParams', + referenceTracker + ); } } }; } }); +function findAncestorOfTypes( + node: TSESTree.Node, + types: string[] +): (TSESTree.Node & { type: T }) | null { + if (types.includes(node.type)) { + return node as TSESTree.Node & { type: T }; + } + if (node.parent === undefined || node.parent === null) { + return null; + } + return findAncestorOfTypes(node.parent, types); +} + +function findEnclosingClassBody(node: TSESTree.Node): TSESTree.ClassBody | null { + return findAncestorOfTypes(node, ['ClassBody']); +} + +function findEnclosingFunction( + node: TSESTree.Node +): TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclaration | null { + return findAncestorOfTypes(node, [ + 'ArrowFunctionExpression', + 'FunctionDeclaration', + 'MethodDefinition' + ]); +} + +function findEnclosingPropertyDefinition(node: TSESTree.Node): TSESTree.PropertyDefinition | null { + return findAncestorOfTypes(node, ['PropertyDefinition']); +} + +function findEnclosingReturn(node: TSESTree.Node): TSESTree.ReturnStatement | null { + return findAncestorOfTypes(node, ['ReturnStatement']); +} + +function isLocalVarEncapsulated( + returnedVariables: Map, + node: TSESTree.Node +): boolean { + const enclosingFunction = findEnclosingFunction(node); + if (enclosingFunction === null) { + return false; + } + return ( + returnedVariables.get(enclosingFunction)?.some((variable) => isIn(node, variable)) !== true + ); +} + +function methodReturnsProperty( + method: TSESTree.MethodDefinition, + property: TSESTree.PropertyDefinition, + returnedFunctionCalls: Map, + returnedVariables: Map +): boolean { + return ( + (returnedVariables.get(method)?.includes(property) ?? false) || + (returnedFunctionCalls + .get(method) + ?.some((calledFn) => + methodReturnsProperty(calledFn, property, returnedFunctionCalls, returnedVariables) + ) ?? + false) + ); +} + +function isPropertyEncapsulated( + node: TSESTree.PropertyDefinition, + returnedFunctionCalls: Map, + returnedVariables: Map +): boolean { + if (isPublic(node)) { + return false; + } + for (const classElement of node.parent.body) { + if ( + classElement.type === 'MethodDefinition' && + isPublic(classElement) && + methodReturnsProperty(classElement, node, returnedFunctionCalls, returnedVariables) + ) { + return false; + } + } + return true; +} + +function isPublic(node: TSESTree.MethodDefinition | TSESTree.PropertyDefinition): boolean { + return ( + (node.accessibility === undefined && node.key.type !== 'PrivateIdentifier') || + node.accessibility === 'public' + ); +} + function isDateMutable(referenceTracker: ReferenceTracker, ctorNode: TSESTree.Expression): boolean { return !referenceTracker .iteratePropertyReferences(ctorNode, { diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/_config.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/_config.json new file mode 100644 index 000000000..1f4c02173 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/_config.json @@ -0,0 +1,3 @@ +{ + "options": [{ "ignoreEncapsulatedLocalVariables": false }] +} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/_requirements.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/_requirements.json new file mode 100644 index 000000000..498661308 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/_requirements.json @@ -0,0 +1,3 @@ +{ + "svelte": ">=5.0.0" +} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-arrow-function01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-arrow-function01-errors.yaml new file mode 100644 index 000000000..261288a54 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-arrow-function01-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 20 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-arrow-function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-arrow-function01-input.svelte new file mode 100644 index 000000000..b1fddc706 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-arrow-function01-input.svelte @@ -0,0 +1,9 @@ + + +{fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class01-errors.yaml new file mode 100644 index 000000000..4356fa0a3 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class01-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 15 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class01-input.svelte new file mode 100644 index 000000000..a773d09dc --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class01-input.svelte @@ -0,0 +1,14 @@ + + +{a.fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class02-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class02-errors.yaml new file mode 100644 index 000000000..4356fa0a3 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class02-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 15 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class02-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class02-input.svelte new file mode 100644 index 000000000..6c220ac86 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class02-input.svelte @@ -0,0 +1,19 @@ + + +{a.fn2()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class03-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class03-errors.yaml new file mode 100644 index 000000000..eafa9d96c --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class03-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 22 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class03-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class03-input.svelte new file mode 100644 index 000000000..20109b36e --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class03-input.svelte @@ -0,0 +1,14 @@ + + +{a.fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class04-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class04-errors.yaml new file mode 100644 index 000000000..eafa9d96c --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class04-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 22 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class04-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class04-input.svelte new file mode 100644 index 000000000..285546187 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-class04-input.svelte @@ -0,0 +1,19 @@ + + +{a.fn2()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-function01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-function01-errors.yaml new file mode 100644 index 000000000..261288a54 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-function01-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 20 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-function01-input.svelte new file mode 100644 index 000000000..1925b4252 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/encapsulated-local-variables/encapsulated-function01-input.svelte @@ -0,0 +1,9 @@ + + +{fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/_requirements.json b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/_requirements.json new file mode 100644 index 000000000..498661308 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/_requirements.json @@ -0,0 +1,3 @@ +{ + "svelte": ">=5.0.0" +} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function01-errors.yaml new file mode 100644 index 000000000..261288a54 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function01-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 20 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function01-input.svelte new file mode 100644 index 000000000..0dafc5973 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function01-input.svelte @@ -0,0 +1,8 @@ + + +{fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function02-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function02-errors.yaml new file mode 100644 index 000000000..83a23dffc --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function02-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 10 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function02-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function02-input.svelte new file mode 100644 index 000000000..9d43ca045 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-arrow-function02-input.svelte @@ -0,0 +1,7 @@ + + +{fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class01-errors.yaml new file mode 100644 index 000000000..4356fa0a3 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class01-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 15 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class01-input.svelte new file mode 100644 index 000000000..f6541953a --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class01-input.svelte @@ -0,0 +1,13 @@ + + +{a.fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class02-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class02-errors.yaml new file mode 100644 index 000000000..4356fa0a3 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class02-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 15 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class02-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class02-input.svelte new file mode 100644 index 000000000..3875bd39d --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class02-input.svelte @@ -0,0 +1,17 @@ + + +{a.fn2().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class03-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class03-errors.yaml new file mode 100644 index 000000000..eafa9d96c --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class03-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 22 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class03-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class03-input.svelte new file mode 100644 index 000000000..1ae19334b --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class03-input.svelte @@ -0,0 +1,13 @@ + + +{a.fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class04-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class04-errors.yaml new file mode 100644 index 000000000..eafa9d96c --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class04-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 22 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class04-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class04-input.svelte new file mode 100644 index 000000000..cf0c955d9 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class04-input.svelte @@ -0,0 +1,17 @@ + + +{a.fn2().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class05-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class05-errors.yaml new file mode 100644 index 000000000..3123a888a --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class05-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 14 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class05-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class05-input.svelte new file mode 100644 index 000000000..f781683fb --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class05-input.svelte @@ -0,0 +1,13 @@ + + +{a.fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class06-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class06-errors.yaml new file mode 100644 index 000000000..5e8895329 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class06-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 21 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class06-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class06-input.svelte new file mode 100644 index 000000000..2cc27ea56 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class06-input.svelte @@ -0,0 +1,13 @@ + + +{a.fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class07-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class07-errors.yaml new file mode 100644 index 000000000..0fd05822b --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class07-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 4 + column: 18 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class07-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class07-input.svelte new file mode 100644 index 000000000..51437ede6 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class07-input.svelte @@ -0,0 +1,12 @@ + + +{a.fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class08-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class08-errors.yaml new file mode 100644 index 000000000..f01de6b75 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class08-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 4 + column: 11 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class08-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class08-input.svelte new file mode 100644 index 000000000..90186aa3a --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-class08-input.svelte @@ -0,0 +1,11 @@ + + +{a.fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function01-errors.yaml new file mode 100644 index 000000000..261288a54 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function01-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 20 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function01-input.svelte new file mode 100644 index 000000000..2bb763a44 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function01-input.svelte @@ -0,0 +1,8 @@ + + +{fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function02-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function02-errors.yaml new file mode 100644 index 000000000..83a23dffc --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function02-errors.yaml @@ -0,0 +1,4 @@ +- message: Found a mutable instance of the built-in Set class. Use SvelteSet instead. + line: 3 + column: 10 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function02-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function02-input.svelte new file mode 100644 index 000000000..5601de190 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/invalid/unencapsulated-local-variables/unencapsulated-function02-input.svelte @@ -0,0 +1,7 @@ + + +{fn().has(42)} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-arrow-function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-arrow-function01-input.svelte new file mode 100644 index 000000000..b1fddc706 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-arrow-function01-input.svelte @@ -0,0 +1,9 @@ + + +{fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class01-input.svelte new file mode 100644 index 000000000..a773d09dc --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class01-input.svelte @@ -0,0 +1,14 @@ + + +{a.fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class02-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class02-input.svelte new file mode 100644 index 000000000..6c220ac86 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class02-input.svelte @@ -0,0 +1,19 @@ + + +{a.fn2()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class03-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class03-input.svelte new file mode 100644 index 000000000..20109b36e --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class03-input.svelte @@ -0,0 +1,14 @@ + + +{a.fn()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class04-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class04-input.svelte new file mode 100644 index 000000000..285546187 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-class04-input.svelte @@ -0,0 +1,19 @@ + + +{a.fn2()} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-function01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-function01-input.svelte new file mode 100644 index 000000000..1925b4252 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/prefer-svelte-reactivity/valid/encapsulated-function01-input.svelte @@ -0,0 +1,9 @@ + + +{fn()}