@@ -101,21 +101,24 @@ export function organizeImports(
101
101
102
102
const { comparersToTest, typeOrdersToTest } = getDetectionLists ( preferences ) ;
103
103
if ( typeof preferences . organizeImportsIgnoreCase === "boolean" ) {
104
- // if case sensitivity is specified (true/false), then use the same setting for both.
104
+ // If case sensitivity is specified (true/false), then use the same setting for both.
105
105
comparer . moduleSpecifierComparer = getOrganizeImportsComparer ( preferences , preferences . organizeImportsIgnoreCase ) ;
106
106
comparer . namedImportComparer = comparer . moduleSpecifierComparer ;
107
107
}
108
108
else {
109
- // otherwise , we must test for both case-sensitivity and later, type order
109
+ // Otherwise , we must test for case-sensitivity. Named import case sensitivity will be tested with type order
110
110
( { comparer : comparer . moduleSpecifierComparer } = detectModuleSpecifierCaseBySort ( topLevelImportGroupDecls , comparersToTest ) ) ;
111
111
}
112
112
113
- const namedImportSort = detectNamedImportOrganizationBySort ( topLevelImportDecls , comparersToTest , typeOrdersToTest ) ;
114
- if ( namedImportSort ) {
115
- const { namedImportComparer, typeOrder } = namedImportSort ;
116
- comparer . namedImportComparer = comparer . namedImportComparer ?? namedImportComparer ;
117
- comparer . typeOrder = comparer . typeOrder ?? typeOrder ;
113
+ if ( ! comparer . typeOrder ) {
114
+ const namedImportSort = detectNamedImportOrganizationBySort ( topLevelImportDecls , comparersToTest , typeOrdersToTest ) ;
115
+ if ( namedImportSort ) {
116
+ const { namedImportComparer, typeOrder } = namedImportSort ;
117
+ comparer . namedImportComparer = comparer . namedImportComparer ?? namedImportComparer ;
118
+ comparer . typeOrder = comparer . typeOrder ?? typeOrder ;
119
+ }
118
120
}
121
+
119
122
topLevelImportGroupDecls . forEach ( importGroupDecl => organizeImportsWorker ( importGroupDecl , comparer ) ) ;
120
123
121
124
// Exports are always used
@@ -211,6 +214,17 @@ export function organizeImports(
211
214
}
212
215
}
213
216
217
+ /** @internal */
218
+ export function getDetectionLists ( preferences : UserPreferences ) : { comparersToTest : Comparer < string > [ ] ; typeOrdersToTest : TypeOrder [ ] ; } {
219
+ // Returns the possible detection outcomes, given the user's preferences. The earlier in the list, the higher the priority.
220
+ return {
221
+ comparersToTest : typeof preferences . organizeImportsIgnoreCase === "boolean"
222
+ ? [ getOrganizeImportsComparer ( preferences , preferences . organizeImportsIgnoreCase ) ]
223
+ : [ getOrganizeImportsComparer ( preferences , /*ignoreCase*/ true ) , getOrganizeImportsComparer ( preferences , /*ignoreCase*/ false ) ] ,
224
+ typeOrdersToTest : preferences . organizeImportsTypeOrder ? [ preferences . organizeImportsTypeOrder ] : [ "last" , "inline" , "first" ] ,
225
+ } ;
226
+ }
227
+
214
228
function groupByNewlineContiguous < T extends ImportDeclaration | ExportDeclaration > ( sourceFile : SourceFile , decls : T [ ] ) : T [ ] [ ] {
215
229
const scanner = createScanner ( sourceFile . languageVersion , /*skipTrivia*/ false , sourceFile . languageVariant ) ;
216
230
const group : T [ ] [ ] = [ ] ;
@@ -672,6 +686,10 @@ function compareModuleSpecifiersWorker(m1: Expression | undefined, m2: Expressio
672
686
comparer ( name1 ! , name2 ! ) ;
673
687
}
674
688
689
+ function getModuleNamesFromDecls ( decls : readonly AnyImportOrRequireStatement [ ] ) : string [ ] {
690
+ return decls . map ( s => getExternalModuleName ( getModuleSpecifierExpression ( s ) ) || "" ) ;
691
+ }
692
+
675
693
function getModuleSpecifierExpression ( declaration : AnyImportOrRequireStatement ) : Expression | undefined {
676
694
switch ( declaration . kind ) {
677
695
case SyntaxKind . ImportEqualsDeclaration :
@@ -813,15 +831,11 @@ function getTopLevelExportGroups(sourceFile: SourceFile) {
813
831
return flatMap ( topLevelExportGroups , exportGroupDecls => groupByNewlineContiguous ( sourceFile , exportGroupDecls ) ) ;
814
832
}
815
833
816
- function getModuleNamesFromDecls ( decls : readonly AnyImportOrRequireStatement [ ] ) : string [ ] {
817
- return decls . map ( s => getExternalModuleName ( getModuleSpecifierExpression ( s ) ) || "" ) ;
818
- }
819
-
820
834
/** @internal */
821
835
export function detectModuleSpecifierCaseBySort ( importDeclsByGroup : ( readonly AnyImportOrRequireStatement [ ] ) [ ] , comparersToTest : Comparer < string > [ ] ) {
822
836
const moduleSpecifiersByGroup : string [ ] [ ] = [ ] ;
823
837
importDeclsByGroup . forEach ( importGroup => {
824
- // turns importDeclsByGroup into string[][] of module specifiers by group to detect sorting on module specifiers
838
+ // Turns importDeclsByGroup into string[][] of module specifiers by group to detect sorting on module specifiers
825
839
moduleSpecifiersByGroup . push ( getModuleNamesFromDecls ( importGroup ) ) ;
826
840
} ) ;
827
841
return detectCaseSensitivityBySort ( moduleSpecifiersByGroup , comparersToTest ) ;
@@ -832,27 +846,26 @@ export type TypeOrder = "first" | "last" | "inline";
832
846
833
847
/** @internal */
834
848
export function detectNamedImportOrganizationBySort ( originalGroups : readonly ImportDeclaration [ ] , comparersToTest : Comparer < string > [ ] , typesToTest : TypeOrder [ ] ) : { namedImportComparer : Comparer < string > ; typeOrder ?: "first" | "last" | "inline" ; isSorted : boolean ; } | undefined {
835
- // filter for import declarations with named imports. Will be a flat array of import declarations without separations by group
849
+ // Filter for import declarations with named imports. Will be a flat array of import declarations without separations by group
836
850
let bothNamedImports = false ;
837
851
const importDeclsWithNamed = originalGroups . filter ( i => {
838
852
const namedImports = tryCast ( i . importClause ?. namedBindings , isNamedImports ) ?. elements ;
839
853
if ( ! namedImports ?. length ) return false ;
840
854
if ( ! bothNamedImports && namedImports . some ( n => n . isTypeOnly ) && namedImports . some ( n => ! n . isTypeOnly ) ) {
841
- // todo:improve check
842
855
bothNamedImports = true ;
843
856
}
844
857
return true ;
845
858
} ) ;
846
859
847
- // no need for more detection if no named imports
860
+ // No need for more detection, if no named imports
848
861
if ( importDeclsWithNamed . length === 0 ) return ;
849
862
850
- // formats the code into lists of named imports, grouped by declaration
863
+ // Formats into lists of named imports, grouped by declaration
851
864
const namedImportsByDecl = importDeclsWithNamed . map ( importDecl => {
852
865
return tryCast ( importDecl . importClause ?. namedBindings , isNamedImports ) ?. elements ;
853
866
} ) . filter ( elements => elements !== undefined ) as any as ImportSpecifier [ ] [ ] ;
854
867
855
- // if we don't have any import statements with both named regular and type imports, we do not need to detect a type ordering
868
+ // If we don't have any import statements with both named regular and type imports, we do not need to detect a type ordering
856
869
if ( ! bothNamedImports || typesToTest . length === 0 ) {
857
870
const sortState = detectCaseSensitivityBySort ( namedImportsByDecl . map ( i => i . map ( n => n . name . text ) ) , comparersToTest ) ;
858
871
return { namedImportComparer : sortState . comparer , isSorted : sortState . isSorted } ;
@@ -886,20 +899,10 @@ export function detectNamedImportOrganizationBySort(originalGroups: readonly Imp
886
899
return { namedImportComparer : bestComparer [ bestTypeOrder ] , typeOrder : bestTypeOrder , isSorted : bestDiff [ bestTypeOrder ] === 0 } ;
887
900
}
888
901
889
- // default; hopefully never hit.....
902
+ // Default behavior. It shouldn't be hit if typesToTest.length > 0
890
903
return { namedImportComparer : bestComparer . last , typeOrder : "last" , isSorted : bestDiff . last === 0 } ;
891
904
}
892
905
893
- /** @internal */
894
- export function getDetectionLists ( preferences : UserPreferences ) : { comparersToTest : Comparer < string > [ ] ; typeOrdersToTest : TypeOrder [ ] ; } {
895
- return {
896
- comparersToTest : typeof preferences . organizeImportsIgnoreCase === "boolean"
897
- ? [ getOrganizeImportsComparer ( preferences , preferences . organizeImportsIgnoreCase ) ]
898
- : [ getOrganizeImportsComparer ( preferences , /*ignoreCase*/ true ) , getOrganizeImportsComparer ( preferences , /*ignoreCase*/ false ) ] ,
899
- typeOrdersToTest : preferences . organizeImportsTypeOrder ? [ preferences . organizeImportsTypeOrder ] : [ "last" , "inline" , "first" ] ,
900
- } ;
901
- }
902
-
903
906
function getSortedMeasure < T > ( arr : readonly T [ ] , comparer : Comparer < T > ) {
904
907
let i = 0 ;
905
908
for ( let j = 0 ; j < arr . length - 1 ; j ++ ) {
@@ -909,9 +912,10 @@ function getSortedMeasure<T>(arr: readonly T[], comparer: Comparer<T>) {
909
912
}
910
913
return i ;
911
914
}
915
+
912
916
function detectCaseSensitivityBySort ( originalGroups : string [ ] [ ] , comparersToTest : Comparer < string > [ ] ) : { comparer : Comparer < string > ; isSorted : boolean ; } {
913
- // each entry in originalGroups will be sorted and compared against the original entry.
914
- // the total diff of each comparison is the sum of the diffs of all groups
917
+ // Each entry in originalGroups will be sorted and compared against the original entry.
918
+ // The total diff of each comparison is the sum of the diffs over all groups
915
919
let bestComparer ;
916
920
let bestDiff = Infinity ;
917
921
@@ -923,8 +927,6 @@ function detectCaseSensitivityBySort(originalGroups: string[][], comparersToTest
923
927
924
928
for ( const listToSort of originalGroups ) {
925
929
if ( listToSort . length <= 1 ) continue ;
926
-
927
- // const sortedList = sort(listToSort, curComparer) as any as string[];
928
930
const diff = getSortedMeasure ( listToSort , curComparer ) ;
929
931
diffOfCurrentComparer += diff ;
930
932
}
0 commit comments