@@ -16,7 +16,16 @@ export enum Message {
1616 DUPLICATE_DECORATOR_CALL = 'duplicateDecoratorCall' ,
1717}
1818
19- const decoratorCalls : Map < string , Set < string > > = new Map ( ) ;
19+ /**
20+ * Saves the decorators by decoratorName → file → Set<String>
21+ */
22+ const decoratorCalls : Map < string , Map < string , Set < string > > > = new Map ( ) ;
23+
24+ /**
25+ * Keep a list of the files wo contain a decorator. This is done in order to prevent the `Program` selector from being
26+ * run for every file.
27+ */
28+ const fileWithDecorators : Set < string > = new Set ( ) ;
2029
2130export interface UniqueDecoratorsOptions {
2231 decorators : string [ ] ;
@@ -72,6 +81,13 @@ export const rule = ESLintUtils.RuleCreator.withoutDocs({
7281 create ( context : TSESLint . RuleContext < Message , unknown [ ] > , options : any ) {
7382
7483 return {
84+ [ 'Program' ] : ( ) => {
85+ if ( fileWithDecorators . has ( context . physicalFilename ) ) {
86+ for ( const decorator of options [ 0 ] . decorators ) {
87+ decoratorCalls . get ( decorator ) ?. get ( context . physicalFilename ) ?. clear ( ) ;
88+ }
89+ }
90+ } ,
7591 [ `ClassDeclaration > Decorator > CallExpression[callee.name=/^(${ options [ 0 ] . decorators . join ( '|' ) } )$/]` ] : ( node : TSESTree . CallExpression ) => {
7692 if ( isTestFile ( context ) ) {
7793 return ;
@@ -82,7 +98,9 @@ export const rule = ESLintUtils.RuleCreator.withoutDocs({
8298 return ;
8399 }
84100
85- if ( ! isUnique ( node ) ) {
101+ fileWithDecorators . add ( context . physicalFilename ) ;
102+
103+ if ( ! isUnique ( node , context . physicalFilename ) ) {
86104 context . report ( {
87105 messageId : Message . DUPLICATE_DECORATOR_CALL ,
88106 node : node ,
@@ -180,22 +198,29 @@ function callKey(node: TSESTree.CallExpression): string {
180198 return key ;
181199}
182200
183- function isUnique ( node : TSESTree . CallExpression ) : boolean {
201+ function isUnique ( node : TSESTree . CallExpression , filePath : string ) : boolean {
184202 const decorator = ( node . callee as TSESTree . Identifier ) . name ;
185203
186204 if ( ! decoratorCalls . has ( decorator ) ) {
187- decoratorCalls . set ( decorator , new Set ( ) ) ;
205+ decoratorCalls . set ( decorator , new Map ( ) ) ;
206+ }
207+
208+ if ( ! decoratorCalls . get ( decorator ) ! . has ( filePath ) ) {
209+ decoratorCalls . get ( decorator ) ! . set ( filePath , new Set ( ) ) ;
188210 }
189211
190212 const key = callKey ( node ) ;
191213
192214 let unique = true ;
193215
194- if ( decoratorCalls . get ( decorator ) ?. has ( key ) ) {
195- unique = ! unique ;
216+ for ( const decoratorCallsByFile of decoratorCalls . get ( decorator ) ! . values ( ) ) {
217+ if ( decoratorCallsByFile . has ( key ) ) {
218+ unique = ! unique ;
219+ break ;
220+ }
196221 }
197222
198- decoratorCalls . get ( decorator ) ?. add ( key ) ;
223+ decoratorCalls . get ( decorator ) ?. get ( filePath ) ?. add ( key ) ;
199224
200225 return unique ;
201226}
0 commit comments