@@ -279,6 +279,16 @@ namespace ts {
279279 let currentSourceFile : SourceFile ;
280280 let currentText : string ;
281281 let hierarchyFacts : HierarchyFacts ;
282+ let taggedTemplateStringDeclarations : VariableDeclaration [ ] ;
283+ function recordTaggedTemplateString ( temp : Identifier ) {
284+ const decl = createVariableDeclaration ( temp ) ;
285+ if ( ! taggedTemplateStringDeclarations ) {
286+ taggedTemplateStringDeclarations = [ decl ] ;
287+ }
288+ else {
289+ taggedTemplateStringDeclarations . push ( decl ) ;
290+ }
291+ }
282292
283293 /**
284294 * Used to track if we are emitting body of the converted loop
@@ -307,6 +317,7 @@ namespace ts {
307317
308318 currentSourceFile = undefined ;
309319 currentText = undefined ;
320+ taggedTemplateStringDeclarations = undefined ;
310321 hierarchyFacts = HierarchyFacts . None ;
311322 return visited ;
312323 }
@@ -520,6 +531,11 @@ namespace ts {
520531 addCaptureThisForNodeIfNeeded ( statements , node ) ;
521532 statementOffset = addCustomPrologue ( statements , node . statements , statementOffset , visitor ) ;
522533 addRange ( statements , visitNodes ( node . statements , visitor , isStatement , statementOffset ) ) ;
534+ if ( taggedTemplateStringDeclarations ) {
535+ statements . push (
536+ createVariableStatement ( /*modifiers*/ undefined ,
537+ createVariableDeclarationList ( taggedTemplateStringDeclarations ) ) ) ;
538+ }
523539 addRange ( statements , endLexicalEnvironment ( ) ) ;
524540 exitSubtree ( ancestorFacts , HierarchyFacts . None , HierarchyFacts . None ) ;
525541 return updateSourceFileNode (
@@ -3637,10 +3653,12 @@ namespace ts {
36373653 const tag = visitNode ( node . tag , visitor , isExpression ) ;
36383654
36393655 // Allocate storage for the template site object
3640- const temp = createTempVariable ( hoistVariableDeclaration ) ;
3656+ const temp = createTempVariable ( recordTaggedTemplateString ) ;
36413657
36423658 // Build up the template arguments and the raw and cooked strings for the template.
3643- const templateArguments : Expression [ ] = [ temp ] ;
3659+ // We start out with 'undefined' for the first argument and revisit later
3660+ // to avoid walking over the template string twice and shifting all our arguments over after the fact.
3661+ const templateArguments : Expression [ ] = [ undefined ] ;
36443662 const cookedStrings : Expression [ ] = [ ] ;
36453663 const rawStrings : Expression [ ] = [ ] ;
36463664 const template = node . template ;
@@ -3658,16 +3676,14 @@ namespace ts {
36583676 }
36593677 }
36603678
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- ) ;
3679+ // Initialize the template object if necessary
3680+ templateArguments [ 0 ] = createLogicalOr (
3681+ temp ,
3682+ createAssignment (
3683+ temp ,
3684+ createTemplateObjectHelper ( context , createArrayLiteral ( cookedStrings ) , createArrayLiteral ( rawStrings ) ) ) ) ;
3685+
3686+ return createCall ( tag , /*typeArguments*/ undefined , templateArguments ) ;
36713687 }
36723688
36733689 /**
@@ -4036,6 +4052,18 @@ namespace ts {
40364052 ) ;
40374053 }
40384054
4055+ function createTemplateObjectHelper ( context : TransformationContext , cooked : ArrayLiteralExpression , raw : ArrayLiteralExpression ) {
4056+ context . requestEmitHelper ( templateObjectHelper ) ;
4057+ return createCall (
4058+ getHelperName ( "__getTemplateObject" ) ,
4059+ /*typeArguments*/ undefined ,
4060+ [
4061+ cooked ,
4062+ raw
4063+ ]
4064+ ) ;
4065+ }
4066+
40394067 const extendsHelper : EmitHelper = {
40404068 name : "typescript:extends" ,
40414069 scoped : false ,
@@ -4052,4 +4080,19 @@ namespace ts {
40524080 };
40534081 })();`
40544082 } ;
4083+
4084+ const templateObjectHelper : EmitHelper = {
4085+ name : "typescript:getTemplateObject" ,
4086+ scoped : false ,
4087+ priority : 0 ,
4088+ text : `
4089+ var __getTemplateObject = (this && this.__getTemplateObject) || function (cooked, raw) {
4090+ if (Object.freeze && Object.defineProperty) {
4091+ return Object.freeze(Object.defineProperty(cooked, "raw", { value: Object.freeze(raw) }));
4092+ }
4093+ cooked.raw = raw;
4094+ return cooked;
4095+ };`
4096+ } ;
4097+
40554098}
0 commit comments