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
Fix 2021-12 decorators application order #14244
Merged
nicolo-ribaudo
merged 15 commits into
babel:main
from
JLHwung:fix-apply-decs-ordering-14242
Feb 8, 2022
Merged
Changes from 14 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
177903a
decorated class and class init are returned last
JLHwung 6c8e7ca
fix: class decs eval earlier than member decs
JLHwung 6fdf140
fix: decorators are applied from right to left
JLHwung 7f2329a
add es2015 test cases
JLHwung ef391c7
fix: ensure applyDecs is ES5 compliant
JLHwung 17db462
bump applyDecs minVersion
JLHwung 2530ca8
fix: do not return stub initializer when empty
JLHwung dc87a18
Revert "fix: class decs eval earlier than member decs"
JLHwung 46214a1
fix: memoise non-static decorators / keys
JLHwung 3f5e0c6
fix: move insertBefore after path queries
JLHwung ca71772
test: add computed keys to ordering test
JLHwung e31ee57
make node 14 happy
JLHwung d328835
add es2015 test
JLHwung 4f1ba1d
cleanup
JLHwung 796ccba
test: apply static block for node 14
JLHwung File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
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
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 |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import type { NodePath } from "@babel/traverse"; | ||
import type { NodePath, Scope } from "@babel/traverse"; | ||
import { types as t, template } from "@babel/core"; | ||
import syntaxDecorators from "@babel/plugin-syntax-decorators"; | ||
import ReplaceSupers from "@babel/helper-replace-supers"; | ||
|
@@ -506,23 +506,38 @@ function transformClass( | |
let constructorPath: NodePath<t.ClassMethod> | undefined; | ||
let requiresProtoInit = false; | ||
let requiresStaticInit = false; | ||
let hasComputedProps = false; | ||
const decoratedPrivateMethods = new Set<string>(); | ||
|
||
let protoInitLocal: t.Identifier, | ||
staticInitLocal: t.Identifier, | ||
classInitLocal: t.Identifier, | ||
classLocal: t.Identifier; | ||
const assignments: t.AssignmentExpression[] = []; | ||
const scopeParent: Scope = path.scope.parent; | ||
|
||
const memoiseExpression = (expression: t.Expression, hint: string) => { | ||
const localEvaluatedId = scopeParent.generateDeclaredUidIdentifier(hint); | ||
assignments.push(t.assignmentExpression("=", localEvaluatedId, expression)); | ||
return t.cloneNode(localEvaluatedId); | ||
}; | ||
|
||
if (classDecorators) { | ||
classInitLocal = | ||
path.scope.parent.generateDeclaredUidIdentifier("initClass"); | ||
classInitLocal = scopeParent.generateDeclaredUidIdentifier("initClass"); | ||
|
||
const [localId, classPath] = replaceClassWithVar(path); | ||
path = classPath; | ||
classLocal = localId; | ||
|
||
path.node.decorators = null; | ||
|
||
for (const classDecorator of classDecorators) { | ||
if (!scopeParent.isStatic(classDecorator.expression)) { | ||
classDecorator.expression = memoiseExpression( | ||
classDecorator.expression, | ||
"dec", | ||
); | ||
} | ||
} | ||
} else { | ||
if (!path.node.id) { | ||
path.node.id = path.scope.generateUidIdentifier("Class"); | ||
|
@@ -536,43 +551,50 @@ function transformClass( | |
continue; | ||
} | ||
|
||
let { key } = element.node; | ||
const kind = getElementKind(element); | ||
const { node } = element; | ||
const decorators = element.get("decorators"); | ||
|
||
const isPrivate = key.type === "PrivateName"; | ||
const hasDecorators = Array.isArray(decorators) && decorators.length > 0; | ||
|
||
if (hasDecorators) { | ||
for (const decoratorPath of decorators) { | ||
if (!scopeParent.isStatic(decoratorPath.node.expression)) { | ||
decoratorPath.node.expression = memoiseExpression( | ||
decoratorPath.node.expression, | ||
"dec", | ||
); | ||
} | ||
} | ||
} | ||
|
||
const isComputed = | ||
"computed" in element.node && element.node.computed === true; | ||
if (isComputed) { | ||
if (!scopeParent.isStatic(node.key)) { | ||
node.key = memoiseExpression(node.key as t.Expression, "computedKey"); | ||
} | ||
} | ||
|
||
const kind = getElementKind(element); | ||
const { key } = node; | ||
|
||
const isPrivate = key.type === "PrivateName"; | ||
|
||
const isStatic = !!element.node.static; | ||
|
||
let name = "computedKey"; | ||
|
||
if (isPrivate) { | ||
name = (key as t.PrivateName).id.name; | ||
} else if (key.type === "Identifier") { | ||
} else if (!isComputed && key.type === "Identifier") { | ||
name = key.name; | ||
} | ||
|
||
if (element.isClassMethod({ kind: "constructor" })) { | ||
constructorPath = element; | ||
} | ||
|
||
if (isComputed) { | ||
const keyPath = element.get("key"); | ||
const localComputedNameId = | ||
keyPath.scope.parent.generateDeclaredUidIdentifier(name); | ||
keyPath.replaceWith(localComputedNameId); | ||
|
||
elementDecoratorInfo.push({ | ||
localComputedNameId: t.cloneNode(localComputedNameId), | ||
keyNode: t.cloneNode(key as t.Expression), | ||
}); | ||
|
||
key = localComputedNameId; | ||
hasComputedProps = true; | ||
} | ||
|
||
if (Array.isArray(decorators) && decorators.length > 0) { | ||
if (hasDecorators) { | ||
let locals: t.Identifier | t.Identifier[]; | ||
let privateMethods: t.FunctionExpression | t.FunctionExpression[]; | ||
|
||
|
@@ -730,34 +752,6 @@ function transformClass( | |
} | ||
} | ||
|
||
if (hasComputedProps) { | ||
const assignments: t.AssignmentExpression[] = []; | ||
|
||
for (const info of elementDecoratorInfo) { | ||
if (isDecoratorInfo(info)) { | ||
const { decorators } = info; | ||
const newDecorators: t.Identifier[] = []; | ||
|
||
for (const decorator of decorators) { | ||
const localComputedNameId = | ||
path.scope.parent.generateDeclaredUidIdentifier("dec"); | ||
assignments.push( | ||
t.assignmentExpression("=", localComputedNameId, decorator), | ||
); | ||
newDecorators.push(t.cloneNode(localComputedNameId)); | ||
} | ||
|
||
info.decorators = newDecorators; | ||
} else { | ||
assignments.push( | ||
t.assignmentExpression("=", info.localComputedNameId, info.keyNode), | ||
); | ||
} | ||
} | ||
|
||
path.insertBefore(assignments); | ||
} | ||
|
||
const elementDecorations = generateDecorationExprs(elementDecoratorInfo); | ||
const classDecorations = t.arrayExpression( | ||
(classDecorators || []).map(d => d.expression), | ||
|
@@ -766,13 +760,8 @@ function transformClass( | |
const locals: t.Identifier[] = | ||
extractElementLocalAssignments(elementDecoratorInfo); | ||
|
||
if (classDecorators) { | ||
locals.push(classLocal, classInitLocal); | ||
} | ||
|
||
if (requiresProtoInit) { | ||
protoInitLocal = | ||
path.scope.parent.generateDeclaredUidIdentifier("initProto"); | ||
protoInitLocal = scopeParent.generateDeclaredUidIdentifier("initProto"); | ||
locals.push(protoInitLocal); | ||
|
||
const protoInitCall = t.callExpression(t.cloneNode(protoInitLocal), [ | ||
|
@@ -833,8 +822,7 @@ function transformClass( | |
} | ||
|
||
if (requiresStaticInit) { | ||
staticInitLocal = | ||
path.scope.parent.generateDeclaredUidIdentifier("initStatic"); | ||
staticInitLocal = scopeParent.generateDeclaredUidIdentifier("initStatic"); | ||
locals.push(staticInitLocal); | ||
} | ||
|
||
|
@@ -879,6 +867,7 @@ function transformClass( | |
const originalClass = path.node; | ||
|
||
if (classDecorators) { | ||
locals.push(classLocal, classInitLocal); | ||
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.
|
||
const statics = []; | ||
let staticBlocks: t.StaticBlock[] = []; | ||
path.get("body.body").forEach(element => { | ||
|
@@ -982,6 +971,10 @@ function transformClass( | |
), | ||
); | ||
|
||
// When path is a ClassExpression, path.insertBefore will convert `path` | ||
// into a SequenceExpression | ||
path.insertBefore(assignments); | ||
|
||
// Recrawl the scope to make sure new identifiers are properly synced | ||
path.scope.crawl(); | ||
|
||
|
1 change: 1 addition & 0 deletions
1
...el-plugin-proposal-decorators/test/fixtures/2021-12-accessors--to-es2015/private/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
@dec | ||
accessor #a; | ||
|
2 changes: 2 additions & 0 deletions
2
...l-plugin-proposal-decorators/test/fixtures/2021-12-accessors--to-es2015/private/output.js
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
1 change: 1 addition & 0 deletions
1
...bel-plugin-proposal-decorators/test/fixtures/2021-12-accessors--to-es2015/public/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
@dec | ||
accessor a; | ||
|
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
1 change: 1 addition & 0 deletions
1
...in-proposal-decorators/test/fixtures/2021-12-accessors--to-es2015/static-private/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
@dec | ||
static accessor #a; | ||
|
2 changes: 2 additions & 0 deletions
2
...n-proposal-decorators/test/fixtures/2021-12-accessors--to-es2015/static-private/output.js
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
1 change: 1 addition & 0 deletions
1
...gin-proposal-decorators/test/fixtures/2021-12-accessors--to-es2015/static-public/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
@dec | ||
static accessor a; | ||
|
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
1 change: 1 addition & 0 deletions
1
...oposal-decorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-private/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
accessor #a; | ||
|
||
|
2 changes: 2 additions & 0 deletions
2
...posal-decorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-private/output.js
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 |
---|---|---|
@@ -1,3 +1,5 @@ | ||
const dec = () => {}; | ||
|
||
var _A = /*#__PURE__*/new WeakMap(); | ||
|
||
var _a = /*#__PURE__*/new WeakMap(); | ||
|
1 change: 1 addition & 0 deletions
1
...roposal-decorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-public/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
accessor a; | ||
|
||
|
2 changes: 2 additions & 0 deletions
2
...oposal-decorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-public/output.js
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 |
---|---|---|
@@ -1,3 +1,5 @@ | ||
const dec = () => {}; | ||
|
||
var _A = /*#__PURE__*/new WeakMap(); | ||
|
||
var _B = /*#__PURE__*/new WeakMap(); | ||
|
1 change: 1 addition & 0 deletions
1
...decorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-static-private/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
static accessor #a; | ||
|
||
|
2 changes: 2 additions & 0 deletions
2
...ecorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-static-private/output.js
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 |
---|---|---|
@@ -1,3 +1,5 @@ | ||
const dec = () => {}; | ||
|
||
class Foo {} | ||
|
||
function _get_a() { | ||
|
1 change: 1 addition & 0 deletions
1
...-decorators/test/fixtures/2021-12-accessors--to-es2015/undecorated-static-public/input.js
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 |
---|---|---|
@@ -1,3 +1,4 @@ | ||
const dec = () => {}; | ||
class Foo { | ||
static accessor a; | ||
|
||
|
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.
Decorators (after evaluated) are applied from right to left.