@@ -252,23 +252,25 @@ export default util.createRule<Options, MessageIds>({
252
252
? node . specifiers [ 0 ]
253
253
: null ;
254
254
const namespaceSpecifier : TSESTree . ImportNamespaceSpecifier | null =
255
- node . specifiers [ 0 ] . type === AST_NODE_TYPES . ImportNamespaceSpecifier
256
- ? node . specifiers [ 0 ]
257
- : null ;
255
+ node . specifiers . find (
256
+ ( specifier ) : specifier is TSESTree . ImportNamespaceSpecifier =>
257
+ specifier . type === AST_NODE_TYPES . ImportNamespaceSpecifier ,
258
+ ) ?? null ;
258
259
const namedSpecifiers : TSESTree . ImportSpecifier [ ] = node . specifiers . filter (
259
260
( specifier ) : specifier is TSESTree . ImportSpecifier =>
260
261
specifier . type === AST_NODE_TYPES . ImportSpecifier ,
261
262
) ;
262
263
263
- if ( namespaceSpecifier ) {
264
+ if ( namespaceSpecifier && ! defaultSpecifier ) {
264
265
// e.g.
265
266
// import * as types from 'foo'
266
267
yield * fixToTypeImportByInsertType ( fixer , node , false ) ;
267
268
return ;
268
269
} else if ( defaultSpecifier ) {
269
270
if (
270
271
report . typeSpecifiers . includes ( defaultSpecifier ) &&
271
- namedSpecifiers . length === 0
272
+ namedSpecifiers . length === 0 &&
273
+ ! namespaceSpecifier
272
274
) {
273
275
// e.g.
274
276
// import Type from 'foo'
@@ -279,7 +281,8 @@ export default util.createRule<Options, MessageIds>({
279
281
if (
280
282
namedSpecifiers . every ( specifier =>
281
283
report . typeSpecifiers . includes ( specifier ) ,
282
- )
284
+ ) &&
285
+ ! namespaceSpecifier
283
286
) {
284
287
// e.g.
285
288
// import {Type1, Type2} from 'foo'
@@ -336,11 +339,40 @@ export default util.createRule<Options, MessageIds>({
336
339
}
337
340
}
338
341
342
+ const fixesRemoveTypeNamespaceSpecifier : TSESLint . RuleFix [ ] = [ ] ;
343
+ if (
344
+ namespaceSpecifier &&
345
+ report . typeSpecifiers . includes ( namespaceSpecifier )
346
+ ) {
347
+ // e.g.
348
+ // import Foo, * as Type from 'foo'
349
+ // import DefType, * as Type from 'foo'
350
+ // import DefType, * as Type from 'foo'
351
+ const commaToken = util . nullThrows (
352
+ sourceCode . getTokenBefore ( namespaceSpecifier , util . isCommaToken ) ,
353
+ util . NullThrowsReasons . MissingToken ( ',' , node . type ) ,
354
+ ) ;
355
+
356
+ // import Def, * as Ns from 'foo'
357
+ // ^^^^^^^^^ remove
358
+ fixesRemoveTypeNamespaceSpecifier . push (
359
+ fixer . removeRange ( [ commaToken . range [ 0 ] , namespaceSpecifier . range [ 1 ] ] ) ,
360
+ ) ;
361
+
362
+ // import type * as Ns from 'foo'
363
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ insert
364
+ yield fixer . insertTextBefore (
365
+ node ,
366
+ `import type ${ sourceCode . getText (
367
+ namespaceSpecifier ,
368
+ ) } from ${ sourceCode . getText ( node . source ) } ;\n`,
369
+ ) ;
370
+ }
339
371
if (
340
372
defaultSpecifier &&
341
373
report . typeSpecifiers . includes ( defaultSpecifier )
342
374
) {
343
- if ( typeNamedSpecifiers . length === namedSpecifiers . length ) {
375
+ if ( report . typeSpecifiers . length === node . specifiers . length ) {
344
376
const importToken = util . nullThrows (
345
377
sourceCode . getFirstToken ( node , isImportToken ) ,
346
378
util . NullThrowsReasons . MissingToken ( 'import' , node . type ) ,
@@ -349,20 +381,36 @@ export default util.createRule<Options, MessageIds>({
349
381
// ^^^^ insert
350
382
yield fixer . insertTextAfter ( importToken , ' type' ) ;
351
383
} else {
384
+ const commaToken = util . nullThrows (
385
+ sourceCode . getTokenAfter ( defaultSpecifier , util . isCommaToken ) ,
386
+ util . NullThrowsReasons . MissingToken ( ',' , defaultSpecifier . type ) ,
387
+ ) ;
388
+ // import Type , {...} from 'foo'
389
+ // ^^^^^ pick
390
+ const defaultText = sourceCode . text
391
+ . slice ( defaultSpecifier . range [ 0 ] , commaToken . range [ 0 ] )
392
+ . trim ( ) ;
352
393
yield fixer . insertTextBefore (
353
394
node ,
354
- `import type ${ sourceCode . getText (
355
- defaultSpecifier ,
356
- ) } from ${ sourceCode . getText ( node . source ) } ;\n`,
395
+ `import type ${ defaultText } from ${ sourceCode . getText (
396
+ node . source ,
397
+ ) } ;\n`,
398
+ ) ;
399
+ const afterToken = util . nullThrows (
400
+ sourceCode . getTokenAfter ( commaToken , { includeComments : true } ) ,
401
+ util . NullThrowsReasons . MissingToken ( 'any token' , node . type ) ,
357
402
) ;
358
403
// import Type , {...} from 'foo'
359
- // ^^^^^^ remove
360
- yield fixer . remove ( defaultSpecifier ) ;
361
- yield fixer . remove ( sourceCode . getTokenAfter ( defaultSpecifier ) ! ) ;
404
+ // ^^^^^^^ remove
405
+ yield fixer . removeRange ( [
406
+ defaultSpecifier . range [ 0 ] ,
407
+ afterToken . range [ 0 ] ,
408
+ ] ) ;
362
409
}
363
410
}
364
411
365
412
yield * fixesNamedSpecifiers . removeTypeNamedSpecifiers ;
413
+ yield * fixesRemoveTypeNamespaceSpecifier ;
366
414
367
415
yield * afterFixes ;
368
416
@@ -376,6 +424,12 @@ export default util.createRule<Options, MessageIds>({
376
424
typeNamedSpecifiersText : string ;
377
425
removeTypeNamedSpecifiers : TSESLint . RuleFix [ ] ;
378
426
} {
427
+ if ( allNamedSpecifiers . length === 0 ) {
428
+ return {
429
+ typeNamedSpecifiersText : '' ,
430
+ removeTypeNamedSpecifiers : [ ] ,
431
+ } ;
432
+ }
379
433
const typeNamedSpecifiersTexts : string [ ] = [ ] ;
380
434
const removeTypeNamedSpecifiers : TSESLint . RuleFix [ ] = [ ] ;
381
435
if ( typeNamedSpecifiers . length === allNamedSpecifiers . length ) {
@@ -564,7 +618,11 @@ export default util.createRule<Options, MessageIds>({
564
618
) ,
565
619
util . NullThrowsReasons . MissingToken ( 'type' , node . type ) ,
566
620
) ;
567
- return fixer . remove ( typeToken ) ;
621
+ const afterToken = util . nullThrows (
622
+ sourceCode . getTokenAfter ( typeToken , { includeComments : true } ) ,
623
+ util . NullThrowsReasons . MissingToken ( 'any token' , node . type ) ,
624
+ ) ;
625
+ return fixer . removeRange ( [ typeToken . range [ 0 ] , afterToken . range [ 0 ] ] ) ;
568
626
}
569
627
} ,
570
628
} ) ;
0 commit comments