@@ -279,6 +279,13 @@ namespace ts {
279279 let currentSourceFile : SourceFile ;
280280 let currentText : string ;
281281 let hierarchyFacts : HierarchyFacts ;
282+ let taggedTemplateStringDeclarations : VariableDeclaration [ ] ;
283+
284+ function recordTaggedTemplateString ( temp : Identifier ) {
285+ taggedTemplateStringDeclarations = append (
286+ taggedTemplateStringDeclarations ,
287+ createVariableDeclaration ( temp ) ) ;
288+ }
282289
283290 /**
284291 * Used to track if we are emitting body of the converted loop
@@ -307,6 +314,7 @@ namespace ts {
307314
308315 currentSourceFile = undefined ;
309316 currentText = undefined ;
317+ taggedTemplateStringDeclarations = undefined ;
310318 hierarchyFacts = HierarchyFacts . None ;
311319 return visited ;
312320 }
@@ -520,6 +528,11 @@ namespace ts {
520528 addCaptureThisForNodeIfNeeded ( statements , node ) ;
521529 statementOffset = addCustomPrologue ( statements , node . statements , statementOffset , visitor ) ;
522530 addRange ( statements , visitNodes ( node . statements , visitor , isStatement , statementOffset ) ) ;
531+ if ( taggedTemplateStringDeclarations ) {
532+ statements . push (
533+ createVariableStatement ( /*modifiers*/ undefined ,
534+ createVariableDeclarationList ( taggedTemplateStringDeclarations ) ) ) ;
535+ }
523536 addRange ( statements , endLexicalEnvironment ( ) ) ;
524537 exitSubtree ( ancestorFacts , HierarchyFacts . None , HierarchyFacts . None ) ;
525538 return updateSourceFileNode (
@@ -3636,11 +3649,10 @@ namespace ts {
36363649 // Visit the tag expression
36373650 const tag = visitNode ( node . tag , visitor , isExpression ) ;
36383651
3639- // Allocate storage for the template site object
3640- const temp = createTempVariable ( hoistVariableDeclaration ) ;
3641-
36423652 // Build up the template arguments and the raw and cooked strings for the template.
3643- const templateArguments : Expression [ ] = [ temp ] ;
3653+ // We start out with 'undefined' for the first argument and revisit later
3654+ // to avoid walking over the template string twice and shifting all our arguments over after the fact.
3655+ const templateArguments : Expression [ ] = [ undefined ] ;
36443656 const cookedStrings : Expression [ ] = [ ] ;
36453657 const rawStrings : Expression [ ] = [ ] ;
36463658 const template = node . template ;
@@ -3658,16 +3670,25 @@ namespace ts {
36583670 }
36593671 }
36603672
3661- // NOTE: The parentheses here is entirely optional as we are now able to auto-
3662- // parenthesize when rebuilding the tree. This should be removed in a
3663- // future version. It is here for now to match our existing emit.
3664- return createParen (
3665- inlineExpressions ( [
3666- createAssignment ( temp , createArrayLiteral ( cookedStrings ) ) ,
3667- createAssignment ( createPropertyAccess ( temp , "raw" ) , createArrayLiteral ( rawStrings ) ) ,
3668- createCall ( tag , /*typeArguments*/ undefined , templateArguments )
3669- ] )
3670- ) ;
3673+ const helperCall = createTemplateObjectHelper ( context , createArrayLiteral ( cookedStrings ) , createArrayLiteral ( rawStrings ) ) ;
3674+
3675+ // Create a variable to cache the template object if we're in a module.
3676+ // Do not do this in the global scope, as any variable we currently generate could conflict with
3677+ // variables from outside of the current compilation. In the future, we can revisit this behavior.
3678+ if ( isExternalModule ( currentSourceFile ) ) {
3679+ const tempVar = createTempVariable ( recordTaggedTemplateString ) ;
3680+ templateArguments [ 0 ] = createLogicalOr (
3681+ tempVar ,
3682+ createAssignment (
3683+ tempVar ,
3684+ helperCall )
3685+ ) ;
3686+ }
3687+ else {
3688+ templateArguments [ 0 ] = helperCall ;
3689+ }
3690+
3691+ return createCall ( tag , /*typeArguments*/ undefined , templateArguments ) ;
36713692 }
36723693
36733694 /**
@@ -4036,6 +4057,18 @@ namespace ts {
40364057 ) ;
40374058 }
40384059
4060+ function createTemplateObjectHelper ( context : TransformationContext , cooked : ArrayLiteralExpression , raw : ArrayLiteralExpression ) {
4061+ context . requestEmitHelper ( templateObjectHelper ) ;
4062+ return createCall (
4063+ getHelperName ( "__makeTemplateObject" ) ,
4064+ /*typeArguments*/ undefined ,
4065+ [
4066+ cooked ,
4067+ raw
4068+ ]
4069+ ) ;
4070+ }
4071+
40394072 const extendsHelper : EmitHelper = {
40404073 name : "typescript:extends" ,
40414074 scoped : false ,
@@ -4052,4 +4085,16 @@ namespace ts {
40524085 };
40534086 })();`
40544087 } ;
4088+
4089+ const templateObjectHelper : EmitHelper = {
4090+ name : "typescript:makeTemplateObject" ,
4091+ scoped : false ,
4092+ priority : 0 ,
4093+ text : `
4094+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
4095+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
4096+ return cooked;
4097+ };`
4098+ } ;
4099+
40554100}
0 commit comments