@@ -40,6 +40,7 @@ import {
40
40
Expression ,
41
41
ExpressionStatement ,
42
42
externalHelpersModuleNameText ,
43
+ filter ,
43
44
first ,
44
45
firstOrUndefined ,
45
46
ForInitializer ,
@@ -131,7 +132,6 @@ import {
131
132
MultiplicativeOperator ,
132
133
MultiplicativeOperatorOrHigher ,
133
134
Mutable ,
134
- NamedImportBindings ,
135
135
Node ,
136
136
NodeArray ,
137
137
NodeFactory ,
@@ -173,6 +173,7 @@ import {
173
173
Token ,
174
174
TransformFlags ,
175
175
TypeNode ,
176
+ UnscopedEmitHelper ,
176
177
WrappedExpression ,
177
178
} from "../_namespaces/ts.js" ;
178
179
@@ -688,26 +689,29 @@ export function hasRecordedExternalHelpers(sourceFile: SourceFile) {
688
689
/** @internal */
689
690
export function createExternalHelpersImportDeclarationIfNeeded ( nodeFactory : NodeFactory , helperFactory : EmitHelperFactory , sourceFile : SourceFile , compilerOptions : CompilerOptions , hasExportStarsToExportValues ?: boolean , hasImportStar ?: boolean , hasImportDefault ?: boolean ) {
690
691
if ( compilerOptions . importHelpers && isEffectiveExternalModule ( sourceFile , compilerOptions ) ) {
691
- let namedBindings : NamedImportBindings | undefined ;
692
692
const moduleKind = getEmitModuleKind ( compilerOptions ) ;
693
- if ( ( moduleKind >= ModuleKind . ES2015 && moduleKind <= ModuleKind . ESNext ) || getImpliedNodeFormatForEmitWorker ( sourceFile , compilerOptions ) === ModuleKind . ESNext ) {
694
- // use named imports
695
- const helpers = getEmitHelpers ( sourceFile ) ;
693
+ const impliedModuleKind = getImpliedNodeFormatForEmitWorker ( sourceFile , compilerOptions ) ;
694
+ const helpers = getImportedHelpers ( sourceFile ) ;
695
+ if (
696
+ ( moduleKind >= ModuleKind . ES2015 && moduleKind <= ModuleKind . ESNext ) ||
697
+ impliedModuleKind === ModuleKind . ESNext ||
698
+ impliedModuleKind === undefined && moduleKind === ModuleKind . Preserve
699
+ ) {
700
+ // When we emit as an ES module, generate an `import` declaration that uses named imports for helpers.
701
+ // If we cannot determine the implied module kind under `module: preserve` we assume ESM.
696
702
if ( helpers ) {
697
703
const helperNames : string [ ] = [ ] ;
698
704
for ( const helper of helpers ) {
699
- if ( ! helper . scoped ) {
700
- const importName = helper . importName ;
701
- if ( importName ) {
702
- pushIfUnique ( helperNames , importName ) ;
703
- }
705
+ const importName = helper . importName ;
706
+ if ( importName ) {
707
+ pushIfUnique ( helperNames , importName ) ;
704
708
}
705
709
}
706
710
if ( some ( helperNames ) ) {
707
711
helperNames . sort ( compareStringsCaseSensitive ) ;
708
712
// Alias the imports if the names are used somewhere in the file.
709
713
// NOTE: We don't need to care about global import collisions as this is a module.
710
- namedBindings = nodeFactory . createNamedImports (
714
+ const namedBindings = nodeFactory . createNamedImports (
711
715
map ( helperNames , name =>
712
716
isFileLevelUniqueName ( sourceFile , name )
713
717
? nodeFactory . createImportSpecifier ( /*isTypeOnly*/ false , /*propertyName*/ undefined , nodeFactory . createIdentifier ( name ) )
@@ -716,55 +720,53 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
716
720
const parseNode = getOriginalNode ( sourceFile , isSourceFile ) ;
717
721
const emitNode = getOrCreateEmitNode ( parseNode ) ;
718
722
emitNode . externalHelpers = true ;
723
+
724
+ const externalHelpersImportDeclaration = nodeFactory . createImportDeclaration (
725
+ /*modifiers*/ undefined ,
726
+ nodeFactory . createImportClause ( /*isTypeOnly*/ false , /*name*/ undefined , namedBindings ) ,
727
+ nodeFactory . createStringLiteral ( externalHelpersModuleNameText ) ,
728
+ /*attributes*/ undefined ,
729
+ ) ;
730
+ addInternalEmitFlags ( externalHelpersImportDeclaration , InternalEmitFlags . NeverApplyImportHelper ) ;
731
+ return externalHelpersImportDeclaration ;
719
732
}
720
733
}
721
734
}
722
735
else {
723
- // use a namespace import
724
- const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded ( nodeFactory , sourceFile , compilerOptions , hasExportStarsToExportValues , hasImportStar || hasImportDefault ) ;
736
+ // When we emit to a non-ES module, generate a synthetic ` import tslib = require("tslib")` to be further transformed.
737
+ const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded ( nodeFactory , sourceFile , compilerOptions , helpers , hasExportStarsToExportValues , hasImportStar || hasImportDefault ) ;
725
738
if ( externalHelpersModuleName ) {
726
- namedBindings = nodeFactory . createNamespaceImport ( externalHelpersModuleName ) ;
739
+ const externalHelpersImportDeclaration = nodeFactory . createImportEqualsDeclaration (
740
+ /*modifiers*/ undefined ,
741
+ /*isTypeOnly*/ false ,
742
+ externalHelpersModuleName ,
743
+ nodeFactory . createExternalModuleReference ( nodeFactory . createStringLiteral ( externalHelpersModuleNameText ) ) ,
744
+ ) ;
745
+ addInternalEmitFlags ( externalHelpersImportDeclaration , InternalEmitFlags . NeverApplyImportHelper ) ;
746
+ return externalHelpersImportDeclaration ;
727
747
}
728
748
}
729
- if ( namedBindings ) {
730
- const externalHelpersImportDeclaration = nodeFactory . createImportDeclaration (
731
- /*modifiers*/ undefined ,
732
- nodeFactory . createImportClause ( /*isTypeOnly*/ false , /*name*/ undefined , namedBindings ) ,
733
- nodeFactory . createStringLiteral ( externalHelpersModuleNameText ) ,
734
- /*attributes*/ undefined ,
735
- ) ;
736
- addInternalEmitFlags ( externalHelpersImportDeclaration , InternalEmitFlags . NeverApplyImportHelper ) ;
737
- return externalHelpersImportDeclaration ;
738
- }
739
749
}
740
750
}
741
751
742
- function getOrCreateExternalHelpersModuleNameIfNeeded ( factory : NodeFactory , node : SourceFile , compilerOptions : CompilerOptions , hasExportStarsToExportValues ?: boolean , hasImportStarOrImportDefault ?: boolean ) {
743
- if ( compilerOptions . importHelpers && isEffectiveExternalModule ( node , compilerOptions ) ) {
744
- const externalHelpersModuleName = getExternalHelpersModuleName ( node ) ;
745
- if ( externalHelpersModuleName ) {
746
- return externalHelpersModuleName ;
747
- }
752
+ function getImportedHelpers ( sourceFile : SourceFile ) {
753
+ return filter ( getEmitHelpers ( sourceFile ) , helper => ! helper . scoped ) ;
754
+ }
755
+
756
+ function getOrCreateExternalHelpersModuleNameIfNeeded ( factory : NodeFactory , node : SourceFile , compilerOptions : CompilerOptions , helpers : UnscopedEmitHelper [ ] | undefined , hasExportStarsToExportValues ?: boolean , hasImportStarOrImportDefault ?: boolean ) {
757
+ const externalHelpersModuleName = getExternalHelpersModuleName ( node ) ;
758
+ if ( externalHelpersModuleName ) {
759
+ return externalHelpersModuleName ;
760
+ }
748
761
749
- let create = ( hasExportStarsToExportValues || ( getESModuleInterop ( compilerOptions ) && hasImportStarOrImportDefault ) )
762
+ const create = some ( helpers )
763
+ || ( hasExportStarsToExportValues || ( getESModuleInterop ( compilerOptions ) && hasImportStarOrImportDefault ) )
750
764
&& getEmitModuleFormatOfFileWorker ( node , compilerOptions ) < ModuleKind . System ;
751
- if ( ! create ) {
752
- const helpers = getEmitHelpers ( node ) ;
753
- if ( helpers ) {
754
- for ( const helper of helpers ) {
755
- if ( ! helper . scoped ) {
756
- create = true ;
757
- break ;
758
- }
759
- }
760
- }
761
- }
762
765
763
- if ( create ) {
764
- const parseNode = getOriginalNode ( node , isSourceFile ) ;
765
- const emitNode = getOrCreateEmitNode ( parseNode ) ;
766
- return emitNode . externalHelpersModuleName || ( emitNode . externalHelpersModuleName = factory . createUniqueName ( externalHelpersModuleNameText ) ) ;
767
- }
766
+ if ( create ) {
767
+ const parseNode = getOriginalNode ( node , isSourceFile ) ;
768
+ const emitNode = getOrCreateEmitNode ( parseNode ) ;
769
+ return emitNode . externalHelpersModuleName || ( emitNode . externalHelpersModuleName = factory . createUniqueName ( externalHelpersModuleNameText ) ) ;
768
770
}
769
771
}
770
772
0 commit comments