diff --git a/.cspell.json b/.cspell.json index 36beb3bb328..c74d69186b9 100644 --- a/.cspell.json +++ b/.cspell.json @@ -89,9 +89,10 @@ "rulesets", "serializers", "superset", - "transpiling", "thenables", + "transpiled", "transpiles", + "transpiling", "tsconfigs", "tsutils", "typedef", diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts index b67f5ef09c3..2b0bb32ccb5 100644 --- a/packages/eslint-plugin/src/rules/no-use-before-define.ts +++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts @@ -133,6 +133,37 @@ function isInRange( return !!node && node.range[0] <= location && location <= node.range[1]; } +/** + * Decorators are transpiled such that the decorator is placed after the class declaration + * So it is considered safe + */ +function isClassRefInClassDecorator( + variable: TSESLint.Scope.Variable, + reference: TSESLint.Scope.Reference, +): boolean { + if (variable.defs[0].type !== 'ClassName') { + return false; + } + + if ( + !variable.defs[0].node.decorators || + variable.defs[0].node.decorators.length === 0 + ) { + return false; + } + + for (const deco of variable.defs[0].node.decorators) { + if ( + reference.identifier.range[0] >= deco.range[0] && + reference.identifier.range[1] <= deco.range[1] + ) { + return true; + } + } + + return false; +} + /** * Checks whether or not a given reference is inside of the initializers of a given variable. * @@ -292,6 +323,7 @@ export default util.createRule({ (variable.identifiers[0].range[1] <= reference.identifier.range[1] && !isInInitializer(variable, reference)) || !isForbidden(variable, reference) || + isClassRefInClassDecorator(variable, reference) || reference.from.type === TSESLint.Scope.ScopeType.functionType ) { return; diff --git a/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts b/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts index 77e434d3382..8fb4d076602 100644 --- a/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts +++ b/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts @@ -394,6 +394,40 @@ declare global { } } `, + // https://github.com/typescript-eslint/typescript-eslint/issues/2824 + ` +@Directive({ + selector: '[rcCidrIpPattern]', + providers: [ + { + provide: NG_VALIDATORS, + useExisting: CidrIpPatternDirective, + multi: true, + }, + ], +}) +export class CidrIpPatternDirective implements Validator {} + `, + { + code: ` +@Directive({ + selector: '[rcCidrIpPattern]', + providers: [ + { + provide: NG_VALIDATORS, + useExisting: CidrIpPatternDirective, + multi: true, + }, + ], +}) +export class CidrIpPatternDirective implements Validator {} + `, + options: [ + { + classes: false, + }, + ], + }, ], invalid: [ {