@@ -101,21 +101,24 @@ export function organizeImports(
101101
102102 const { comparersToTest, typeOrdersToTest } = getDetectionLists ( preferences ) ;
103103 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.
105105 comparer . moduleSpecifierComparer = getOrganizeImportsComparer ( preferences , preferences . organizeImportsIgnoreCase ) ;
106106 comparer . namedImportComparer = comparer . moduleSpecifierComparer ;
107107 }
108108 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
110110 ( { comparer : comparer . moduleSpecifierComparer } = detectModuleSpecifierCaseBySort ( topLevelImportGroupDecls , comparersToTest ) ) ;
111111 }
112112
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+ }
118120 }
121+
119122 topLevelImportGroupDecls . forEach ( importGroupDecl => organizeImportsWorker ( importGroupDecl , comparer ) ) ;
120123
121124 // Exports are always used
@@ -211,6 +214,17 @@ export function organizeImports(
211214 }
212215}
213216
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+
214228function groupByNewlineContiguous < T extends ImportDeclaration | ExportDeclaration > ( sourceFile : SourceFile , decls : T [ ] ) : T [ ] [ ] {
215229 const scanner = createScanner ( sourceFile . languageVersion , /*skipTrivia*/ false , sourceFile . languageVariant ) ;
216230 const group : T [ ] [ ] = [ ] ;
@@ -672,6 +686,10 @@ function compareModuleSpecifiersWorker(m1: Expression | undefined, m2: Expressio
672686 comparer ( name1 ! , name2 ! ) ;
673687}
674688
689+ function getModuleNamesFromDecls ( decls : readonly AnyImportOrRequireStatement [ ] ) : string [ ] {
690+ return decls . map ( s => getExternalModuleName ( getModuleSpecifierExpression ( s ) ) || "" ) ;
691+ }
692+
675693function getModuleSpecifierExpression ( declaration : AnyImportOrRequireStatement ) : Expression | undefined {
676694 switch ( declaration . kind ) {
677695 case SyntaxKind . ImportEqualsDeclaration :
@@ -813,15 +831,11 @@ function getTopLevelExportGroups(sourceFile: SourceFile) {
813831 return flatMap ( topLevelExportGroups , exportGroupDecls => groupByNewlineContiguous ( sourceFile , exportGroupDecls ) ) ;
814832}
815833
816- function getModuleNamesFromDecls ( decls : readonly AnyImportOrRequireStatement [ ] ) : string [ ] {
817- return decls . map ( s => getExternalModuleName ( getModuleSpecifierExpression ( s ) ) || "" ) ;
818- }
819-
820834/** @internal */
821835export function detectModuleSpecifierCaseBySort ( importDeclsByGroup : ( readonly AnyImportOrRequireStatement [ ] ) [ ] , comparersToTest : Comparer < string > [ ] ) {
822836 const moduleSpecifiersByGroup : string [ ] [ ] = [ ] ;
823837 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
825839 moduleSpecifiersByGroup . push ( getModuleNamesFromDecls ( importGroup ) ) ;
826840 } ) ;
827841 return detectCaseSensitivityBySort ( moduleSpecifiersByGroup , comparersToTest ) ;
@@ -832,27 +846,26 @@ export type TypeOrder = "first" | "last" | "inline";
832846
833847/** @internal */
834848export 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
836850 let bothNamedImports = false ;
837851 const importDeclsWithNamed = originalGroups . filter ( i => {
838852 const namedImports = tryCast ( i . importClause ?. namedBindings , isNamedImports ) ?. elements ;
839853 if ( ! namedImports ?. length ) return false ;
840854 if ( ! bothNamedImports && namedImports . some ( n => n . isTypeOnly ) && namedImports . some ( n => ! n . isTypeOnly ) ) {
841- // todo:improve check
842855 bothNamedImports = true ;
843856 }
844857 return true ;
845858 } ) ;
846859
847- // no need for more detection if no named imports
860+ // No need for more detection, if no named imports
848861 if ( importDeclsWithNamed . length === 0 ) return ;
849862
850- // formats the code into lists of named imports, grouped by declaration
863+ // Formats into lists of named imports, grouped by declaration
851864 const namedImportsByDecl = importDeclsWithNamed . map ( importDecl => {
852865 return tryCast ( importDecl . importClause ?. namedBindings , isNamedImports ) ?. elements ;
853866 } ) . filter ( elements => elements !== undefined ) as any as ImportSpecifier [ ] [ ] ;
854867
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
856869 if ( ! bothNamedImports || typesToTest . length === 0 ) {
857870 const sortState = detectCaseSensitivityBySort ( namedImportsByDecl . map ( i => i . map ( n => n . name . text ) ) , comparersToTest ) ;
858871 return { namedImportComparer : sortState . comparer , isSorted : sortState . isSorted } ;
@@ -886,20 +899,10 @@ export function detectNamedImportOrganizationBySort(originalGroups: readonly Imp
886899 return { namedImportComparer : bestComparer [ bestTypeOrder ] , typeOrder : bestTypeOrder , isSorted : bestDiff [ bestTypeOrder ] === 0 } ;
887900 }
888901
889- // default; hopefully never hit.....
902+ // Default behavior. It shouldn't be hit if typesToTest.length > 0
890903 return { namedImportComparer : bestComparer . last , typeOrder : "last" , isSorted : bestDiff . last === 0 } ;
891904}
892905
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-
903906function getSortedMeasure < T > ( arr : readonly T [ ] , comparer : Comparer < T > ) {
904907 let i = 0 ;
905908 for ( let j = 0 ; j < arr . length - 1 ; j ++ ) {
@@ -909,9 +912,10 @@ function getSortedMeasure<T>(arr: readonly T[], comparer: Comparer<T>) {
909912 }
910913 return i ;
911914}
915+
912916function 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
915919 let bestComparer ;
916920 let bestDiff = Infinity ;
917921
@@ -923,8 +927,6 @@ function detectCaseSensitivityBySort(originalGroups: string[][], comparersToTest
923927
924928 for ( const listToSort of originalGroups ) {
925929 if ( listToSort . length <= 1 ) continue ;
926-
927- // const sortedList = sort(listToSort, curComparer) as any as string[];
928930 const diff = getSortedMeasure ( listToSort , curComparer ) ;
929931 diffOfCurrentComparer += diff ;
930932 }
0 commit comments