@@ -355,11 +355,29 @@ module.exports = {
355355 * fix ( fixer ) {
356356 for ( const [ entrypoint , importSpecifiers ] of changes ) {
357357 const importDeclaration = node . parent . body . find ( node => {
358- return node . type === 'ImportDeclaration' && node . source . value === entrypoint
358+ return (
359+ node . type === 'ImportDeclaration' && node . source . value === entrypoint && node . importKind !== 'type'
360+ )
361+ } )
362+ const typeImportDeclaration = node . parent . body . find ( node => {
363+ return (
364+ node . type === 'ImportDeclaration' && node . source . value === entrypoint && node . importKind === 'type'
365+ )
359366 } )
360367 const namedSpecifiers = importSpecifiers
361- . filter ( ( [ imported ] ) => {
362- return imported !== 'default'
368+ . filter ( ( [ imported , _local , type ] ) => {
369+ return imported !== 'default' && type !== 'type'
370+ } )
371+ . map ( ( [ imported , local , type ] ) => {
372+ const prefix = type === 'type' ? 'type ' : ''
373+ if ( imported !== local ) {
374+ return `${ prefix } ${ imported } as ${ local } `
375+ }
376+ return `${ prefix } ${ imported } `
377+ } )
378+ const namedTypeSpecifiers = importSpecifiers
379+ . filter ( ( [ imported , _local , type ] ) => {
380+ return imported !== 'default' && type === 'type'
363381 } )
364382 . map ( ( [ imported , local , type ] ) => {
365383 const prefix = type === 'type' ? 'type ' : ''
@@ -368,46 +386,82 @@ module.exports = {
368386 }
369387 return `${ prefix } ${ imported } `
370388 } )
371- let defaultSpecifier = importSpecifiers . find ( ( [ imported ] ) => {
372- return imported === 'default'
389+ let defaultSpecifier = importSpecifiers . find ( ( [ imported , _local , type ] ) => {
390+ return imported === 'default' && type !== 'type'
373391 } )
374392 if ( defaultSpecifier ) {
375- const prefix = defaultSpecifier [ 2 ] === 'type' ? 'type ' : ''
376- defaultSpecifier = `${ prefix } ${ defaultSpecifier [ 1 ] } `
393+ defaultSpecifier = defaultSpecifier [ 1 ]
394+ }
395+ let defaultTypeSpecifier = importSpecifiers . find ( ( [ imported , _local , type ] ) => {
396+ return imported === 'default' && type === 'type'
397+ } )
398+ if ( defaultTypeSpecifier ) {
399+ defaultTypeSpecifier = `type ${ defaultTypeSpecifier [ 1 ] } `
377400 }
378401
379- const hasNamedSpecifiers = namedSpecifiers . length > 0
380- const hasDefaultSpecifier = ! ! defaultSpecifier
381-
382- if ( importDeclaration ) {
402+ if ( typeImportDeclaration || importDeclaration ) {
383403 yield fixer . remove ( node )
404+ }
405+
406+ // Reuse a type import if it exists
407+ if ( typeImportDeclaration ) {
408+ const firstSpecifier = typeImportDeclaration . specifiers [ 0 ]
409+ const lastSpecifier = typeImportDeclaration . specifiers [ importDeclaration . specifiers . length - 1 ]
384410
385- if ( importDeclaration . specifiers . length === 0 ) {
386- throw new Error ( 'Import Declaration has no specifiers' )
411+ if ( defaultTypeSpecifier ) {
412+ const postfix =
413+ namedTypeSpecifiers . length > 0 || typeImportDeclaration . specifiers . length > 0 ? ', ' : ' '
414+ yield fix . insertTextBeforeRange (
415+ [ firstSpecifier . range [ 0 ] - 1 , firstSpecifier . range [ 1 ] ] ,
416+ `${ defaultTypeSpecifier } ${ postfix } ` ,
417+ )
387418 }
388419
420+ if ( namedTypeSpecifiers . length > 0 ) {
421+ yield fixer . insertTextAfter ( lastSpecifier , `, ${ namedTypeSpecifiers . join ( ', ' ) } ` )
422+ }
423+ }
424+
425+ // Reuse an import declaration if one exists
426+ if ( importDeclaration ) {
389427 const firstSpecifier = importDeclaration . specifiers [ 0 ]
390428 const lastSpecifier = importDeclaration . specifiers [ importDeclaration . specifiers . length - 1 ]
391429
392- if ( hasDefaultSpecifier ) {
393- yield fixer . insertTextBefore ( firstSpecifier , `${ defaultSpecifier } , ` )
430+ if ( defaultSpecifier ) {
431+ const postfix = namedSpecifiers . length > 0 || importDeclaration . specifiers . length > 0 ? ', ' : ' '
432+ yield fix . insertTextBeforeRange (
433+ [ firstSpecifier . range [ 0 ] - 1 , firstSpecifier . range [ 1 ] ] ,
434+ `${ defaultSpecifier } ${ postfix } ` ,
435+ )
394436 }
395437
396- if ( hasNamedSpecifiers ) {
397- yield fixer . insertTextAfter ( lastSpecifier , `, ${ namedSpecifiers . join ( ', ' ) } ` )
438+ if ( namedSpecifiers . length > 0 || ( ! typeImportDeclaration && namedTypeSpecifiers . length > 0 ) ) {
439+ const specifiers = [ ...namedSpecifiers ]
440+ if ( ! typeImportDeclaration ) {
441+ specifiers . push ( ...namedTypeSpecifiers )
442+ }
443+ yield fixer . insertTextAfter ( lastSpecifier , `, ${ specifiers . join ( ', ' ) } ` )
398444 }
399445 } else {
446+ const specifiers = [ ...namedSpecifiers ]
447+ if ( ! typeImportDeclaration ) {
448+ specifiers . push ( ...namedTypeSpecifiers )
449+ }
400450 let declaration = 'import '
401451
402- if ( hasDefaultSpecifier ) {
452+ if ( defaultSpecifier ) {
403453 declaration += defaultSpecifier
404454 }
405455
406- if ( hasNamedSpecifiers ) {
407- if ( hasDefaultSpecifier ) {
456+ if ( defaultTypeSpecifier && ! typeImportDeclaration ) {
457+ declaration += defaultTypeSpecifier
458+ }
459+
460+ if ( specifiers . length > 0 ) {
461+ if ( defaultSpecifier || defaultTypeSpecifier ) {
408462 declaration += ', '
409463 }
410- declaration += `{${ namedSpecifiers . join ( ', ' ) } }`
464+ declaration += `{${ specifiers . join ( ', ' ) } }`
411465 }
412466
413467 declaration += ` from '${ entrypoint } '`
0 commit comments