@@ -89,7 +89,7 @@ export function organizeImports(
89
89
const shouldCombine = shouldSort ; // These are currently inseparable, but I draw a distinction for clarity and in case we add modes in the future.
90
90
const shouldRemove = mode === OrganizeImportsMode . RemoveUnused || mode === OrganizeImportsMode . All ;
91
91
// All of the old ImportDeclarations in the file, in syntactic order.
92
- const topLevelImportGroupDecls = groupImportsByNewlineContiguous ( sourceFile , sourceFile . statements . filter ( isImportDeclaration ) ) ;
92
+ const topLevelImportGroupDecls = groupByNewlineContiguous ( sourceFile , sourceFile . statements . filter ( isImportDeclaration ) ) ;
93
93
94
94
const comparer = getOrganizeImportsComparerWithDetection ( preferences , shouldSort ? ( ) => detectSortingWorker ( topLevelImportGroupDecls , preferences ) === SortKind . CaseInsensitive : undefined ) ;
95
95
@@ -105,14 +105,14 @@ export function organizeImports(
105
105
// Exports are always used
106
106
if ( mode !== OrganizeImportsMode . RemoveUnused ) {
107
107
// All of the old ExportDeclarations in the file, in syntactic order.
108
- const topLevelExportDecls = sourceFile . statements . filter ( isExportDeclaration ) ;
109
- organizeImportsWorker ( topLevelExportDecls , group => coalesceExportsWorker ( group , comparer ) ) ;
108
+ getTopLevelExportGroups ( sourceFile ) . forEach ( exportGroupDecl =>
109
+ organizeImportsWorker ( exportGroupDecl , group => coalesceExportsWorker ( group , comparer ) ) ) ;
110
110
}
111
111
112
112
for ( const ambientModule of sourceFile . statements . filter ( isAmbientModule ) ) {
113
113
if ( ! ambientModule . body ) continue ;
114
114
115
- const ambientModuleImportGroupDecls = groupImportsByNewlineContiguous ( sourceFile , ambientModule . body . statements . filter ( isImportDeclaration ) ) ;
115
+ const ambientModuleImportGroupDecls = groupByNewlineContiguous ( sourceFile , ambientModule . body . statements . filter ( isImportDeclaration ) ) ;
116
116
ambientModuleImportGroupDecls . forEach ( importGroupDecl => organizeImportsWorker ( importGroupDecl , processImportsOfSameModuleSpecifier ) ) ;
117
117
118
118
// Exports are always used
@@ -146,7 +146,7 @@ export function organizeImports(
146
146
? stableSort ( oldImportGroups , ( group1 , group2 ) => compareModuleSpecifiersWorker ( group1 [ 0 ] . moduleSpecifier , group2 [ 0 ] . moduleSpecifier , comparer ) )
147
147
: oldImportGroups ;
148
148
const newImportDecls = flatMap ( sortedImportGroups , importGroup =>
149
- getExternalModuleName ( importGroup [ 0 ] . moduleSpecifier )
149
+ getExternalModuleName ( importGroup [ 0 ] . moduleSpecifier ) || importGroup [ 0 ] . moduleSpecifier === undefined
150
150
? coalesce ( importGroup )
151
151
: importGroup ) ;
152
152
@@ -175,30 +175,30 @@ export function organizeImports(
175
175
}
176
176
}
177
177
178
- function groupImportsByNewlineContiguous ( sourceFile : SourceFile , importDecls : ImportDeclaration [ ] ) : ImportDeclaration [ ] [ ] {
178
+ function groupByNewlineContiguous < T extends ImportDeclaration | ExportDeclaration > ( sourceFile : SourceFile , decls : T [ ] ) : T [ ] [ ] {
179
179
const scanner = createScanner ( sourceFile . languageVersion , /*skipTrivia*/ false , sourceFile . languageVariant ) ;
180
- const groupImports : ImportDeclaration [ ] [ ] = [ ] ;
180
+ const group : T [ ] [ ] = [ ] ;
181
181
let groupIndex = 0 ;
182
- for ( const topLevelImportDecl of importDecls ) {
183
- if ( groupImports [ groupIndex ] && isNewGroup ( sourceFile , topLevelImportDecl , scanner ) ) {
182
+ for ( const decl of decls ) {
183
+ if ( group [ groupIndex ] && isNewGroup ( sourceFile , decl , scanner ) ) {
184
184
groupIndex ++ ;
185
185
}
186
186
187
- if ( ! groupImports [ groupIndex ] ) {
188
- groupImports [ groupIndex ] = [ ] ;
187
+ if ( ! group [ groupIndex ] ) {
188
+ group [ groupIndex ] = [ ] ;
189
189
}
190
190
191
- groupImports [ groupIndex ] . push ( topLevelImportDecl ) ;
191
+ group [ groupIndex ] . push ( decl ) ;
192
192
}
193
193
194
- return groupImports ;
194
+ return group ;
195
195
}
196
196
197
- // a new group is created if an import includes at least two new line
197
+ // a new group is created if an import/export includes at least two new line
198
198
// new line from multi-line comment doesn't count
199
- function isNewGroup ( sourceFile : SourceFile , topLevelImportDecl : ImportDeclaration , scanner : Scanner ) {
200
- const startPos = topLevelImportDecl . getFullStart ( ) ;
201
- const endPos = topLevelImportDecl . getStart ( ) ;
199
+ function isNewGroup ( sourceFile : SourceFile , decl : ImportDeclaration | ExportDeclaration , scanner : Scanner ) {
200
+ const startPos = decl . getFullStart ( ) ;
201
+ const endPos = decl . getStart ( ) ;
202
202
scanner . setText ( sourceFile . text , startPos , endPos - startPos ) ;
203
203
204
204
let numberOfNewLines = 0 ;
@@ -617,7 +617,7 @@ function getModuleSpecifierExpression(declaration: AnyImportOrRequireStatement):
617
617
/** @internal */
618
618
export function detectSorting ( sourceFile : SourceFile , preferences : UserPreferences ) : SortKind {
619
619
return detectSortingWorker (
620
- groupImportsByNewlineContiguous ( sourceFile , sourceFile . statements . filter ( isImportDeclaration ) ) ,
620
+ groupByNewlineContiguous ( sourceFile , sourceFile . statements . filter ( isImportDeclaration ) ) ,
621
621
preferences ) ;
622
622
}
623
623
@@ -824,3 +824,34 @@ function getOrganizeImportsComparerWithDetection(preferences: UserPreferences, d
824
824
const ignoreCase = typeof preferences . organizeImportsIgnoreCase === "boolean" ? preferences . organizeImportsIgnoreCase : detectIgnoreCase ?.( ) ?? false ;
825
825
return getOrganizeImportsComparer ( preferences , ignoreCase ) ;
826
826
}
827
+
828
+ function getTopLevelExportGroups ( sourceFile : SourceFile ) {
829
+ const topLevelExportGroups : ExportDeclaration [ ] [ ] = [ ] ;
830
+ const statements = sourceFile . statements ;
831
+ const len = length ( statements ) ;
832
+
833
+ let i = 0 ;
834
+ let groupIndex = 0 ;
835
+ while ( i < len ) {
836
+ if ( isExportDeclaration ( statements [ i ] ) ) {
837
+ if ( topLevelExportGroups [ groupIndex ] === undefined ) {
838
+ topLevelExportGroups [ groupIndex ] = [ ] ;
839
+ }
840
+ const exportDecl = statements [ i ] as ExportDeclaration ;
841
+ if ( exportDecl . moduleSpecifier ) {
842
+ topLevelExportGroups [ groupIndex ] . push ( exportDecl ) ;
843
+ i ++ ;
844
+ }
845
+ else {
846
+ while ( i < len && isExportDeclaration ( statements [ i ] ) ) {
847
+ topLevelExportGroups [ groupIndex ] . push ( statements [ i ++ ] as ExportDeclaration ) ;
848
+ }
849
+ groupIndex ++ ;
850
+ }
851
+ }
852
+ else {
853
+ i ++ ;
854
+ }
855
+ }
856
+ return flatMap ( topLevelExportGroups , exportGroupDecls => groupByNewlineContiguous ( sourceFile , exportGroupDecls ) ) ;
857
+ }
0 commit comments