Skip to content

Commit cedbad5

Browse files
rishipalrrdelaney
authored andcommitted
Inject call to createTemplateTagFirstArg() at the nearest SCRIPT scoped node
Currently we inject the calls to createTemplateTagFirstArg at beginning of the SCRIPT which contains a tagged template literal. This creates a runtime error for tagged template literals used in the first SCRIPT. PiperOrigin-RevId: 309995860
1 parent a1c41ba commit cedbad5

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/com/google/javascript/jscomp/Es6TemplateLiterals.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.google.javascript.jscomp;
1717

18+
import static com.google.common.base.Preconditions.checkNotNull;
1819
import static com.google.common.base.Preconditions.checkState;
1920
import static com.google.javascript.jscomp.Es6ToEs3Util.createGenericType;
2021
import static com.google.javascript.jscomp.Es6ToEs3Util.createType;
@@ -158,8 +159,12 @@ void visitTaggedTemplateLiteral(NodeTraversal t, Node n, boolean addTypes) {
158159
.createSingleVarNameDeclaration(TEMPLATELIT_VAR + uniqueId, callTemplateTagArgCreator)
159160
.setJSDocInfo(info)
160161
.useSourceInfoIfMissingFromForTree(n);
161-
Node script = NodeUtil.getEnclosingScript(n);
162-
script.addChildToFront(tagFnFirstArgDeclaration);
162+
163+
// Get the nearest SCRIPT-scoped node as insertion point for this assignment as injecting to the
164+
// top of the script causes runtime errors
165+
// https://github.com/google/closure-compiler/issues/3589
166+
Node insertionPoint = findInsertionPoint(n);
167+
insertionPoint.getParent().addChildBefore(tagFnFirstArgDeclaration, insertionPoint);
163168
t.reportCodeChange(tagFnFirstArgDeclaration);
164169

165170
// Generate the call expression.
@@ -186,6 +191,21 @@ private Node createRawStringArray(Node n, JSType arrayType) {
186191
return array;
187192
}
188193

194+
/**
195+
* Finds the closest enclosing node whose parent is a SCRIPT. We'll want to insert the call to
196+
* `var tagFnFirstArg = $jscomp.createTemplateTagFirstArg...` just before that one.
197+
*/
198+
private static Node findInsertionPoint(Node n) {
199+
Node insertionPoint = n;
200+
Node insertionParent = checkNotNull(insertionPoint.getParent(), n);
201+
while (!insertionParent.isScript()) {
202+
insertionPoint = insertionParent;
203+
insertionParent = checkNotNull(insertionPoint.getParent(), insertionPoint);
204+
}
205+
checkState(insertionParent.isScript(), insertionParent);
206+
return insertionPoint;
207+
}
208+
189209
private Node createCookedStringArray(Node n, JSType templateArrayType) {
190210
Node array = withType(IR.arraylit(), templateArrayType);
191211
for (Node child = n.getFirstChild(); child != null; child = child.getNext()) {

test/com/google/javascript/jscomp/LateEs6ToEs3ConverterTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,36 @@ public void testTaggedTemplateLiteral() {
357357
"tag(TAGGED_TEMPLATE_TMP_VAR$0);"));
358358
}
359359

360+
@Test
361+
public void testTaggedTemplateLiteral_InsertPosition() {
362+
// inserted at the directly enclosing script scope
363+
taggedTemplateLiteral_TestRunner(
364+
lines("var a = {};", "tag``;"),
365+
lines(
366+
"var a = {};",
367+
"/** @noinline */ var TAGGED_TEMPLATE_TMP_VAR$0 =",
368+
" $jscomp.createTemplateTagFirstArg(['']);",
369+
"tag(TAGGED_TEMPLATE_TMP_VAR$0);"));
370+
371+
// inserted at the script scope above the immediate enclosing function at the script scope
372+
taggedTemplateLiteral_TestRunner(
373+
lines("var a = {};", "function foo() {tag``;}"),
374+
lines(
375+
"var a = {};",
376+
"/** @noinline */ var TAGGED_TEMPLATE_TMP_VAR$0 =",
377+
" $jscomp.createTemplateTagFirstArg(['']);",
378+
"function foo() {tag(TAGGED_TEMPLATE_TMP_VAR$0);}"));
379+
380+
// inserted at the script scope above the outer enclosing function at the script scope
381+
taggedTemplateLiteral_TestRunner(
382+
lines("var a = {};", "function foo() {function bar() {tag``;}}"),
383+
lines(
384+
"var a = {};",
385+
"/** @noinline */ var TAGGED_TEMPLATE_TMP_VAR$0 =",
386+
" $jscomp.createTemplateTagFirstArg(['']);",
387+
"function foo() {function bar() {tag(TAGGED_TEMPLATE_TMP_VAR$0);}}"));
388+
}
389+
360390
@Test
361391
public void testUnicodeEscapes() {
362392
test("var \\u{73} = \'\\u{2603}\'", "var s = \'\u2603\'"); // ☃

0 commit comments

Comments
 (0)