@@ -6,6 +6,7 @@ import * as ESTree from 'estree';
6
6
import * as estraverse from 'estraverse' ;
7
7
8
8
import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory' ;
9
+ import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope' ;
9
10
10
11
import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer' ;
11
12
import { IOptions } from '../../interfaces/options/IOptions' ;
@@ -44,9 +45,9 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
44
45
private readonly identifierObfuscatingReplacer : IIdentifierObfuscatingReplacer ;
45
46
46
47
/**
47
- * @type {Map<eslintScope.Scope['block'] , boolean> }
48
+ * @type {Map<TNodeWithLexicalScope , boolean> }
48
49
*/
49
- private readonly lexicalScopesWithObjectPatternWithoutDeclarationMap : Map < eslintScope . Scope [ 'block' ] , boolean > = new Map ( ) ;
50
+ private readonly lexicalScopesWithObjectPatternWithoutDeclarationMap : Map < TNodeWithLexicalScope , boolean > = new Map ( ) ;
50
51
51
52
/**
52
53
* @type {IScopeAnalyzer }
@@ -122,12 +123,36 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
122
123
* @param {Scope } scope
123
124
*/
124
125
private traverseScopeVariables ( scope : eslintScope . Scope ) : void {
125
- const variableScope : eslintScope . Scope = scope . variableScope ;
126
- const isGlobalVariableScope : boolean = ScopeIdentifiersTransformer . globalScopeNames . includes ( variableScope . type ) ;
126
+ const lexicalScope : eslintScope . Scope = scope . variableScope ;
127
+ const nodeWithLexicalScope : TNodeWithLexicalScope | null = NodeGuards . isNodeWithBlockLexicalScope ( lexicalScope . block )
128
+ ? lexicalScope . block
129
+ : null ;
130
+ const isGlobalDeclaration : boolean = ScopeIdentifiersTransformer . globalScopeNames . includes ( lexicalScope . type ) ;
127
131
128
- scope . variables . forEach ( ( variable : eslintScope . Variable ) => {
129
- this . processScopeVariableIdentifiers ( variable , scope , variableScope , isGlobalVariableScope ) ;
130
- } ) ;
132
+ if ( ! nodeWithLexicalScope ) {
133
+ return ;
134
+ }
135
+
136
+ for ( const variable of scope . variables ) {
137
+ if ( variable . name === ScopeIdentifiersTransformer . argumentsVariableName ) {
138
+ continue ;
139
+ }
140
+
141
+ if ( ! this . options . renameGlobals && isGlobalDeclaration ) {
142
+ const isImportBindingOrCatchClauseIdentifier : boolean = variable . defs
143
+ . every ( ( definition : eslintScope . Definition ) =>
144
+ definition . type === 'ImportBinding'
145
+ || definition . type === 'CatchClause'
146
+ ) ;
147
+
148
+ // skip all global identifiers except import statement and catch clause parameter identifiers
149
+ if ( ! isImportBindingOrCatchClauseIdentifier ) {
150
+ continue ;
151
+ }
152
+ }
153
+
154
+ this . transformScopeVariableIdentifiers ( variable , nodeWithLexicalScope , isGlobalDeclaration ) ;
155
+ }
131
156
132
157
for ( const childScope of scope . childScopes ) {
133
158
this . traverseScopeVariables ( childScope ) ;
@@ -136,117 +161,86 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
136
161
137
162
/**
138
163
* @param {Variable } variable
139
- * @param {Scope } scope
140
- * @param {Scope } variableScope
141
- * @param {boolean } isGlobalVariableScope
164
+ * @param {TNodeWithLexicalScope } lexicalScopeNode
165
+ * @param {boolean } isGlobalDeclaration
142
166
*/
143
- private processScopeVariableIdentifiers (
167
+ private transformScopeVariableIdentifiers (
144
168
variable : eslintScope . Variable ,
145
- scope : eslintScope . Scope ,
146
- variableScope : eslintScope . Scope ,
147
- isGlobalVariableScope : boolean
169
+ lexicalScopeNode : TNodeWithLexicalScope ,
170
+ isGlobalDeclaration : boolean
148
171
) : void {
149
- if ( variable . name === ScopeIdentifiersTransformer . argumentsVariableName ) {
150
- return ;
151
- }
152
-
153
- if ( ! this . options . renameGlobals && isGlobalVariableScope ) {
154
- const isImportBindingOrCatchClauseIdentifier : boolean = variable . defs
155
- . every ( ( definition : eslintScope . Definition ) =>
156
- definition . type === 'ImportBinding'
157
- || definition . type === 'CatchClause'
158
- ) ;
159
-
160
- // skip all global identifiers except import statement and catch clause identifiers
161
- if ( ! isImportBindingOrCatchClauseIdentifier ) {
162
- return ;
163
- }
164
- }
165
-
166
172
for ( const identifier of variable . identifiers ) {
167
- if ( ! this . isReplaceableIdentifierNode ( variable , identifier , variableScope . block ) ) {
173
+ if ( ! this . isReplaceableIdentifierNode ( identifier , lexicalScopeNode , variable ) ) {
168
174
continue ;
169
175
}
170
176
171
- identifier . name = this . getNewIdentifierName (
172
- identifier ,
173
- scope ,
174
- variableScope ,
175
- isGlobalVariableScope
176
- ) ;
177
-
178
- // rename of references
179
- variable . references . forEach ( ( reference : eslintScope . Reference ) => {
180
- reference . identifier . name = identifier . name ;
181
- } ) ;
182
-
183
- // rename of function default parameter identifiers if exists
184
- ( < any > variable . scope . block ) . defaults ?. forEach ( ( node : ESTree . Node ) => {
185
- if ( NodeGuards . isIdentifierNode ( node ) && node . name === variable . name ) {
186
- node . name = identifier . name ;
187
- }
188
- } ) ;
177
+ this . storeIdentifierName ( identifier , lexicalScopeNode , isGlobalDeclaration ) ;
178
+ this . replaceIdentifierName ( identifier , lexicalScopeNode , variable ) ;
189
179
}
190
180
}
191
181
192
182
/**
193
183
* @param {Identifier } identifierNode
194
- * @param {Scope } scope
195
- * @param {Scope } variableScope
196
- * @param {boolean } isGlobalVariableScope
197
- * @returns {string }
184
+ * @param {TNodeWithLexicalScope } lexicalScopeNode
185
+ * @param {boolean } isGlobalDeclaration
198
186
*/
199
- private getNewIdentifierName (
187
+ private storeIdentifierName (
200
188
identifierNode : ESTree . Identifier ,
201
- scope : eslintScope . Scope ,
202
- variableScope : eslintScope . Scope ,
203
- isGlobalVariableScope : boolean
204
- ) : string {
205
- if ( ! identifierNode . parentNode || ! NodeGuards . isNodeWithBlockLexicalScope ( variableScope . block ) ) {
206
- return identifierNode . name ;
207
- }
208
-
209
- // prevent class name renaming twice for outer scope and for class scope
210
- if ( scope . type === 'class' && this . isClassDeclarationNameIdentifierNode ( identifierNode , identifierNode . parentNode ) ) {
211
- return identifierNode . name ;
189
+ lexicalScopeNode : TNodeWithLexicalScope ,
190
+ isGlobalDeclaration : boolean
191
+ ) : void {
192
+ if ( isGlobalDeclaration ) {
193
+ this . identifierObfuscatingReplacer . storeGlobalName ( identifierNode , lexicalScopeNode ) ;
194
+ } else {
195
+ this . identifierObfuscatingReplacer . storeLocalName ( identifierNode , lexicalScopeNode ) ;
212
196
}
213
-
214
- isGlobalVariableScope
215
- ? this . identifierObfuscatingReplacer . storeGlobalName ( identifierNode , variableScope . block )
216
- : this . identifierObfuscatingReplacer . storeLocalName ( identifierNode , variableScope . block ) ;
217
-
218
- return this . identifierObfuscatingReplacer . replace ( identifierNode , variableScope . block ) . name ;
219
197
}
220
198
221
199
/**
222
200
* @param {Identifier } identifierNode
223
- * @param {Node } parentNode
224
- * @returns { identifierNode is Identifier }
201
+ * @param {TNodeWithLexicalScope } lexicalScopeNode
202
+ * @param { Variable } variable
225
203
*/
226
- private isClassDeclarationNameIdentifierNode (
204
+ private replaceIdentifierName (
227
205
identifierNode : ESTree . Identifier ,
228
- parentNode : ESTree . Node
229
- ) : identifierNode is ESTree . Identifier {
230
- return NodeGuards . isClassDeclarationNode ( parentNode )
231
- && parentNode . id === identifierNode ;
206
+ lexicalScopeNode : TNodeWithLexicalScope ,
207
+ variable : eslintScope . Variable
208
+ ) : void {
209
+ const newIdentifier : ESTree . Identifier = this . identifierObfuscatingReplacer
210
+ . replace ( identifierNode , lexicalScopeNode ) ;
211
+
212
+ identifierNode . name = newIdentifier . name ;
213
+
214
+ // rename of references
215
+ variable . references . forEach ( ( reference : eslintScope . Reference ) => {
216
+ reference . identifier . name = identifierNode . name ;
217
+ } ) ;
218
+
219
+ // rename of function default parameter identifiers if exists
220
+ ( < any > variable . scope . block ) . defaults ?. forEach ( ( node : ESTree . Node ) => {
221
+ if ( NodeGuards . isIdentifierNode ( node ) && node . name === variable . name ) {
222
+ node . name = identifierNode . name ;
223
+ }
224
+ } ) ;
232
225
}
233
226
234
227
/**
235
- * @param {Variable } variable
236
228
* @param {Identifier } identifierNode
237
- * @param {Scope["block"] } lexicalScopeNode
229
+ * @param {TNodeWithLexicalScope } lexicalScopeNode
230
+ * @param {Variable } variable
238
231
* @returns {boolean }
239
232
*/
240
233
private isReplaceableIdentifierNode (
241
- variable : eslintScope . Variable ,
242
234
identifierNode : ESTree . Identifier ,
243
- lexicalScopeNode : eslintScope . Scope [ 'block' ]
244
- ) : boolean {
235
+ lexicalScopeNode : TNodeWithLexicalScope ,
236
+ variable : eslintScope . Variable
237
+ ) : identifierNode is ESTree . Identifier & { parentNode : ESTree . Node } {
245
238
const parentNode : ESTree . Node | undefined = identifierNode . parentNode ;
246
239
247
240
return ! ! parentNode
248
241
&& ! NodeMetadata . isIgnoredNode ( identifierNode )
249
242
&& ! this . isProhibitedPropertyNode ( identifierNode , parentNode )
243
+ && ! this . isProhibitedClassDeclarationNameIdentifierNode ( variable , identifierNode , parentNode )
250
244
&& ! this . isProhibitedExportNamedClassDeclarationIdentifierNode ( identifierNode , parentNode )
251
245
&& ! this . isProhibitedExportNamedFunctionDeclarationIdentifierNode ( identifierNode , parentNode )
252
246
&& ! this . isProhibitedExportNamedVariableDeclarationIdentifierNode ( identifierNode , parentNode )
@@ -255,6 +249,22 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
255
249
&& ! NodeGuards . isLabelIdentifierNode ( identifierNode , parentNode ) ;
256
250
}
257
251
252
+ /**
253
+ * @param {Variable } variable
254
+ * @param {Identifier } identifierNode
255
+ * @param {Node } parentNode
256
+ * @returns {identifierNode is Identifier }
257
+ */
258
+ private isProhibitedClassDeclarationNameIdentifierNode (
259
+ variable : eslintScope . Variable ,
260
+ identifierNode : ESTree . Identifier ,
261
+ parentNode : ESTree . Node
262
+ ) : identifierNode is ESTree . Identifier {
263
+ return NodeGuards . isClassDeclarationNode ( variable . scope . block )
264
+ && NodeGuards . isClassDeclarationNode ( parentNode )
265
+ && parentNode . id === identifierNode ;
266
+ }
267
+
258
268
/**
259
269
* @param {Identifier } identifierNode
260
270
* @param {Node } parentNode
@@ -331,13 +341,13 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
331
341
*
332
342
* @param {Variable } variable
333
343
* @param {Identifier } identifierNode
334
- * @param {eslintScope.Scope['block'] } lexicalScopeNode
344
+ * @param {TNodeWithLexicalScope } lexicalScopeNode
335
345
* @returns {boolean }
336
346
*/
337
347
private isProhibitedVariableNameUsedInObjectPatternNode (
338
348
variable : eslintScope . Variable ,
339
349
identifierNode : ESTree . Identifier ,
340
- lexicalScopeNode : eslintScope . Scope [ 'block' ]
350
+ lexicalScopeNode : TNodeWithLexicalScope
341
351
) : boolean {
342
352
let isLexicalScopeHasObjectPatternWithoutDeclaration : boolean | undefined =
343
353
this . lexicalScopesWithObjectPatternWithoutDeclarationMap . get ( lexicalScopeNode ) ;
0 commit comments