@@ -114,14 +114,14 @@ import {
114
114
removeFileExtension ,
115
115
removeSuffix ,
116
116
RequireVariableStatement ,
117
+ sameMap ,
117
118
ScriptTarget ,
118
119
SemanticMeaning ,
119
120
shouldUseUriStyleNodeCoreModules ,
120
121
single ,
121
122
skipAlias ,
122
123
some ,
123
124
sort ,
124
- SortKind ,
125
125
SourceFile ,
126
126
stableSort ,
127
127
startsWith ,
@@ -1394,11 +1394,10 @@ function promoteFromTypeOnly(
1394
1394
switch ( aliasDeclaration . kind ) {
1395
1395
case SyntaxKind . ImportSpecifier :
1396
1396
if ( aliasDeclaration . isTypeOnly ) {
1397
- const sortKind = OrganizeImports . detectImportSpecifierSorting ( aliasDeclaration . parent . elements , preferences ) ;
1398
- if ( aliasDeclaration . parent . elements . length > 1 && sortKind ) {
1397
+ if ( aliasDeclaration . parent . elements . length > 1 ) {
1399
1398
const newSpecifier = factory . updateImportSpecifier ( aliasDeclaration , /*isTypeOnly*/ false , aliasDeclaration . propertyName , aliasDeclaration . name ) ;
1400
- const comparer = OrganizeImports . getOrganizeImportsComparer ( preferences , sortKind === SortKind . CaseInsensitive ) ;
1401
- const insertionIndex = OrganizeImports . getImportSpecifierInsertionIndex ( aliasDeclaration . parent . elements , newSpecifier , comparer , preferences ) ;
1399
+ const { specifierComparer } = OrganizeImports . getNamedImportSpecifierComparerWithDetection ( aliasDeclaration . parent . parent . parent , preferences , sourceFile ) ;
1400
+ const insertionIndex = OrganizeImports . getImportSpecifierInsertionIndex ( aliasDeclaration . parent . elements , newSpecifier , specifierComparer ) ;
1402
1401
if ( insertionIndex !== aliasDeclaration . parent . elements . indexOf ( aliasDeclaration ) ) {
1403
1402
changes . delete ( sourceFile , aliasDeclaration ) ;
1404
1403
changes . insertImportSpecifierAtIndex ( sourceFile , newSpecifier , aliasDeclaration . parent , insertionIndex ) ;
@@ -1440,8 +1439,9 @@ function promoteFromTypeOnly(
1440
1439
if ( convertExistingToTypeOnly ) {
1441
1440
const namedImports = tryCast ( importClause . namedBindings , isNamedImports ) ;
1442
1441
if ( namedImports && namedImports . elements . length > 1 ) {
1442
+ const sortState = OrganizeImports . getNamedImportSpecifierComparerWithDetection ( importClause . parent , preferences , sourceFile ) ;
1443
1443
if (
1444
- OrganizeImports . detectImportSpecifierSorting ( namedImports . elements , preferences ) &&
1444
+ ( sortState . isSorted !== false ) &&
1445
1445
aliasDeclaration . kind === SyntaxKind . ImportSpecifier &&
1446
1446
namedImports . elements . indexOf ( aliasDeclaration ) !== 0
1447
1447
) {
@@ -1478,6 +1478,7 @@ function doAddExistingFix(
1478
1478
return ;
1479
1479
}
1480
1480
1481
+ // promoteFromTypeOnly = true if we need to promote the entire original clause from type only
1481
1482
const promoteFromTypeOnly = clause . isTypeOnly && some ( [ defaultImport , ...namedImports ] , i => i ?. addAsTypeOnly === AddAsTypeOnly . NotAllowed ) ;
1482
1483
const existingSpecifiers = clause . namedBindings && tryCast ( clause . namedBindings , isNamedImports ) ?. elements ;
1483
1484
@@ -1487,25 +1488,7 @@ function doAddExistingFix(
1487
1488
}
1488
1489
1489
1490
if ( namedImports . length ) {
1490
- // sort case sensitivity:
1491
- // - if the user preference is explicit, use that
1492
- // - otherwise, if there are enough existing import specifiers in this import to detect unambiguously, use that
1493
- // - otherwise, detect from other imports in the file
1494
- let ignoreCaseForSorting : boolean | undefined ;
1495
- if ( typeof preferences . organizeImportsIgnoreCase === "boolean" ) {
1496
- ignoreCaseForSorting = preferences . organizeImportsIgnoreCase ;
1497
- }
1498
- else if ( existingSpecifiers ) {
1499
- const targetImportSorting = OrganizeImports . detectImportSpecifierSorting ( existingSpecifiers , preferences ) ;
1500
- if ( targetImportSorting !== SortKind . Both ) {
1501
- ignoreCaseForSorting = targetImportSorting === SortKind . CaseInsensitive ;
1502
- }
1503
- }
1504
- if ( ignoreCaseForSorting === undefined ) {
1505
- ignoreCaseForSorting = OrganizeImports . detectSorting ( sourceFile , preferences ) === SortKind . CaseInsensitive ;
1506
- }
1507
-
1508
- const comparer = OrganizeImports . getOrganizeImportsComparer ( preferences , ignoreCaseForSorting ) ;
1491
+ const { specifierComparer, isSorted } = OrganizeImports . getNamedImportSpecifierComparerWithDetection ( clause . parent , preferences , sourceFile ) ;
1509
1492
const newSpecifiers = stableSort (
1510
1493
namedImports . map ( namedImport =>
1511
1494
factory . createImportSpecifier (
@@ -1514,23 +1497,24 @@ function doAddExistingFix(
1514
1497
factory . createIdentifier ( namedImport . name ) ,
1515
1498
)
1516
1499
) ,
1517
- ( s1 , s2 ) => OrganizeImports . compareImportOrExportSpecifiers ( s1 , s2 , comparer ) ,
1500
+ specifierComparer ,
1518
1501
) ;
1519
1502
1520
1503
// The sorting preference computed earlier may or may not have validated that these particular
1521
1504
// import specifiers are sorted. If they aren't, `getImportSpecifierInsertionIndex` will return
1522
1505
// nonsense. So if there are existing specifiers, even if we know the sorting preference, we
1523
1506
// need to ensure that the existing specifiers are sorted according to the preference in order
1524
1507
// to do a sorted insertion.
1525
- const specifierSort = existingSpecifiers ?. length && OrganizeImports . detectImportSpecifierSorting ( existingSpecifiers , preferences ) ;
1526
- if ( specifierSort && ! ( ignoreCaseForSorting && specifierSort === SortKind . CaseSensitive ) ) {
1508
+
1509
+ // changed to check if existing specifiers are sorted
1510
+ if ( existingSpecifiers ?. length && isSorted !== false ) {
1511
+ // if we're promoting the clause from type-only, we need to transform the existing imports before attempting to insert the new named imports
1512
+ const transformedExistingSpecifiers = ( promoteFromTypeOnly && existingSpecifiers ) ? factory . updateNamedImports (
1513
+ clause . namedBindings as NamedImports ,
1514
+ sameMap ( existingSpecifiers , e => factory . updateImportSpecifier ( e , /*isTypeOnly*/ true , e . propertyName , e . name ) ) ,
1515
+ ) . elements : existingSpecifiers ;
1527
1516
for ( const spec of newSpecifiers ) {
1528
- // Organize imports puts type-only import specifiers last, so if we're
1529
- // adding a non-type-only specifier and converting all the other ones to
1530
- // type-only, there's no need to ask for the insertion index - it's 0.
1531
- const insertionIndex = promoteFromTypeOnly && ! spec . isTypeOnly
1532
- ? 0
1533
- : OrganizeImports . getImportSpecifierInsertionIndex ( existingSpecifiers , spec , comparer , preferences ) ;
1517
+ const insertionIndex = OrganizeImports . getImportSpecifierInsertionIndex ( transformedExistingSpecifiers , spec , specifierComparer ) ;
1534
1518
changes . insertImportSpecifierAtIndex ( sourceFile , spec , clause . namedBindings as NamedImports , insertionIndex ) ;
1535
1519
}
1536
1520
}
0 commit comments