@@ -48,17 +48,17 @@ describe("ES6 class", () => {
48
48
expect ( scope . isStrict ) . to . be . false ;
49
49
expect ( scope . variables ) . to . have . length ( 1 ) ;
50
50
expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "Derived" ) ;
51
- expect ( scope . references ) . to . have . length ( 2 ) ;
52
- expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Base" ) ;
53
- expect ( scope . references [ 1 ] . identifier . name ) . to . be . equal ( "Derived" ) ;
51
+ expect ( scope . references ) . to . have . length ( 1 ) ;
52
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Derived" ) ;
54
53
55
54
scope = scopeManager . scopes [ 1 ] ;
56
55
expect ( scope . type ) . to . be . equal ( "class" ) ;
57
56
expect ( scope . block . type ) . to . be . equal ( "ClassDeclaration" ) ;
58
57
expect ( scope . isStrict ) . to . be . true ;
59
58
expect ( scope . variables ) . to . have . length ( 1 ) ;
60
59
expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "Derived" ) ;
61
- expect ( scope . references ) . to . have . length ( 0 ) ;
60
+ expect ( scope . references ) . to . have . length ( 1 ) ;
61
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Base" ) ;
62
62
63
63
scope = scopeManager . scopes [ 2 ] ;
64
64
expect ( scope . type ) . to . be . equal ( "function" ) ;
@@ -87,16 +87,16 @@ describe("ES6 class", () => {
87
87
expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
88
88
expect ( scope . isStrict ) . to . be . false ;
89
89
expect ( scope . variables ) . to . have . length ( 0 ) ;
90
- expect ( scope . references ) . to . have . length ( 1 ) ;
91
- expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Base" ) ;
90
+ expect ( scope . references ) . to . have . length ( 0 ) ;
92
91
93
92
scope = scopeManager . scopes [ 1 ] ;
94
93
expect ( scope . type ) . to . be . equal ( "class" ) ;
95
94
expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
96
95
expect ( scope . isStrict ) . to . be . true ;
97
96
expect ( scope . variables ) . to . have . length ( 1 ) ;
98
97
expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "Derived" ) ;
99
- expect ( scope . references ) . to . have . length ( 0 ) ;
98
+ expect ( scope . references ) . to . have . length ( 1 ) ;
99
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Base" ) ;
100
100
101
101
scope = scopeManager . scopes [ 2 ] ;
102
102
expect ( scope . type ) . to . be . equal ( "function" ) ;
@@ -121,12 +121,13 @@ describe("ES6 class", () => {
121
121
expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
122
122
expect ( scope . isStrict ) . to . be . false ;
123
123
expect ( scope . variables ) . to . have . length ( 0 ) ;
124
- expect ( scope . references ) . to . have . length ( 1 ) ;
125
- expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Base" ) ;
124
+ expect ( scope . references ) . to . have . length ( 0 ) ;
126
125
127
126
scope = scopeManager . scopes [ 1 ] ;
128
127
expect ( scope . type ) . to . be . equal ( "class" ) ;
129
128
expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
129
+ expect ( scope . references ) . to . have . length ( 1 ) ;
130
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "Base" ) ;
130
131
131
132
scope = scopeManager . scopes [ 2 ] ;
132
133
expect ( scope . type ) . to . be . equal ( "function" ) ;
@@ -177,6 +178,193 @@ describe("ES6 class", () => {
177
178
expect ( scope . references [ 1 ] . identifier . name ) . to . be . equal ( "yuyushiki" ) ;
178
179
} ) ;
179
180
181
+ // https://github.com/eslint/eslint-scope/issues/59
182
+ it ( "class heritage may refer class name in class expressions #1" , ( ) => {
183
+ const ast = espree ( `
184
+ const A = class A extends A {}
185
+ ` ) ;
186
+
187
+ const scopeManager = analyze ( ast , { ecmaVersion : 6 } ) ;
188
+
189
+ expect ( scopeManager . scopes ) . to . have . length ( 2 ) ;
190
+
191
+ let scope = scopeManager . scopes [ 0 ] ;
192
+
193
+ expect ( scope . type ) . to . be . equal ( "global" ) ;
194
+ expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
195
+ expect ( scope . isStrict ) . to . be . false ;
196
+ expect ( scope . variables ) . to . have . length ( 1 ) ;
197
+ expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "A" ) ; // variable `A` defined by `const A`
198
+ expect ( scope . variables [ 0 ] . references ) . to . have . length ( 1 ) ; // init reference `A` in `const A`
199
+ expect ( scope . variables [ 0 ] . references [ 0 ] . init ) . to . be . true ;
200
+ expect ( scope . references ) . to . have . length ( 1 ) ;
201
+ expect ( scope . references [ 0 ] ) . to . be . equal ( scope . variables [ 0 ] . references [ 0 ] ) ;
202
+
203
+ scope = scopeManager . scopes [ 1 ] ;
204
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
205
+ expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
206
+ expect ( scope . isStrict ) . to . be . true ;
207
+ expect ( scope . variables ) . to . have . length ( 1 ) ;
208
+ expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "A" ) ; // variable `A` defined by `class A`
209
+ expect ( scope . variables [ 0 ] . references ) . to . have . length ( 1 ) ; // reference `A` in `extends A`
210
+ expect ( scope . references ) . to . have . length ( 1 ) ;
211
+ expect ( scope . references [ 0 ] . resolved ) . to . be . equal ( scope . variables [ 0 ] ) ;
212
+ expect ( scope . references [ 0 ] ) . to . be . equal ( scope . variables [ 0 ] . references [ 0 ] ) ;
213
+ } ) ;
214
+
215
+ it ( "class heritage may refer class name in class expressions #2" , ( ) => {
216
+ const ast = espree ( `
217
+ let foo;
218
+ (class C extends (foo = C, class {}) {});
219
+ ` ) ;
220
+
221
+ const scopeManager = analyze ( ast , { ecmaVersion : 6 } ) ;
222
+
223
+ expect ( scopeManager . scopes ) . to . have . length ( 3 ) ;
224
+
225
+ let scope = scopeManager . scopes [ 0 ] ;
226
+
227
+ expect ( scope . type ) . to . be . equal ( "global" ) ;
228
+ expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
229
+ expect ( scope . isStrict ) . to . be . false ;
230
+ expect ( scope . variables ) . to . have . length ( 1 ) ;
231
+ expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "foo" ) ;
232
+ expect ( scope . references ) . to . have . length ( 0 ) ;
233
+
234
+ scope = scopeManager . scopes [ 1 ] ;
235
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
236
+ expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
237
+ expect ( scope . isStrict ) . to . be . true ;
238
+ expect ( scope . variables ) . to . have . length ( 1 ) ;
239
+ expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "C" ) ;
240
+ expect ( scope . variables [ 0 ] . references ) . to . have . length ( 1 ) ;
241
+ expect ( scope . references ) . to . have . length ( 2 ) ;
242
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "foo" ) ;
243
+ expect ( scope . references [ 1 ] . identifier . name ) . to . be . equal ( "C" ) ;
244
+
245
+ // `C` in `foo = C` is a reference to variable `C` defined by `class C`
246
+ expect ( scope . references [ 1 ] . resolved ) . to . be . equal ( scope . variables [ 0 ] ) ;
247
+ expect ( scope . references [ 1 ] ) . to . be . equal ( scope . variables [ 0 ] . references [ 0 ] ) ;
248
+
249
+ scope = scopeManager . scopes [ 2 ] ;
250
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
251
+ expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
252
+ expect ( scope . isStrict ) . to . be . true ;
253
+ expect ( scope . variables ) . to . have . length ( 0 ) ;
254
+ expect ( scope . references ) . to . have . length ( 0 ) ;
255
+ } ) ;
256
+
257
+ it ( "class heritage may refer class name in class declarations" , ( ) => {
258
+ const ast = espree ( `
259
+ let foo;
260
+ class C extends (foo = C, class {}) {}
261
+ new C();
262
+ ` ) ;
263
+
264
+ const scopeManager = analyze ( ast , { ecmaVersion : 6 } ) ;
265
+
266
+ expect ( scopeManager . scopes ) . to . have . length ( 3 ) ;
267
+
268
+ let scope = scopeManager . scopes [ 0 ] ;
269
+
270
+ expect ( scope . type ) . to . be . equal ( "global" ) ;
271
+ expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
272
+ expect ( scope . isStrict ) . to . be . false ;
273
+ expect ( scope . variables ) . to . have . length ( 2 ) ;
274
+ expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "foo" ) ;
275
+ expect ( scope . variables [ 0 ] . references ) . to . have . length ( 1 ) ;
276
+ expect ( scope . variables [ 1 ] . name ) . to . be . equal ( "C" ) ;
277
+ expect ( scope . variables [ 1 ] . references ) . to . have . length ( 1 ) ;
278
+ expect ( scope . references ) . to . have . length ( 1 ) ;
279
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "C" ) ; // `C` in `new C()`
280
+ expect ( scope . references [ 0 ] . resolved ) . to . be . equal ( scope . variables [ 1 ] ) ;
281
+ expect ( scope . references [ 0 ] ) . to . be . equal ( scope . variables [ 1 ] . references [ 0 ] ) ;
282
+
283
+ scope = scopeManager . scopes [ 1 ] ;
284
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
285
+ expect ( scope . block . type ) . to . be . equal ( "ClassDeclaration" ) ;
286
+ expect ( scope . isStrict ) . to . be . true ;
287
+ expect ( scope . variables ) . to . have . length ( 1 ) ;
288
+ expect ( scope . variables [ 0 ] . name ) . to . be . equal ( "C" ) ;
289
+ expect ( scope . variables [ 0 ] . references ) . to . have . length ( 1 ) ;
290
+ expect ( scope . references ) . to . have . length ( 2 ) ;
291
+ expect ( scope . references [ 0 ] . identifier . name ) . to . be . equal ( "foo" ) ;
292
+ expect ( scope . references [ 1 ] . identifier . name ) . to . be . equal ( "C" ) ; // `C` in `foo = C`
293
+
294
+ /*
295
+ * `class C` creates two variables `C`: one in the scope where the class
296
+ * is declared, another in the class scope. References inside the class
297
+ * should be to the variable in the class scope.
298
+ */
299
+ expect ( scope . references [ 1 ] . resolved ) . to . be . equal ( scope . variables [ 0 ] ) ;
300
+ expect ( scope . references [ 1 ] ) . to . be . equal ( scope . variables [ 0 ] . references [ 0 ] ) ;
301
+
302
+ scope = scopeManager . scopes [ 2 ] ;
303
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
304
+ expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
305
+ expect ( scope . isStrict ) . to . be . true ;
306
+ expect ( scope . variables ) . to . have . length ( 0 ) ;
307
+ expect ( scope . references ) . to . have . length ( 0 ) ;
308
+ } ) ;
309
+
310
+ it ( "inner scopes in the class heritage of a class expression are nested in the class scope" , ( ) => {
311
+ const ast = espree ( `
312
+ (class extends function () {} {})
313
+ ` ) ;
314
+
315
+ const scopeManager = analyze ( ast , { ecmaVersion : 6 } ) ;
316
+
317
+ expect ( scopeManager . scopes ) . to . have . length ( 3 ) ;
318
+
319
+ let scope = scopeManager . scopes [ 0 ] ;
320
+
321
+ expect ( scope . type ) . to . be . equal ( "global" ) ;
322
+ expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
323
+ expect ( scope . isStrict ) . to . be . false ;
324
+
325
+ scope = scopeManager . scopes [ 1 ] ;
326
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
327
+ expect ( scope . block . type ) . to . be . equal ( "ClassExpression" ) ;
328
+ expect ( scope . isStrict ) . to . be . true ;
329
+
330
+ scope = scopeManager . scopes [ 2 ] ;
331
+ expect ( scope . type ) . to . be . equal ( "function" ) ;
332
+ expect ( scope . block . type ) . to . be . equal ( "FunctionExpression" ) ;
333
+ expect ( scope . isStrict ) . to . be . true ;
334
+ expect ( scope . upper ) . to . be . equal ( scopeManager . scopes [ 1 ] ) ;
335
+ expect ( scopeManager . scopes [ 1 ] . childScopes ) . to . have . length ( 1 ) ;
336
+ expect ( scopeManager . scopes [ 1 ] . childScopes [ 0 ] ) . to . be . equal ( scope ) ;
337
+ } ) ;
338
+
339
+ it ( "inner scopes in the class heritage of a class declaration are nested in the class scope" , ( ) => {
340
+ const ast = espree ( `
341
+ class C extends function () {} {}
342
+ ` ) ;
343
+
344
+ const scopeManager = analyze ( ast , { ecmaVersion : 6 } ) ;
345
+
346
+ expect ( scopeManager . scopes ) . to . have . length ( 3 ) ;
347
+
348
+ let scope = scopeManager . scopes [ 0 ] ;
349
+
350
+ expect ( scope . type ) . to . be . equal ( "global" ) ;
351
+ expect ( scope . block . type ) . to . be . equal ( "Program" ) ;
352
+ expect ( scope . isStrict ) . to . be . false ;
353
+
354
+ scope = scopeManager . scopes [ 1 ] ;
355
+ expect ( scope . type ) . to . be . equal ( "class" ) ;
356
+ expect ( scope . block . type ) . to . be . equal ( "ClassDeclaration" ) ;
357
+ expect ( scope . isStrict ) . to . be . true ;
358
+
359
+ scope = scopeManager . scopes [ 2 ] ;
360
+ expect ( scope . type ) . to . be . equal ( "function" ) ;
361
+ expect ( scope . block . type ) . to . be . equal ( "FunctionExpression" ) ;
362
+ expect ( scope . isStrict ) . to . be . true ;
363
+ expect ( scope . upper ) . to . be . equal ( scopeManager . scopes [ 1 ] ) ;
364
+ expect ( scopeManager . scopes [ 1 ] . childScopes ) . to . have . length ( 1 ) ;
365
+ expect ( scopeManager . scopes [ 1 ] . childScopes [ 0 ] ) . to . be . equal ( scope ) ;
366
+ } ) ;
367
+
180
368
it ( "regression #49" , ( ) => {
181
369
const ast = espree ( `
182
370
class Shoe {
0 commit comments