@@ -96,18 +96,29 @@ export function organizeImports(
96
96
// All of the old ImportDeclarations in the file, in syntactic order.
97
97
const topLevelImportGroupDecls = groupByNewlineContiguous ( sourceFile , sourceFile . statements . filter ( isImportDeclaration ) ) ;
98
98
99
- const DefaultComparer = getOrganizeImportsComparer ( preferences , /*ignoreCase*/ true ) ;
99
+ const DefaultComparer = getOrganizeImportsComparer ( preferences , /*ignoreCase*/ typeof preferences . organizeImportsIgnoreCase === "boolean" ? preferences . organizeImportsIgnoreCase : true ) ;
100
100
101
- let detectedModuleCaseComparer = DefaultComparer ;
102
- let detectedNamedImportCaseComparer = ( s1 , s2 ) => compareImportOrExportSpecifiers ( s1 , s2 , DefaultComparer , { organizeImportsTypeOrder : "last" } ) ;
103
- let detectedTypeOrder : typeof preferences . organizeImportsTypeOrder = "last" ;
101
+ // if case sensitivity is specified (true/false), then use the same setting for both.
102
+ let detectedModuleCaseComparer : Comparer < string > | undefined = typeof preferences . organizeImportsIgnoreCase === "boolean" ? DefaultComparer : undefined ;
103
+ let detectedNamedImportCaseComparer : Comparer < string > | undefined = detectedModuleCaseComparer ;
104
+
105
+ let detectedTypeOrder : typeof preferences . organizeImportsTypeOrder = preferences . organizeImportsTypeOrder ;
106
+
107
+ if ( ! detectedModuleCaseComparer || ! detectedNamedImportCaseComparer || ! detectedTypeOrder ) {
108
+ const { moduleSpecifierComparer, namedImportComparer, typeOrder } = getDetectionByDiff ( topLevelImportGroupDecls , preferences )
109
+
110
+ detectedModuleCaseComparer = detectedModuleCaseComparer ?? moduleSpecifierComparer ?? DefaultComparer ;
111
+ detectedNamedImportCaseComparer = detectedNamedImportCaseComparer ?? namedImportComparer ?? DefaultComparer ;
112
+ detectedTypeOrder = detectedTypeOrder ?? typeOrder ;
113
+ // TODO return unset comparer
114
+ }
104
115
105
116
topLevelImportGroupDecls . forEach ( importGroupDecl => organizeImportsWorker ( importGroupDecl ) ) ;
106
117
107
118
// Exports are always used
108
119
if ( mode !== OrganizeImportsMode . RemoveUnused ) {
109
120
// All of the old ExportDeclarations in the file, in syntactic order.
110
- getTopLevelExportGroups ( sourceFile ) . forEach ( exportGroupDecl => organizeExportsWorker ( exportGroupDecl ) ) ;
121
+ getTopLevelExportGroups ( sourceFile ) . forEach ( exportGroupDecl => organizeExportsWorker ( exportGroupDecl , detectedNamedImportCaseComparer ) ) ;
111
122
}
112
123
113
124
for ( const ambientModule of sourceFile . statements . filter ( isAmbientModule ) ) {
@@ -119,7 +130,7 @@ export function organizeImports(
119
130
// Exports are always used
120
131
if ( mode !== OrganizeImportsMode . RemoveUnused ) {
121
132
const ambientModuleExportDecls = ambientModule . body . statements . filter ( isExportDeclaration ) ;
122
- organizeExportsWorker ( ambientModuleExportDecls ) ;
133
+ organizeExportsWorker ( ambientModuleExportDecls , detectedNamedImportCaseComparer ) ;
123
134
}
124
135
}
125
136
@@ -144,7 +155,7 @@ export function organizeImports(
144
155
? group ( oldImportDecls , importDecl => getExternalModuleName ( importDecl . moduleSpecifier ) ! )
145
156
: [ oldImportDecls ] ;
146
157
const sortedImportGroups = shouldSort
147
- ? stableSort ( oldImportGroups , ( group1 , group2 ) => compareModuleSpecifiersWorker ( group1 [ 0 ] . moduleSpecifier , group2 [ 0 ] . moduleSpecifier , detectedModuleCaseComparer ) )
158
+ ? stableSort ( oldImportGroups , ( group1 , group2 ) => compareModuleSpecifiersWorker ( group1 [ 0 ] . moduleSpecifier , group2 [ 0 ] . moduleSpecifier , detectedModuleCaseComparer ?? DefaultComparer ) )
148
159
: oldImportGroups ;
149
160
const newImportDecls = flatMap ( sortedImportGroups , importGroup =>
150
161
getExternalModuleName ( importGroup [ 0 ] . moduleSpecifier ) || importGroup [ 0 ] . moduleSpecifier === undefined
@@ -175,30 +186,22 @@ export function organizeImports(
175
186
}
176
187
}
177
188
178
- function organizeImportsWorker ( oldImportDecls : readonly ImportDeclaration [ ] , comparer ?: Comparer < string > ) {
179
- if ( ! comparer ) {
180
- const { moduleSpecifierComparer, namedImportComparer, typeOrder } = getDetectionByDiff ( topLevelImportGroupDecls , preferences )
181
-
182
- detectedModuleCaseComparer = moduleSpecifierComparer ?? detectedModuleCaseComparer ;
183
- detectedNamedImportCaseComparer = namedImportComparer ?? detectedNamedImportCaseComparer ;
184
- detectedTypeOrder = typeOrder ?? detectedTypeOrder ;
185
- // TODO return unset comparer
186
- }
187
-
189
+ function organizeImportsWorker ( oldImportDecls : readonly ImportDeclaration [ ] ) {
190
+ const specifierComparer = getOrganizeImportsSpecifierComparer ( { organizeImportsTypeOrder : detectedTypeOrder ?? preferences . organizeImportsTypeOrder } , detectedNamedImportCaseComparer ) ;
188
191
const processImportsOfSameModuleSpecifier = ( importGroup : readonly ImportDeclaration [ ] ) => {
189
192
if ( shouldRemove ) importGroup = removeUnusedImports ( importGroup , sourceFile , program ) ;
190
- if ( shouldCombine ) importGroup = coalesceImportsWorker ( importGroup , detectedNamedImportCaseComparer , sourceFile , { organizeImportsTypeOrder : detectedTypeOrder } ) ;
191
- if ( shouldSort ) importGroup = stableSort ( importGroup , ( s1 , s2 ) => compareImportsOrRequireStatements ( s1 , s2 , detectedModuleCaseComparer ) ) ;
193
+ if ( shouldCombine ) importGroup = coalesceImportsWorker ( importGroup , detectedModuleCaseComparer ?? DefaultComparer , specifierComparer , sourceFile ) ;
194
+ if ( shouldSort ) importGroup = stableSort ( importGroup , ( s1 , s2 ) => compareImportsOrRequireStatements ( s1 , s2 , detectedModuleCaseComparer ?? DefaultComparer ) ) ;
192
195
return importGroup ;
193
196
} ;
194
197
195
198
organizeDeclsWorker ( oldImportDecls , processImportsOfSameModuleSpecifier ) ;
196
199
// return { moduleSpecifierComparer, namedImportComparer, typeOrder };
197
200
}
198
201
199
- function organizeExportsWorker ( oldExportDecls : readonly ExportDeclaration [ ] , comparer ?: Comparer < string > ) {
200
- const useComparer = comparer ?? DefaultComparer ;
201
- organizeDeclsWorker ( oldExportDecls , group => coalesceExportsWorker ( group , useComparer , { organizeImportsTypeOrder : detectedTypeOrder ?? preferences . organizeImportsTypeOrder } ) )
202
+ function organizeExportsWorker ( oldExportDecls : readonly ExportDeclaration [ ] , specifierCaseComparer ?: Comparer < string > ) {
203
+ const useComparer = getOrganizeImportsSpecifierComparer ( preferences , specifierCaseComparer ) ;
204
+ organizeDeclsWorker ( oldExportDecls , group => coalesceExportsWorker ( group , useComparer ) )
202
205
}
203
206
}
204
207
@@ -341,10 +344,11 @@ function getExternalModuleName(specifier: Expression | undefined) {
341
344
*/
342
345
export function coalesceImports ( importGroup : readonly ImportDeclaration [ ] , ignoreCase : boolean , sourceFile ?: SourceFile , preferences ?: UserPreferences ) : readonly ImportDeclaration [ ] {
343
346
const comparer = getOrganizeImportsOrdinalStringComparer ( ignoreCase ) ;
344
- return coalesceImportsWorker ( importGroup , comparer , sourceFile , preferences ) ;
347
+ const specifierComparer = getOrganizeImportsSpecifierComparer ( { organizeImportsTypeOrder : preferences ?. organizeImportsTypeOrder } , comparer ) ;
348
+ return coalesceImportsWorker ( importGroup , comparer , specifierComparer , sourceFile ) ;
345
349
}
346
350
347
- function coalesceImportsWorker ( importGroup : readonly ImportDeclaration [ ] , comparer : Comparer < string > , sourceFile ?: SourceFile , preferences ?: UserPreferences ) : readonly ImportDeclaration [ ] {
351
+ function coalesceImportsWorker ( importGroup : readonly ImportDeclaration [ ] , comparer : Comparer < string > , specifierComparer : Comparer < ImportSpecifier > , sourceFile ?: SourceFile ) : readonly ImportDeclaration [ ] {
348
352
if ( importGroup . length === 0 ) {
349
353
return importGroup ;
350
354
}
@@ -417,7 +421,7 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar
417
421
newImportSpecifiers . push ( ...getNewImportSpecifiers ( namedImports ) ) ;
418
422
419
423
const sortedImportSpecifiers = factory . createNodeArray (
420
- sortSpecifiers ( newImportSpecifiers , comparer , preferences ) ,
424
+ sortSpecifiers ( newImportSpecifiers , specifierComparer ) ,
421
425
firstNamedImport ?. importClause . namedBindings . elements . hasTrailingComma ,
422
426
) ;
423
427
@@ -536,11 +540,12 @@ function getCategorizedImports(importGroup: readonly ImportDeclaration[]) {
536
540
* @internal
537
541
*/
538
542
export function coalesceExports ( exportGroup : readonly ExportDeclaration [ ] , ignoreCase : boolean , preferences ?: UserPreferences ) {
539
- const comparer = getOrganizeImportsOrdinalStringComparer ( ignoreCase ) ;
540
- return coalesceExportsWorker ( exportGroup , comparer , preferences ) ;
543
+ const comparer = ( s1 : ExportSpecifier , s2 : ExportSpecifier ) =>
544
+ compareImportOrExportSpecifiers ( s1 , s2 , getOrganizeImportsOrdinalStringComparer ( ignoreCase ) , { organizeImportsTypeOrder : preferences ?. organizeImportsTypeOrder ?? "last" } ) ;
545
+ return coalesceExportsWorker ( exportGroup , comparer ) ;
541
546
}
542
547
543
- function coalesceExportsWorker ( exportGroup : readonly ExportDeclaration [ ] , comparer : Comparer < string > , preferences ?: UserPreferences ) {
548
+ function coalesceExportsWorker ( exportGroup : readonly ExportDeclaration [ ] , specifierComparer : Comparer < ExportSpecifier > ) {
544
549
if ( exportGroup . length === 0 ) {
545
550
return exportGroup ;
546
551
}
@@ -559,7 +564,7 @@ function coalesceExportsWorker(exportGroup: readonly ExportDeclaration[], compar
559
564
const newExportSpecifiers : ExportSpecifier [ ] = [ ] ;
560
565
newExportSpecifiers . push ( ...flatMap ( exportGroup , i => i . exportClause && isNamedExports ( i . exportClause ) ? i . exportClause . elements : emptyArray ) ) ;
561
566
562
- const sortedExportSpecifiers = sortSpecifiers ( newExportSpecifiers , comparer , preferences ) ;
567
+ const sortedExportSpecifiers = sortSpecifiers ( newExportSpecifiers , specifierComparer ) ;
563
568
564
569
const exportDecl = exportGroup [ 0 ] ;
565
570
coalescedExports . push (
@@ -626,8 +631,8 @@ function updateImportDeclarationAndClause(
626
631
) ;
627
632
}
628
633
629
- function sortSpecifiers < T extends ImportOrExportSpecifier > ( specifiers : readonly T [ ] , comparer : Comparer < string > , preferences ?: UserPreferences ) : readonly T [ ] {
630
- return stableSort ( specifiers , ( s1 , s2 ) => compareImportOrExportSpecifiers ( s1 , s2 , comparer , preferences ) ) ;
634
+ function sortSpecifiers < T extends ImportOrExportSpecifier > ( specifiers : readonly T [ ] , specifierComparer : Comparer < T > ) : readonly T [ ] {
635
+ return stableSort ( specifiers , specifierComparer ) ;
631
636
}
632
637
633
638
/** @internal */
@@ -642,6 +647,11 @@ export function compareImportOrExportSpecifiers<T extends ImportOrExportSpecifie
642
647
}
643
648
}
644
649
650
+ function getOrganizeImportsSpecifierComparer < T extends ImportOrExportSpecifier > ( preferences : UserPreferences , comparer ?: Comparer < string > ) : Comparer < T > {
651
+ const stringComparer = comparer ?? getOrganizeImportsOrdinalStringComparer ( ! ! preferences . organizeImportsIgnoreCase ) ;
652
+ return ( s1 , s2 ) => compareImportOrExportSpecifiers ( s1 , s2 , stringComparer , preferences ) ;
653
+ }
654
+
645
655
/**
646
656
* Exported for testing
647
657
*
@@ -963,21 +973,24 @@ export function getDetectionByDiff(importDeclsByGroup: ImportDeclaration[][], pr
963
973
moduleSpecifierComparer : Comparer < string > ;
964
974
namedImportComparer ?: Comparer < string > ;
965
975
typeOrder ?: "first" | "last" | "inline" ;
966
- } = { moduleSpecifierComparer : getOrganizeImportsComparer ( preferences , typeof preferences . organizeImportsIgnoreCase === "boolean" ? preferences . organizeImportsIgnoreCase : true ) } ;
976
+ } = {
977
+ moduleSpecifierComparer : getOrganizeImportsComparer ( preferences , typeof preferences . organizeImportsIgnoreCase === "boolean" ? preferences . organizeImportsIgnoreCase : true ) ,
978
+ typeOrder : preferences . organizeImportsTypeOrder ,
979
+ } ;
967
980
968
- let comparers : Comparer < string > [ ] ;
981
+ let comparersToTest : Comparer < string > [ ] ;
969
982
if ( typeof preferences . organizeImportsIgnoreCase === "boolean" ) {
970
983
// both moduleSpecifier and namedImport comparer to the correct case-sensitivity.
971
984
// does not yet exit because we still need to detect for type order
972
985
comparer . moduleSpecifierComparer = getOrganizeImportsComparer ( preferences , preferences . organizeImportsIgnoreCase ) ;
973
986
comparer . namedImportComparer = comparer . moduleSpecifierComparer ;
974
- comparers = [ comparer . moduleSpecifierComparer ] ;
987
+ comparersToTest = [ comparer . moduleSpecifierComparer ] ;
975
988
}
976
989
else {
977
990
// otherwise, we must test for both case-sensitivity and later, type order
978
991
const CASE_INSENSITIVE_COMPARER = getOrganizeImportsComparer ( preferences , /*ignoreCase*/ true ) ;
979
992
const CASE_SENSITIVE_COMPARER = getOrganizeImportsComparer ( preferences , /*ignoreCase*/ false ) ;
980
- comparers = [ CASE_INSENSITIVE_COMPARER , CASE_SENSITIVE_COMPARER ] ;
993
+ comparersToTest = [ CASE_INSENSITIVE_COMPARER , CASE_SENSITIVE_COMPARER ] ;
981
994
982
995
getModuleSpecifierNames ( importDeclsByGroup , comparer , detectCaseSensitivityBySort ) ;
983
996
}
@@ -1018,7 +1031,7 @@ export function getDetectionByDiff(importDeclsByGroup: ImportDeclaration[][], pr
1018
1031
1019
1032
const { namedImportComparer, typeOrder } = detectNamedImportOrganizationBySort ( namedImportsByDecl ) ;
1020
1033
comparer . namedImportComparer = namedImportComparer ;
1021
- comparer . typeOrder = typeOrder ;
1034
+ comparer . typeOrder = comparer . typeOrder ?? typeOrder ;
1022
1035
1023
1036
return comparer ;
1024
1037
@@ -1037,7 +1050,7 @@ export function getDetectionByDiff(importDeclsByGroup: ImportDeclaration[][], pr
1037
1050
let bestComparer ;
1038
1051
let bestDiff = Infinity ;
1039
1052
1040
- for ( const curComparer of comparers ) {
1053
+ for ( const curComparer of comparersToTest ) {
1041
1054
let diffOfCurrentComparer = 0 ;
1042
1055
1043
1056
for ( const listToSort of originalGroups ) {
@@ -1053,7 +1066,7 @@ export function getDetectionByDiff(importDeclsByGroup: ImportDeclaration[][], pr
1053
1066
bestComparer = curComparer ;
1054
1067
}
1055
1068
}
1056
- return bestComparer ?? comparers [ 0 ] ;
1069
+ return bestComparer ?? comparersToTest [ 0 ] ;
1057
1070
}
1058
1071
1059
1072
// interface NamedImportByDecl {
@@ -1080,9 +1093,9 @@ export function getDetectionByDiff(importDeclsByGroup: ImportDeclaration[][], pr
1080
1093
type TypeOrder = "first" | "last" | "inline" ;
1081
1094
1082
1095
const bestDiff = { first : Infinity , last : Infinity , inline : Infinity } ;
1083
- const bestComparer = { first : comparers [ 0 ] , last : comparers [ 0 ] , inline : comparers [ 0 ] } ;
1096
+ const bestComparer = { first : comparersToTest [ 0 ] , last : comparersToTest [ 0 ] , inline : comparersToTest [ 0 ] } ;
1084
1097
1085
- for ( const curComparer of comparers ) {
1098
+ for ( const curComparer of comparersToTest ) {
1086
1099
const currDiff = { first : 0 , last : 0 , inline : 0 } ;
1087
1100
1088
1101
for ( const importDecl of originalGroups ) {
0 commit comments