@@ -135,7 +135,8 @@ namespace ts.codefix {
135
135
Named ,
136
136
Default ,
137
137
Namespace ,
138
- Equals
138
+ Equals ,
139
+ ConstEquals
139
140
}
140
141
141
142
/** Information about how a symbol is exported from a module. (We don't need to store the exported symbol, just its module.) */
@@ -163,7 +164,7 @@ namespace ts.codefix {
163
164
position : number ,
164
165
preferences : UserPreferences ,
165
166
) : { readonly moduleSpecifier : string , readonly codeAction : CodeAction } {
166
- const exportInfos = getAllReExportingModules ( exportedSymbol , moduleSymbol , symbolName , sourceFile , program . getCompilerOptions ( ) , program . getTypeChecker ( ) , program . getSourceFiles ( ) ) ;
167
+ const exportInfos = getAllReExportingModules ( sourceFile , exportedSymbol , moduleSymbol , symbolName , sourceFile , program . getCompilerOptions ( ) , program . getTypeChecker ( ) , program . getSourceFiles ( ) ) ;
167
168
Debug . assert ( exportInfos . some ( info => info . moduleSymbol === moduleSymbol ) ) ;
168
169
// We sort the best codefixes first, so taking `first` is best for completions.
169
170
const moduleSpecifier = first ( getNewImportInfos ( program , sourceFile , position , exportInfos , host , preferences ) ) . moduleSpecifier ;
@@ -175,15 +176,15 @@ namespace ts.codefix {
175
176
return { description, changes, commands } ;
176
177
}
177
178
178
- function getAllReExportingModules ( exportedSymbol : Symbol , exportingModuleSymbol : Symbol , symbolName : string , sourceFile : SourceFile , compilerOptions : CompilerOptions , checker : TypeChecker , allSourceFiles : ReadonlyArray < SourceFile > ) : ReadonlyArray < SymbolExportInfo > {
179
+ function getAllReExportingModules ( importingFile : SourceFile , exportedSymbol : Symbol , exportingModuleSymbol : Symbol , symbolName : string , sourceFile : SourceFile , compilerOptions : CompilerOptions , checker : TypeChecker , allSourceFiles : ReadonlyArray < SourceFile > ) : ReadonlyArray < SymbolExportInfo > {
179
180
const result : SymbolExportInfo [ ] = [ ] ;
180
181
forEachExternalModule ( checker , allSourceFiles , ( moduleSymbol , moduleFile ) => {
181
182
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
182
183
if ( moduleFile && moduleSymbol !== exportingModuleSymbol && startsWith ( sourceFile . fileName , getDirectoryPath ( moduleFile . fileName ) ) ) {
183
184
return ;
184
185
}
185
186
186
- const defaultInfo = getDefaultLikeExportInfo ( moduleSymbol , checker , compilerOptions ) ;
187
+ const defaultInfo = getDefaultLikeExportInfo ( importingFile , moduleSymbol , checker , compilerOptions ) ;
187
188
if ( defaultInfo && defaultInfo . name === symbolName && skipAlias ( defaultInfo . symbol , checker ) === exportedSymbol ) {
188
189
result . push ( { moduleSymbol, importKind : defaultInfo . kind , exportedSymbolIsTypeOnly : isTypeOnlySymbol ( defaultInfo . symbol , checker ) } ) ;
189
190
}
@@ -329,7 +330,7 @@ namespace ts.codefix {
329
330
if ( ! umdSymbol ) return undefined ;
330
331
const symbol = checker . getAliasedSymbol ( umdSymbol ) ;
331
332
const symbolName = umdSymbol . name ;
332
- const exportInfos : ReadonlyArray < SymbolExportInfo > = [ { moduleSymbol : symbol , importKind : getUmdImportKind ( program . getCompilerOptions ( ) ) , exportedSymbolIsTypeOnly : false } ] ;
333
+ const exportInfos : ReadonlyArray < SymbolExportInfo > = [ { moduleSymbol : symbol , importKind : getUmdImportKind ( sourceFile , program . getCompilerOptions ( ) ) , exportedSymbolIsTypeOnly : false } ] ;
333
334
const fixes = getFixForImport ( exportInfos , symbolName , isIdentifier ( token ) ? token . getStart ( sourceFile ) : undefined , program , sourceFile , host , preferences ) ;
334
335
return { fixes, symbolName } ;
335
336
}
@@ -345,7 +346,7 @@ namespace ts.codefix {
345
346
: undefined ;
346
347
}
347
348
348
- function getUmdImportKind ( compilerOptions : CompilerOptions ) : ImportKind {
349
+ function getUmdImportKind ( importingFile : SourceFile , compilerOptions : CompilerOptions ) : ImportKind {
349
350
// Import a synthetic `default` if enabled.
350
351
if ( getAllowSyntheticDefaultImports ( compilerOptions ) ) {
351
352
return ImportKind . Default ;
@@ -357,7 +358,10 @@ namespace ts.codefix {
357
358
case ModuleKind . AMD :
358
359
case ModuleKind . CommonJS :
359
360
case ModuleKind . UMD :
360
- return ImportKind . Equals ;
361
+ if ( isInJSFile ( importingFile ) ) {
362
+ return isExternalModule ( importingFile ) ? ImportKind . Namespace : ImportKind . ConstEquals ;
363
+ }
364
+ return ImportKind . Equals ;
361
365
case ModuleKind . System :
362
366
case ModuleKind . ES2015 :
363
367
case ModuleKind . ESNext :
@@ -403,7 +407,7 @@ namespace ts.codefix {
403
407
forEachExternalModuleToImportFrom ( checker , sourceFile , program . getSourceFiles ( ) , moduleSymbol => {
404
408
cancellationToken . throwIfCancellationRequested ( ) ;
405
409
406
- const defaultInfo = getDefaultLikeExportInfo ( moduleSymbol , checker , program . getCompilerOptions ( ) ) ;
410
+ const defaultInfo = getDefaultLikeExportInfo ( sourceFile , moduleSymbol , checker , program . getCompilerOptions ( ) ) ;
407
411
if ( defaultInfo && defaultInfo . name === symbolName && symbolHasMeaning ( defaultInfo . symbolForMeaning , currentTokenMeaning ) ) {
408
412
addSymbol ( moduleSymbol , defaultInfo . symbol , defaultInfo . kind ) ;
409
413
}
@@ -418,20 +422,41 @@ namespace ts.codefix {
418
422
}
419
423
420
424
function getDefaultLikeExportInfo (
421
- moduleSymbol : Symbol , checker : TypeChecker , compilerOptions : CompilerOptions ,
422
- ) : { readonly symbol : Symbol , readonly symbolForMeaning : Symbol , readonly name : string , readonly kind : ImportKind . Default | ImportKind . Equals } | undefined {
423
- const exported = getDefaultLikeExportWorker ( moduleSymbol , checker ) ;
425
+ importingFile : SourceFile , moduleSymbol : Symbol , checker : TypeChecker , compilerOptions : CompilerOptions ,
426
+ ) : { readonly symbol : Symbol , readonly symbolForMeaning : Symbol , readonly name : string , readonly kind : ImportKind } | undefined {
427
+ const exported = getDefaultLikeExportWorker ( importingFile , moduleSymbol , checker , compilerOptions ) ;
424
428
if ( ! exported ) return undefined ;
425
429
const { symbol, kind } = exported ;
426
430
const info = getDefaultExportInfoWorker ( symbol , moduleSymbol , checker , compilerOptions ) ;
427
431
return info && { symbol, kind, ...info } ;
428
432
}
429
433
430
- function getDefaultLikeExportWorker ( moduleSymbol : Symbol , checker : TypeChecker ) : { readonly symbol : Symbol , readonly kind : ImportKind . Default | ImportKind . Equals } | undefined {
434
+ function getDefaultLikeExportWorker ( importingFile : SourceFile , moduleSymbol : Symbol , checker : TypeChecker , compilerOptions : CompilerOptions ) : { readonly symbol : Symbol , readonly kind : ImportKind } | undefined {
431
435
const defaultExport = checker . tryGetMemberInModuleExports ( InternalSymbolName . Default , moduleSymbol ) ;
432
436
if ( defaultExport ) return { symbol : defaultExport , kind : ImportKind . Default } ;
433
437
const exportEquals = checker . resolveExternalModuleSymbol ( moduleSymbol ) ;
434
- return exportEquals === moduleSymbol ? undefined : { symbol : exportEquals , kind : ImportKind . Equals } ;
438
+ return exportEquals === moduleSymbol ? undefined : { symbol : exportEquals , kind : getExportEqualsImportKind ( importingFile , compilerOptions , checker ) } ;
439
+ }
440
+
441
+ function getExportEqualsImportKind ( importingFile : SourceFile , compilerOptions : CompilerOptions , checker : TypeChecker ) : ImportKind {
442
+ if ( getAllowSyntheticDefaultImports ( compilerOptions ) && getEmitModuleKind ( compilerOptions ) >= ModuleKind . ES2015 ) {
443
+ return ImportKind . Default ;
444
+ }
445
+ if ( isInJSFile ( importingFile ) ) {
446
+ return isExternalModule ( importingFile ) ? ImportKind . Default : ImportKind . ConstEquals ;
447
+ }
448
+ for ( const statement of importingFile . statements ) {
449
+ if ( isImportEqualsDeclaration ( statement ) ) {
450
+ return ImportKind . Equals ;
451
+ }
452
+ if ( isImportDeclaration ( statement ) && statement . importClause && statement . importClause . name ) {
453
+ const moduleSymbol = checker . getImmediateAliasedSymbol ( statement . importClause . symbol ) ;
454
+ if ( moduleSymbol && moduleSymbol . name !== InternalSymbolName . Default ) {
455
+ return ImportKind . Default ;
456
+ }
457
+ }
458
+ }
459
+ return ImportKind . Equals ;
435
460
}
436
461
437
462
function getDefaultExportInfoWorker ( defaultExport : Symbol , moduleSymbol : Symbol , checker : TypeChecker , compilerOptions : CompilerOptions ) : { readonly symbolForMeaning : Symbol , readonly name : string } | undefined {
@@ -543,7 +568,10 @@ namespace ts.codefix {
543
568
interface ImportsCollection {
544
569
readonly defaultImport : string | undefined ;
545
570
readonly namedImports : string [ ] ;
546
- readonly namespaceLikeImport : { readonly importKind : ImportKind . Equals | ImportKind . Namespace , readonly name : string } | undefined ;
571
+ readonly namespaceLikeImport : {
572
+ readonly importKind : ImportKind . Equals | ImportKind . Namespace | ImportKind . ConstEquals ;
573
+ readonly name : string ;
574
+ } | undefined ;
547
575
}
548
576
function addNewImports ( changes : textChanges . ChangeTracker , sourceFile : SourceFile , moduleSpecifier : string , quotePreference : QuotePreference , { defaultImport, namedImports, namespaceLikeImport } : ImportsCollection ) : void {
549
577
const quotedModuleSpecifier = makeStringLiteral ( moduleSpecifier , quotePreference ) ;
@@ -554,12 +582,25 @@ namespace ts.codefix {
554
582
namedImports . map ( n => createImportSpecifier ( /*propertyName*/ undefined , createIdentifier ( n ) ) ) , moduleSpecifier , quotePreference ) ) ;
555
583
}
556
584
if ( namespaceLikeImport ) {
557
- insertImport ( changes , sourceFile , namespaceLikeImport . importKind === ImportKind . Equals
558
- ? createImportEqualsDeclaration ( /*decorators*/ undefined , /*modifiers*/ undefined , createIdentifier ( namespaceLikeImport . name ) , createExternalModuleReference ( quotedModuleSpecifier ) )
559
- : createImportDeclaration ( /*decorators*/ undefined , /*modifiers*/ undefined , createImportClause ( /*name*/ undefined , createNamespaceImport ( createIdentifier ( namespaceLikeImport . name ) ) ) , quotedModuleSpecifier ) ) ;
585
+ insertImport (
586
+ changes ,
587
+ sourceFile ,
588
+ namespaceLikeImport . importKind === ImportKind . Equals ? createImportEqualsDeclaration ( /*decorators*/ undefined , /*modifiers*/ undefined , createIdentifier ( namespaceLikeImport . name ) , createExternalModuleReference ( quotedModuleSpecifier ) ) :
589
+ namespaceLikeImport . importKind === ImportKind . ConstEquals ? createConstEqualsRequireDeclaration ( namespaceLikeImport . name , quotedModuleSpecifier ) :
590
+ createImportDeclaration ( /*decorators*/ undefined , /*modifiers*/ undefined , createImportClause ( /*name*/ undefined , createNamespaceImport ( createIdentifier ( namespaceLikeImport . name ) ) ) , quotedModuleSpecifier ) ) ;
560
591
}
561
592
}
562
593
594
+ function createConstEqualsRequireDeclaration ( name : string , quotedModuleSpecifier : StringLiteral ) : VariableStatement {
595
+ return createVariableStatement ( /*modifiers*/ undefined , createVariableDeclarationList ( [
596
+ createVariableDeclaration (
597
+ createIdentifier ( name ) ,
598
+ /*type*/ undefined ,
599
+ createCall ( createIdentifier ( "require" ) , /*typeArguments*/ undefined , [ quotedModuleSpecifier ] )
600
+ )
601
+ ] , NodeFlags . Const ) ) ;
602
+ }
603
+
563
604
function symbolHasMeaning ( { declarations } : Symbol , meaning : SemanticMeaning ) : boolean {
564
605
return some ( declarations , decl => ! ! ( getMeaningFromDeclaration ( decl ) & meaning ) ) ;
565
606
}
0 commit comments