forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 15
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
Keep class properties in ESNext target #10
Merged
mheiber
merged 2 commits into
bloomberg:es-private-fields
from
joeywatts:class-properties-esnext
Nov 15, 2018
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -240,6 +240,47 @@ namespace ts { | |
isIdentifier(expression); | ||
} | ||
|
||
/** | ||
* A simple inlinable expression is an expression which can be copied into multiple locations | ||
* without risk of repeating any sideeffects and whose value could not possibly change between | ||
* any such locations | ||
*/ | ||
export function isSimpleInlineableExpression(expression: Expression) { | ||
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) || | ||
isWellKnownSymbolSyntactically(expression); | ||
} | ||
|
||
/** | ||
* Adds super call and preceding prologue directives into the list of statements. | ||
* | ||
* @param ctor The constructor node. | ||
* @param result The list of statements. | ||
* @param visitor The visitor to apply to each node added to the result array. | ||
* @returns index of the statement that follows super call | ||
joeywatts marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
export function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[], visitor: Visitor): number { | ||
if (ctor.body) { | ||
const statements = ctor.body.statements; | ||
// add prologue directives to the list (if any) | ||
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); | ||
if (index === statements.length) { | ||
// list contains nothing but prologue directives (or empty) - exit | ||
return index; | ||
} | ||
|
||
const statement = statements[index]; | ||
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((<ExpressionStatement>statement).expression)) { | ||
result.push(visitNode(statement, visitor, isStatement)); | ||
return index + 1; | ||
} | ||
|
||
return index; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
|
||
/** | ||
* @param input Template string input strings | ||
* @param args Names which need to be made file-level unique | ||
|
@@ -255,4 +296,43 @@ namespace ts { | |
return result; | ||
}; | ||
} | ||
|
||
/** | ||
* Gets all property declarations with initializers on either the static or instance side of a class. | ||
* | ||
* @param node The class node. | ||
* @param isStatic A value indicating whether to get properties from the static or instance side of the class. | ||
*/ | ||
export function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> { | ||
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty); | ||
} | ||
|
||
/** | ||
* Gets a value indicating whether a class element is a static property declaration with an initializer. | ||
* | ||
* @param member The class element node. | ||
*/ | ||
export function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { | ||
return isInitializedProperty(member) && hasStaticModifier(member); | ||
} | ||
joeywatts marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Gets a value indicating whether a class element is an instance property declaration with an initializer. | ||
* | ||
* @param member The class element node. | ||
joeywatts marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
export function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { | ||
return isInitializedProperty(member) && !hasStaticModifier(member); | ||
} | ||
|
||
/** | ||
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. I recommend deleting this doc comment: it's longer than the function and doesn't add any information beyond what the signature says. |
||
* Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer. | ||
* | ||
* @param member The class element node. | ||
* @param isStatic A value indicating whether the member should be a static or instance member. | ||
*/ | ||
export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { | ||
return member.kind === SyntaxKind.PropertyDeclaration | ||
&& (<PropertyDeclaration>member).initializer !== undefined; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
nice work.
It seems to me that the PR does two thing:
Is there anything else? Just checking to make sure I follow
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.
I also understand that you did some work on the interaction of decorators and computed properties. But I can't remember why we needed new code to handle it (I know there was a reason, I just didn't take good enough notes)
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.
The transformation of TypeScript's experimental decorators was sort of entangled in the property transformation that was taking place in the TypeScript transformation. Recall that the goal is to move the class field transformation to the ESNext transformer, but we want to keep the transformation of experimental decorators in the TypeScript transformer.
When transforming decorated properties with computed names, the TypeScript transformer must create a hoisted variable to store the computed property name to avoid it being evaluated twice (once in the initialization of the property and again in the call to the decorator function). Before, the class field transformation and decorator transformation were happening all at once and the declarations were being omitted, but now, we'd like to preserve the class field declarations in the TypeScript transform, and leave the logic of transforming them to the ESNext transform. To accomplish this, the TypeScript transformer only creates a hoisted property name variable for the decorated properties with computed names and keeps the existing property declaration (transforming it to include the assignment to the hoisted variable if necessary).
The ESNext transformer is now responsible for transforming class field declarations. This involves moving the initializers to the constructor and storing computed property names into hoisted variables. Note that this is just for class fields and not for methods, which support computed property names in ES2015. The evaluation order of computed property names must be preserved (see example below where this becomes tricky). This logic was mostly moved from the TypeScript transformer with minor changes to handle the cases where the computed name of a decorated class property was already hoisted into a variable.