From c0df9a26b145084a41d1dde912e6a103d1522b5f Mon Sep 17 00:00:00 2001 From: Alexandre Vryghem Date: Fri, 4 Oct 2024 18:50:16 +0200 Subject: [PATCH] 117616: Fixed unique-decorators rule not working in IntelliJ because the decorator calls were registered every time the file was updated --- lint/src/rules/ts/unique-decorators.ts | 39 +++++++++++++++++++++----- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/lint/src/rules/ts/unique-decorators.ts b/lint/src/rules/ts/unique-decorators.ts index 682f89f5a23..5cab1b3bee0 100644 --- a/lint/src/rules/ts/unique-decorators.ts +++ b/lint/src/rules/ts/unique-decorators.ts @@ -16,7 +16,16 @@ export enum Message { DUPLICATE_DECORATOR_CALL = 'duplicateDecoratorCall', } -const decoratorCalls: Map> = new Map(); +/** + * Saves the decorators by decoratorName → file → Set + */ +const decoratorCalls: Map>> = new Map(); + +/** + * Keep a list of the files wo contain a decorator. This is done in order to prevent the `Program` selector from being + * run for every file. + */ +const fileWithDecorators: Set = new Set(); export interface UniqueDecoratorsOptions { decorators: string[]; @@ -75,6 +84,13 @@ export const rule = ESLintUtils.RuleCreator.withoutDocs({ create(context: TSESLint.RuleContext, options: any) { return { + ['Program']: () => { + if (fileWithDecorators.has(context.physicalFilename)) { + for (const decorator of options[0].decorators) { + decoratorCalls.get(decorator)?.get(context.physicalFilename)?.clear(); + } + } + }, [`ClassDeclaration > Decorator > CallExpression[callee.name=/^(${options[0].decorators.join('|')})$/]`]: (node: TSESTree.CallExpression) => { if (isTestFile(context)) { return; @@ -85,7 +101,9 @@ export const rule = ESLintUtils.RuleCreator.withoutDocs({ return; } - if (!isUnique(node)) { + fileWithDecorators.add(context.physicalFilename); + + if (!isUnique(node, context.physicalFilename)) { context.report({ messageId: Message.DUPLICATE_DECORATOR_CALL, node: node, @@ -183,22 +201,29 @@ function callKey(node: TSESTree.CallExpression): string { return key; } -function isUnique(node: TSESTree.CallExpression): boolean { +function isUnique(node: TSESTree.CallExpression, filePath: string): boolean { const decorator = (node.callee as TSESTree.Identifier).name; if (!decoratorCalls.has(decorator)) { - decoratorCalls.set(decorator, new Set()); + decoratorCalls.set(decorator, new Map()); + } + + if (!decoratorCalls.get(decorator)!.has(filePath)) { + decoratorCalls.get(decorator)!.set(filePath, new Set()); } const key = callKey(node); let unique = true; - if (decoratorCalls.get(decorator)?.has(key)) { - unique = !unique; + for (const decoratorCallsByFile of decoratorCalls.get(decorator)!.values()) { + if (decoratorCallsByFile.has(key)) { + unique = !unique; + break; + } } - decoratorCalls.get(decorator)?.add(key); + decoratorCalls.get(decorator)?.get(filePath)?.add(key); return unique; }