1- import { Node , ParameterDeclaration , FunctionDeclaration , MethodDeclaration , ArrowFunction , FunctionExpression , BindingElement , OmittedExpression , ConstructorDeclaration , ObjectBindingPattern } from 'ts-morph' ;
1+ import { Node , ParameterDeclaration , FunctionDeclaration , MethodDeclaration , ArrowFunction , FunctionExpression , BindingElement , OmittedExpression , ConstructorDeclaration } from 'ts-morph' ;
2+ import { ScopeAnalyzer } from './scope-analyzer' ;
23
34type FunctionLikeNode = FunctionDeclaration | MethodDeclaration | ArrowFunction | FunctionExpression | ConstructorDeclaration ;
45
56export class VariableNameValidator {
67 generateUniqueName ( baseName : string , scope : Node ) : string {
7- const existingNames = this . getExistingVariableNames ( scope ) ;
8-
9- if ( ! existingNames . has ( baseName ) ) {
8+ if ( ! this . getExistingVariableNames ( scope ) . has ( baseName ) ) {
109 return baseName ;
1110 }
1211
@@ -18,6 +17,7 @@ export class VariableNameValidator {
1817
1918 this . addFunctionParametersIfInBlock ( scope , names ) ;
2019 this . addDescendantVariableNames ( scope , names ) ;
20+ this . addParentScopeVariableNames ( scope , names ) ;
2121
2222 return names ;
2323 }
@@ -44,21 +44,48 @@ export class VariableNameValidator {
4444 } ) ;
4545 }
4646
47+ private addParentScopeVariableNames ( scope : Node , names : Set < string > ) : void {
48+ let parentScope = ScopeAnalyzer . getParentScope ( scope ) ;
49+ while ( parentScope ) {
50+ this . addDirectVariableNames ( parentScope , names ) ;
51+ this . addFunctionParametersIfInBlock ( parentScope , names ) ;
52+ parentScope = ScopeAnalyzer . getParentScope ( parentScope ) ;
53+ }
54+ }
55+
56+ private addDirectVariableNames ( scope : Node , names : Set < string > ) : void {
57+ scope . forEachChild ( ( child ) => {
58+ this . addChildVariableNames ( child , names ) ;
59+ } ) ;
60+ }
61+
62+ private addChildVariableNames ( child : Node , names : Set < string > ) : void {
63+ if ( Node . isVariableStatement ( child ) ) {
64+ child . getDeclarations ( ) . forEach ( ( declaration ) => {
65+ this . addVariableNameIfExists ( declaration , names ) ;
66+ } ) ;
67+ } else if ( Node . isVariableDeclaration ( child ) ) {
68+ this . addVariableNameIfExists ( child , names ) ;
69+ } else if ( Node . isParameterDeclaration ( child ) ) {
70+ this . addParameterNameIfExists ( child , names ) ;
71+ }
72+ }
73+
74+ private addNameIfIdentifier ( node : Node , names : Set < string > ) : void {
75+ if ( Node . isIdentifier ( node ) ) {
76+ names . add ( node . getText ( ) ) ;
77+ }
78+ }
79+
4780 private addVariableNameIfExists ( node : Node , names : Set < string > ) : void {
4881 if ( Node . isVariableDeclaration ( node ) ) {
49- const nameNode = node . getNameNode ( ) ;
50- if ( Node . isIdentifier ( nameNode ) ) {
51- names . add ( nameNode . getText ( ) ) ;
52- }
82+ this . addNameIfIdentifier ( node . getNameNode ( ) , names ) ;
5383 }
5484 }
5585
5686 private addParameterNameIfExists ( node : Node , names : Set < string > ) : void {
5787 if ( Node . isParameterDeclaration ( node ) ) {
58- const nameNode = node . getNameNode ( ) ;
59- if ( Node . isIdentifier ( nameNode ) ) {
60- names . add ( nameNode . getText ( ) ) ;
61- }
88+ this . addNameIfIdentifier ( node . getNameNode ( ) , names ) ;
6289 }
6390 }
6491
@@ -69,16 +96,13 @@ export class VariableNameValidator {
6996 }
7097
7198 private processParameters ( functionNode : Node , names : Set < string > ) : void {
72- const parameters = this . getParametersFromFunction ( functionNode ) ;
73- for ( const param of parameters ) {
99+ for ( const param of this . getParametersFromFunction ( functionNode ) ) {
74100 this . processParameter ( param , names ) ;
75101 }
76102 }
77103
78104 private getParametersFromFunction ( functionNode : Node ) : ParameterDeclaration [ ] {
79- if ( Node . isFunctionDeclaration ( functionNode ) || Node . isMethodDeclaration ( functionNode ) ||
80- Node . isArrowFunction ( functionNode ) || Node . isFunctionExpression ( functionNode ) ||
81- Node . isConstructorDeclaration ( functionNode ) ) {
105+ if ( this . isFunctionNode ( functionNode ) ) {
82106 return ( functionNode as FunctionLikeNode ) . getParameters ( ) ;
83107 }
84108 return [ ] ;
@@ -87,54 +111,27 @@ export class VariableNameValidator {
87111 private processParameter ( param : ParameterDeclaration , names : Set < string > ) : void {
88112 const nameNode = param . getNameNode ( ) ;
89113 if ( Node . isIdentifier ( nameNode ) ) {
90- names . add ( nameNode . getText ( ) ) ;
114+ this . addNameIfIdentifier ( nameNode , names ) ;
91115 } else {
92- this . addDestructuredParameterNames ( nameNode , names ) ;
93- }
94- }
95-
96- private addDestructuredParameterNames ( nameNode : Node , names : Set < string > ) : void {
97- if ( Node . isObjectBindingPattern ( nameNode ) ) {
98- this . addObjectBindingNames ( nameNode , names ) ;
99- } else if ( Node . isArrayBindingPattern ( nameNode ) ) {
100- this . addArrayBindingNames ( nameNode , names ) ;
116+ this . addBindingPatternNames ( nameNode , names ) ;
101117 }
102118 }
103119
104- private addObjectBindingNames ( nameNode : Node , names : Set < string > ) : void {
105- if ( Node . isObjectBindingPattern ( nameNode ) ) {
106- this . processBindingElements ( nameNode , names ) ;
107- }
108- }
109-
110- private processBindingElements ( nameNode : ObjectBindingPattern , names : Set < string > ) : void {
111- nameNode . getElements ( ) . forEach ( ( element : BindingElement | OmittedExpression ) => {
112- this . processBindingElement ( element , names ) ;
113- } ) ;
114- }
115-
116- private processBindingElement ( element : BindingElement | OmittedExpression , names : Set < string > ) : void {
117- if ( ! Node . isBindingElement ( element ) ) return ;
118- const elementName = element . getNameNode ( ) ;
119- if ( Node . isIdentifier ( elementName ) ) {
120- names . add ( elementName . getText ( ) ) ;
121- }
122- }
123-
124- private addArrayBindingNames ( nameNode : Node , names : Set < string > ) : void {
125- if ( Node . isArrayBindingPattern ( nameNode ) ) {
126- nameNode . getElements ( ) . forEach ( ( element : BindingElement | OmittedExpression ) => {
127- this . processArrayBindingElement ( element , names ) ;
120+ private addBindingPatternNames ( pattern : Node , names : Set < string > ) : void {
121+ if ( Node . isObjectBindingPattern ( pattern ) ) {
122+ pattern . getElements ( ) . forEach ( element => {
123+ this . addBindingElementName ( element , names ) ;
124+ } ) ;
125+ } else if ( Node . isArrayBindingPattern ( pattern ) ) {
126+ pattern . getElements ( ) . forEach ( element => {
127+ this . addBindingElementName ( element , names ) ;
128128 } ) ;
129129 }
130130 }
131131
132- private processArrayBindingElement ( element : BindingElement | OmittedExpression , names : Set < string > ) : void {
132+ private addBindingElementName ( element : BindingElement | OmittedExpression , names : Set < string > ) : void {
133133 if ( element && Node . isBindingElement ( element ) ) {
134- const elementName = element . getNameNode ( ) ;
135- if ( Node . isIdentifier ( elementName ) ) {
136- names . add ( elementName . getText ( ) ) ;
137- }
134+ this . addNameIfIdentifier ( element . getNameNode ( ) , names ) ;
138135 }
139136 }
140137}
0 commit comments