@@ -179,6 +179,9 @@ export class ImportManager {
179179
180180 // Extract re-export statements (export { X } from './m' or export * as ns from './m')
181181 // These should be preserved and placed AFTER imports
182+ //
183+ // KNOWN LIMITATION: Re-exports are preserved in original file order, not sorted/grouped.
184+ // Sorting re-exports could be added in a future version if there's demand.
182185 const exportDeclarations = this . sourceFile . getExportDeclarations ( ) ;
183186 for ( const exportDecl of exportDeclarations ) {
184187 // Only capture re-exports (those with moduleSpecifier)
@@ -550,7 +553,12 @@ export class ImportManager {
550553 for ( const imp of keep ) {
551554 // In modern mode, include isTypeOnly in the grouping key
552555 // This prevents merging type-only imports with value imports
553- const typePrefix = ( ! isLegacy && imp instanceof NamedImport && imp . isTypeOnly ) ? 'type:' : '' ;
556+ // Check both NamedImport and NamespaceImport for isTypeOnly flag
557+ const isTypeOnlyImport = ! isLegacy && (
558+ ( imp instanceof NamedImport && imp . isTypeOnly ) ||
559+ ( imp instanceof NamespaceImport && imp . isTypeOnly )
560+ ) ;
561+ const typePrefix = isTypeOnlyImport ? 'type:' : '' ;
554562 const groupKey = typePrefix + imp . libraryName ;
555563
556564 if ( ! byLibrary . has ( groupKey ) ) {
@@ -726,25 +734,35 @@ export class ImportManager {
726734 // Get the position info including blank lines before imports
727735 const { blankLinesBefore, hasHeader, hasLeadingBlanks, headerStartLine } = this . getImportInsertPosition ( ) ;
728736
729- // Delete leading blank lines before header (if any) as a separate edit
730- if ( hasLeadingBlanks && headerStartLine > 0 ) {
731- const leadingBlanksRange = new Range (
732- new Position ( 0 , 0 ) ,
733- new Position ( headerStartLine , 0 ) ,
734- ) ;
735- edits . push ( TextEdit . delete ( leadingBlanksRange ) ) ;
736- }
737-
738737 // Calculate the full range of imports to replace (excluding any header)
739738 const firstImport = allImports [ 0 ] ;
740739 const lastImport = allImports [ allImports . length - 1 ] ;
741740
742741 let importSectionStartLine = firstImport . getStartLineNumber ( ) - 1 ; // Convert to 0-indexed
743742 let importSectionEndLine = lastImport . getEndLineNumber ( ) - 1 ;
744743
744+ // Delete leading blank lines before header or imports (if any) as a separate edit
745+ // When hasLeadingBlanks is true:
746+ // - If headerStartLine > 0: There's a header, delete blanks from line 0 to headerStartLine
747+ // - If headerStartLine === -1: No header, delete blanks from line 0 to importSectionStartLine
748+ if ( hasLeadingBlanks ) {
749+ const deleteToLine = headerStartLine > 0 ? headerStartLine : importSectionStartLine ;
750+ if ( deleteToLine > 0 ) {
751+ const leadingBlanksRange = new Range (
752+ new Position ( 0 , 0 ) ,
753+ new Position ( deleteToLine , 0 ) ,
754+ ) ;
755+ edits . push ( TextEdit . delete ( leadingBlanksRange ) ) ;
756+ }
757+ }
758+
745759 // Extract comments between imports (old TypeScript Hero moves them after imports)
746760 // Only extract standalone comment lines that are BETWEEN import declarations,
747761 // not lines that are WITHIN a multi-line import declaration
762+ //
763+ // KNOWN LIMITATION: Comments INSIDE multiline import braces are not preserved.
764+ // Example: `import { Foo, /* comment */ Bar } from 'lib'` - the comment is lost.
765+ // This is complex to fix and is an edge case. Standalone comments between imports ARE preserved.
748766 const commentsBetweenImports : string [ ] = [ ] ;
749767 for ( let i = importSectionStartLine ; i <= importSectionEndLine ; i ++ ) {
750768 const lineNumber = i + 1 ; // Convert to 1-indexed for comparison with ts-morph
@@ -773,8 +791,11 @@ export class ImportManager {
773791 }
774792 }
775793
776- // Include blank lines before first import (but not header)
777- if ( blankLinesBefore > 0 ) {
794+ // Include blank lines before first import (but not header) in the replace range.
795+ // IMPORTANT: Only do this if we did NOT create a separate delete edit for leading blanks!
796+ // When hasLeadingBlanks is true, we already deleted lines 0 to importSectionStartLine,
797+ // so we must NOT extend importSectionStartLine backwards (would create overlapping ranges).
798+ if ( blankLinesBefore > 0 && ! hasLeadingBlanks ) {
778799 importSectionStartLine = Math . max ( 0 , importSectionStartLine - blankLinesBefore ) ;
779800 }
780801
0 commit comments