Skip to content

Commit 52ef1f0

Browse files
committed
feat(prefer-svelte-reactivity): added support for ES class element accessibility
1 parent b30cb5b commit 52ef1f0

File tree

1 file changed

+76
-63
lines changed

1 file changed

+76
-63
lines changed

packages/eslint-plugin-svelte/src/rules/prefer-svelte-reactivity.ts

Lines changed: 76 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,71 @@ export default createRule('prefer-svelte-reactivity', {
5454
const returnedFunctionCalls: Map<FunctionLike, TSESTree.MethodDefinition[]> = new Map();
5555
const returnedVariables: Map<FunctionLike, VariableLike[]> = new Map();
5656
const exportedVars: TSESTree.Node[] = [];
57+
58+
function recordReturnedIdentifiers(node: TSESTree.Identifier | TSESTree.PrivateIdentifier) {
59+
function recordVariable(enclosingFunction: FunctionLike, variable: VariableLike): void {
60+
if (variable === null) {
61+
return;
62+
}
63+
if (!returnedVariables.has(enclosingFunction)) {
64+
returnedVariables.set(enclosingFunction, []);
65+
}
66+
returnedVariables.get(enclosingFunction)?.push(variable);
67+
}
68+
69+
function recordFunctionCall(
70+
enclosingFunction: FunctionLike,
71+
functionCall: TSESTree.MethodDefinition
72+
): void {
73+
if (functionCall === null) {
74+
return;
75+
}
76+
if (!returnedFunctionCalls.has(enclosingFunction)) {
77+
returnedFunctionCalls.set(enclosingFunction, []);
78+
}
79+
returnedFunctionCalls.get(enclosingFunction)?.push(functionCall);
80+
}
81+
82+
const enclosingReturn = findEnclosingReturn(node);
83+
if (enclosingReturn === null) {
84+
return;
85+
}
86+
const enclosingFunction = findEnclosingFunction(enclosingReturn);
87+
if (enclosingFunction === null) {
88+
return;
89+
}
90+
if (node.parent.type === 'MemberExpression') {
91+
const enclosingClassBody = findEnclosingClassBody(node);
92+
for (const classElement of enclosingClassBody?.body ?? []) {
93+
if (
94+
classElement.type === 'PropertyDefinition' &&
95+
(classElement.key.type === 'Identifier' ||
96+
classElement.key.type === 'PrivateIdentifier') &&
97+
node.name === classElement.key.name
98+
) {
99+
recordVariable(enclosingFunction, classElement);
100+
}
101+
if (
102+
classElement.type === 'MethodDefinition' &&
103+
(classElement.key.type === 'Identifier' ||
104+
classElement.key.type === 'PrivateIdentifier') &&
105+
node.name === classElement.key.name
106+
) {
107+
recordFunctionCall(enclosingFunction, classElement);
108+
}
109+
}
110+
} else if (node.type === 'Identifier') {
111+
const variable = findVariable(context, node);
112+
if (
113+
variable !== null &&
114+
variable.identifiers.length > 0 &&
115+
variable.identifiers[0].parent.type === 'VariableDeclarator'
116+
) {
117+
recordVariable(enclosingFunction, variable.identifiers[0].parent);
118+
}
119+
}
120+
}
121+
57122
return {
58123
...(getSvelteContext(context)?.svelteFileType === '.svelte.[js|ts]' && {
59124
ExportNamedDeclaration(node) {
@@ -81,67 +146,8 @@ export default createRule('prefer-svelte-reactivity', {
81146
}
82147
}
83148
}),
84-
Identifier(node) {
85-
function recordVariable(enclosingFunction: FunctionLike, variable: VariableLike): void {
86-
if (variable === null) {
87-
return;
88-
}
89-
if (!returnedVariables.has(enclosingFunction)) {
90-
returnedVariables.set(enclosingFunction, []);
91-
}
92-
returnedVariables.get(enclosingFunction)?.push(variable);
93-
}
94-
95-
function recordFunctionCall(
96-
enclosingFunction: FunctionLike,
97-
functionCall: TSESTree.MethodDefinition
98-
): void {
99-
if (functionCall === null) {
100-
return;
101-
}
102-
if (!returnedFunctionCalls.has(enclosingFunction)) {
103-
returnedFunctionCalls.set(enclosingFunction, []);
104-
}
105-
returnedFunctionCalls.get(enclosingFunction)?.push(functionCall);
106-
}
107-
108-
const enclosingReturn = findEnclosingReturn(node);
109-
if (enclosingReturn === null) {
110-
return;
111-
}
112-
const enclosingFunction = findEnclosingFunction(enclosingReturn);
113-
if (enclosingFunction === null) {
114-
return;
115-
}
116-
if (node.parent.type === 'MemberExpression') {
117-
const enclosingClassBody = findEnclosingClassBody(node);
118-
for (const classElement of enclosingClassBody?.body ?? []) {
119-
if (
120-
classElement.type === 'PropertyDefinition' &&
121-
classElement.key.type === 'Identifier' &&
122-
node.name === classElement.key.name
123-
) {
124-
recordVariable(enclosingFunction, classElement);
125-
}
126-
if (
127-
classElement.type === 'MethodDefinition' &&
128-
classElement.key.type === 'Identifier' &&
129-
node.name === classElement.key.name
130-
) {
131-
recordFunctionCall(enclosingFunction, classElement);
132-
}
133-
}
134-
} else {
135-
const variable = findVariable(context, node);
136-
if (
137-
variable !== null &&
138-
variable.identifiers.length > 0 &&
139-
variable.identifiers[0].parent.type === 'VariableDeclarator'
140-
) {
141-
recordVariable(enclosingFunction, variable.identifiers[0].parent);
142-
}
143-
}
144-
},
149+
Identifier: recordReturnedIdentifiers,
150+
PrivateIdentifier: recordReturnedIdentifiers,
145151
'Program:exit'() {
146152
const referenceTracker = new ReferenceTracker(context.sourceCode.scopeManager.globalScope!);
147153
for (const { node, path } of referenceTracker.iterateGlobalReferences({
@@ -320,13 +326,13 @@ function isPropertyEncapsulated(
320326
returnedFunctionCalls: Map<FunctionLike, TSESTree.MethodDefinition[]>,
321327
returnedVariables: Map<FunctionLike, VariableLike[]>
322328
): boolean {
323-
if (node.accessibility === 'public') {
329+
if (isPublic(node)) {
324330
return false;
325331
}
326332
for (const classElement of node.parent.body) {
327333
if (
328334
classElement.type === 'MethodDefinition' &&
329-
classElement.accessibility === 'public' &&
335+
isPublic(classElement) &&
330336
methodReturnsProperty(classElement, node, returnedFunctionCalls, returnedVariables)
331337
) {
332338
return false;
@@ -335,6 +341,13 @@ function isPropertyEncapsulated(
335341
return true;
336342
}
337343

344+
function isPublic(node: TSESTree.MethodDefinition | TSESTree.PropertyDefinition): boolean {
345+
return (
346+
(node.accessibility === undefined && node.key.type !== 'PrivateIdentifier') ||
347+
node.accessibility === 'public'
348+
);
349+
}
350+
338351
function isDateMutable(referenceTracker: ReferenceTracker, ctorNode: TSESTree.Expression): boolean {
339352
return !referenceTracker
340353
.iteratePropertyReferences(ctorNode, {

0 commit comments

Comments
 (0)