-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correctly cache tagged template objects in modules #18300
Changes from 2 commits
c4b1a9d
166af8c
aa634ba
4beb9b0
6a9fa83
c966059
8fbb304
7871e08
9f669d0
e9c6dfe
1656790
b137f24
5565709
9907453
1cb5eb9
886a29b
1841afe
0b7538d
b406d54
4ec1643
d039942
5da45fb
f94bded
81b3e85
a23d1bf
e2c6aac
b80b2ee
babe3cb
8fd638c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -279,6 +279,16 @@ namespace ts { | |
let currentSourceFile: SourceFile; | ||
let currentText: string; | ||
let hierarchyFacts: HierarchyFacts; | ||
let taggedTemplateStringDeclarations: VariableDeclaration[]; | ||
function recordTaggedTemplateString(temp: Identifier) { | ||
const decl = createVariableDeclaration(temp); | ||
if (!taggedTemplateStringDeclarations) { | ||
taggedTemplateStringDeclarations = [decl]; | ||
} | ||
else { | ||
taggedTemplateStringDeclarations.push(decl); | ||
} | ||
} | ||
|
||
/** | ||
* Used to track if we are emitting body of the converted loop | ||
|
@@ -307,6 +317,7 @@ namespace ts { | |
|
||
currentSourceFile = undefined; | ||
currentText = undefined; | ||
taggedTemplateStringDeclarations = undefined; | ||
hierarchyFacts = HierarchyFacts.None; | ||
return visited; | ||
} | ||
|
@@ -520,6 +531,11 @@ namespace ts { | |
addCaptureThisForNodeIfNeeded(statements, node); | ||
statementOffset = addCustomPrologue(statements, node.statements, statementOffset, visitor); | ||
addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); | ||
if (taggedTemplateStringDeclarations) { | ||
statements.push( | ||
createVariableStatement(/*modifiers*/ undefined, | ||
createVariableDeclarationList(taggedTemplateStringDeclarations))); | ||
} | ||
addRange(statements, endLexicalEnvironment()); | ||
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); | ||
return updateSourceFileNode( | ||
|
@@ -3637,10 +3653,12 @@ namespace ts { | |
const tag = visitNode(node.tag, visitor, isExpression); | ||
|
||
// Allocate storage for the template site object | ||
const temp = createTempVariable(hoistVariableDeclaration); | ||
const temp = createTempVariable(recordTaggedTemplateString); | ||
|
||
// Build up the template arguments and the raw and cooked strings for the template. | ||
const templateArguments: Expression[] = [temp]; | ||
// We start out with 'undefined' for the first argument and revisit later | ||
// to avoid walking over the template string twice and shifting all our arguments over after the fact. | ||
const templateArguments: Expression[] = [undefined]; | ||
const cookedStrings: Expression[] = []; | ||
const rawStrings: Expression[] = []; | ||
const template = node.template; | ||
|
@@ -3658,16 +3676,14 @@ namespace ts { | |
} | ||
} | ||
|
||
// NOTE: The parentheses here is entirely optional as we are now able to auto- | ||
// parenthesize when rebuilding the tree. This should be removed in a | ||
// future version. It is here for now to match our existing emit. | ||
return createParen( | ||
inlineExpressions([ | ||
createAssignment(temp, createArrayLiteral(cookedStrings)), | ||
createAssignment(createPropertyAccess(temp, "raw"), createArrayLiteral(rawStrings)), | ||
createCall(tag, /*typeArguments*/ undefined, templateArguments) | ||
]) | ||
); | ||
// Initialize the template object if necessary | ||
templateArguments[0] = createLogicalOr( | ||
temp, | ||
createAssignment( | ||
temp, | ||
createTemplateObjectHelper(context, createArrayLiteral(cookedStrings), createArrayLiteral(rawStrings)))); | ||
|
||
return createCall(tag, /*typeArguments*/ undefined, templateArguments); | ||
} | ||
|
||
/** | ||
|
@@ -4036,6 +4052,18 @@ namespace ts { | |
); | ||
} | ||
|
||
function createTemplateObjectHelper(context: TransformationContext, cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression) { | ||
context.requestEmitHelper(templateObjectHelper); | ||
return createCall( | ||
getHelperName("__getTemplateObject"), | ||
/*typeArguments*/ undefined, | ||
[ | ||
cooked, | ||
raw | ||
] | ||
); | ||
} | ||
|
||
const extendsHelper: EmitHelper = { | ||
name: "typescript:extends", | ||
scoped: false, | ||
|
@@ -4052,4 +4080,19 @@ namespace ts { | |
}; | ||
})();` | ||
}; | ||
|
||
const templateObjectHelper: EmitHelper = { | ||
name: "typescript:getTemplateObject", | ||
scoped: false, | ||
priority: 0, | ||
text: ` | ||
var __getTemplateObject = (this && this.__getTemplateObject) || function (cooked, raw) { | ||
if (Object.freeze && Object.defineProperty) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need the defineProperty call? I suppose it makes the property non-enumerable... |
||
return Object.freeze(Object.defineProperty(cooked, "raw", { value: Object.freeze(raw) })); | ||
} | ||
cooked.raw = raw; | ||
return cooked; | ||
};` | ||
}; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4217,22 +4217,23 @@ namespace ts { | |
*/ | ||
/* @internal */ | ||
export const enum ExternalEmitHelpers { | ||
Extends = 1 << 0, // __extends (used by the ES2015 class transformation) | ||
Assign = 1 << 1, // __assign (used by Jsx and ESNext object spread transformations) | ||
Rest = 1 << 2, // __rest (used by ESNext object rest transformation) | ||
Decorate = 1 << 3, // __decorate (used by TypeScript decorators transformation) | ||
Metadata = 1 << 4, // __metadata (used by TypeScript decorators transformation) | ||
Param = 1 << 5, // __param (used by TypeScript decorators transformation) | ||
Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation) | ||
Generator = 1 << 7, // __generator (used by ES2015 generator transformation) | ||
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations) | ||
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation) | ||
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations) | ||
Await = 1 << 11, // __await (used by ES2017 async generator transformation) | ||
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation) | ||
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation) | ||
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation) | ||
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation) | ||
Extends = 1 << 0, // __extends (used by the ES2015 class transformation) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this change is an example of why aligned comments make me sad :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :( |
||
Assign = 1 << 1, // __assign (used by Jsx and ESNext object spread transformations) | ||
Rest = 1 << 2, // __rest (used by ESNext object rest transformation) | ||
Decorate = 1 << 3, // __decorate (used by TypeScript decorators transformation) | ||
Metadata = 1 << 4, // __metadata (used by TypeScript decorators transformation) | ||
Param = 1 << 5, // __param (used by TypeScript decorators transformation) | ||
Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation) | ||
Generator = 1 << 7, // __generator (used by ES2015 generator transformation) | ||
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations) | ||
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation) | ||
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations) | ||
Await = 1 << 11, // __await (used by ES2017 async generator transformation) | ||
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation) | ||
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation) | ||
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation) | ||
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation) | ||
GetTemplateObject = 1 << 16, // __getTemplateObject (used for constructing template string array objects) | ||
|
||
// Helpers included by ES2015 for..of | ||
ForOfIncludes = Values, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
taggedTemplateStringDeclarations = append(taggedTemplateStringDeclarations, createVariableDeclaration(temp));