@@ -279,6 +279,13 @@ namespace ts {
279
279
let currentSourceFile : SourceFile ;
280
280
let currentText : string ;
281
281
let hierarchyFacts : HierarchyFacts ;
282
+ let taggedTemplateStringDeclarations : VariableDeclaration [ ] ;
283
+
284
+ function recordTaggedTemplateString ( temp : Identifier ) {
285
+ taggedTemplateStringDeclarations = append (
286
+ taggedTemplateStringDeclarations ,
287
+ createVariableDeclaration ( temp ) ) ;
288
+ }
282
289
283
290
/**
284
291
* Used to track if we are emitting body of the converted loop
@@ -307,6 +314,7 @@ namespace ts {
307
314
308
315
currentSourceFile = undefined ;
309
316
currentText = undefined ;
317
+ taggedTemplateStringDeclarations = undefined ;
310
318
hierarchyFacts = HierarchyFacts . None ;
311
319
return visited ;
312
320
}
@@ -520,6 +528,11 @@ namespace ts {
520
528
addCaptureThisForNodeIfNeeded ( statements , node ) ;
521
529
statementOffset = addCustomPrologue ( statements , node . statements , statementOffset , visitor ) ;
522
530
addRange ( statements , visitNodes ( node . statements , visitor , isStatement , statementOffset ) ) ;
531
+ if ( taggedTemplateStringDeclarations ) {
532
+ statements . push (
533
+ createVariableStatement ( /*modifiers*/ undefined ,
534
+ createVariableDeclarationList ( taggedTemplateStringDeclarations ) ) ) ;
535
+ }
523
536
addRange ( statements , endLexicalEnvironment ( ) ) ;
524
537
exitSubtree ( ancestorFacts , HierarchyFacts . None , HierarchyFacts . None ) ;
525
538
return updateSourceFileNode (
@@ -3636,11 +3649,10 @@ namespace ts {
3636
3649
// Visit the tag expression
3637
3650
const tag = visitNode ( node . tag , visitor , isExpression ) ;
3638
3651
3639
- // Allocate storage for the template site object
3640
- const temp = createTempVariable ( hoistVariableDeclaration ) ;
3641
-
3642
3652
// 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 ] ;
3644
3656
const cookedStrings : Expression [ ] = [ ] ;
3645
3657
const rawStrings : Expression [ ] = [ ] ;
3646
3658
const template = node . template ;
@@ -3658,16 +3670,25 @@ namespace ts {
3658
3670
}
3659
3671
}
3660
3672
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 ) ;
3671
3692
}
3672
3693
3673
3694
/**
@@ -4036,6 +4057,18 @@ namespace ts {
4036
4057
) ;
4037
4058
}
4038
4059
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
+
4039
4072
const extendsHelper : EmitHelper = {
4040
4073
name : "typescript:extends" ,
4041
4074
scoped : false ,
@@ -4052,4 +4085,16 @@ namespace ts {
4052
4085
};
4053
4086
})();`
4054
4087
} ;
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
+
4055
4100
}
0 commit comments