@@ -40,6 +40,7 @@ import {
4040 Expression ,
4141 ExpressionStatement ,
4242 externalHelpersModuleNameText ,
43+ filter ,
4344 first ,
4445 firstOrUndefined ,
4546 ForInitializer ,
@@ -131,7 +132,6 @@ import {
131132 MultiplicativeOperator ,
132133 MultiplicativeOperatorOrHigher ,
133134 Mutable ,
134- NamedImportBindings ,
135135 Node ,
136136 NodeArray ,
137137 NodeFactory ,
@@ -173,6 +173,7 @@ import {
173173 Token ,
174174 TransformFlags ,
175175 TypeNode ,
176+ UnscopedEmitHelper ,
176177 WrappedExpression ,
177178} from "../_namespaces/ts.js" ;
178179
@@ -688,26 +689,29 @@ export function hasRecordedExternalHelpers(sourceFile: SourceFile) {
688689/** @internal */
689690export function createExternalHelpersImportDeclarationIfNeeded ( nodeFactory : NodeFactory , helperFactory : EmitHelperFactory , sourceFile : SourceFile , compilerOptions : CompilerOptions , hasExportStarsToExportValues ?: boolean , hasImportStar ?: boolean , hasImportDefault ?: boolean ) {
690691 if ( compilerOptions . importHelpers && isEffectiveExternalModule ( sourceFile , compilerOptions ) ) {
691- let namedBindings : NamedImportBindings | undefined ;
692692 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.
696702 if ( helpers ) {
697703 const helperNames : string [ ] = [ ] ;
698704 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 ) ;
704708 }
705709 }
706710 if ( some ( helperNames ) ) {
707711 helperNames . sort ( compareStringsCaseSensitive ) ;
708712 // Alias the imports if the names are used somewhere in the file.
709713 // 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 (
711715 map ( helperNames , name =>
712716 isFileLevelUniqueName ( sourceFile , name )
713717 ? nodeFactory . createImportSpecifier ( /*isTypeOnly*/ false , /*propertyName*/ undefined , nodeFactory . createIdentifier ( name ) )
@@ -716,55 +720,53 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
716720 const parseNode = getOriginalNode ( sourceFile , isSourceFile ) ;
717721 const emitNode = getOrCreateEmitNode ( parseNode ) ;
718722 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 ;
719732 }
720733 }
721734 }
722735 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 ) ;
725738 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 ;
727747 }
728748 }
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- }
739749 }
740750}
741751
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+ }
748761
749- let create = ( hasExportStarsToExportValues || ( getESModuleInterop ( compilerOptions ) && hasImportStarOrImportDefault ) )
762+ const create = some ( helpers )
763+ || ( hasExportStarsToExportValues || ( getESModuleInterop ( compilerOptions ) && hasImportStarOrImportDefault ) )
750764 && 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- }
762765
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 ) ) ;
768770 }
769771}
770772
0 commit comments