Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
environmentVisitor should skip decorator expressions (#14371)
* refactor: remove @babel/types deps * fix: replace super in decorator expressions * fix: rename variables in decorator expressions * fix: allow any traversal state * review comment * fix: also apply on class private property * fix: skip method scope for decorator expressions * feat: export requeueComputedKeyAndDecorator * review comments * add test case * fix: requeue computed keys of class accessors * fix typing errors
- Loading branch information
Showing
28 changed files
with
400 additions
and
60 deletions.
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
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,38 +1,56 @@ | ||
import type { NodePath } from "@babel/traverse"; | ||
import { VISITOR_KEYS, staticBlock } from "@babel/types"; | ||
import type { NodePath, Visitor } from "@babel/traverse"; | ||
import type * as t from "@babel/types"; | ||
|
||
// TODO (Babel 8): Don't export this function. | ||
export function skipAllButComputedKey( | ||
path: NodePath<t.Method | t.ClassProperty>, | ||
) { | ||
// If the path isn't computed, just skip everything. | ||
if (!path.node.computed) { | ||
path.skip(); | ||
return; | ||
path.skip(); | ||
if (path.node.computed) { | ||
// requeue the computed key | ||
path.context.maybeQueue(path.get("key")); | ||
} | ||
} | ||
|
||
// So it's got a computed key. Make sure to skip every other key the | ||
// traversal would visit. | ||
const keys = VISITOR_KEYS[path.type]; | ||
for (const key of keys) { | ||
if (key !== "key") path.skipKey(key); | ||
export function requeueComputedKeyAndDecorators( | ||
path: NodePath<t.Method | t.Property>, | ||
) { | ||
const { context, node } = path; | ||
//@ts-ignore ClassPrivateProperty does not have computed | ||
if (node.computed) { | ||
// requeue the computed key | ||
context.maybeQueue(path.get("key")); | ||
} | ||
if (node.decorators) { | ||
for (const decorator of path.get("decorators")) { | ||
// requeue the decorators | ||
context.maybeQueue(decorator); | ||
} | ||
} | ||
} | ||
|
||
// Methods are handled by the Method visitor; arrows are not skipped because they inherit the context. | ||
const skipKey = process.env.BABEL_8_BREAKING | ||
? "StaticBlock|ClassPrivateProperty|TypeAnnotation|FunctionDeclaration|FunctionExpression" | ||
: (staticBlock ? "StaticBlock|" : "") + | ||
"ClassPrivateProperty|TypeAnnotation|FunctionDeclaration|FunctionExpression"; | ||
|
||
// environmentVisitor should be used when traversing the whole class and not for specific class elements/methods. | ||
// For perf reasons, the environmentVisitor might be traversed with `{ noScope: true }`, which means `path.scope` is undefined. | ||
// Avoid using `path.scope` here | ||
export default { | ||
[skipKey]: path => path.skip(), | ||
|
||
"Method|ClassProperty"(path: NodePath<t.Method | t.ClassProperty>) { | ||
skipAllButComputedKey(path); | ||
const visitor: Visitor = { | ||
FunctionParent(path) { | ||
if (path.isArrowFunctionExpression()) { | ||
// arrows are not skipped because they inherit the context. | ||
return; | ||
} else { | ||
path.skip(); | ||
if (path.isMethod()) { | ||
requeueComputedKeyAndDecorators(path); | ||
} | ||
} | ||
}, | ||
Property(path) { | ||
if (path.isObjectProperty()) { | ||
return; | ||
} | ||
path.skip(); | ||
requeueComputedKeyAndDecorators(path); | ||
}, | ||
}; | ||
|
||
export default visitor; |
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
7 changes: 6 additions & 1 deletion
7
packages/babel-plugin-proposal-class-properties/test/fixtures/nested-class/options.json
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,8 @@ | ||
{ | ||
"plugins": ["proposal-class-properties", "transform-classes"] | ||
"plugins": [ | ||
["proposal-decorators", { "version": "2021-12" }], | ||
"proposal-class-static-block", | ||
"proposal-class-properties", | ||
"transform-classes" | ||
] | ||
} |
18 changes: 18 additions & 0 deletions
18
...ugin-proposal-class-properties/test/fixtures/nested-class/super-call-in-decorator/exec.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 |
---|---|---|
@@ -0,0 +1,18 @@ | ||
"use strict"; | ||
class Hello { | ||
constructor() { | ||
return () => () => "hello"; | ||
} | ||
} | ||
|
||
class Outer extends Hello { | ||
constructor() { | ||
class Inner { | ||
@(super()) hello; | ||
} | ||
|
||
return new Inner(); | ||
} | ||
} | ||
|
||
expect(new Outer().hello).toBe('hello'); |
18 changes: 18 additions & 0 deletions
18
...gin-proposal-class-properties/test/fixtures/nested-class/super-call-in-decorator/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 |
---|---|---|
@@ -0,0 +1,18 @@ | ||
"use strict"; | ||
class Hello { | ||
constructor() { | ||
return () => () => "hello"; | ||
} | ||
} | ||
|
||
class Outer extends Hello { | ||
constructor() { | ||
class Inner { | ||
@(super()) hello; | ||
} | ||
|
||
return new Inner(); | ||
} | ||
} | ||
|
||
expect(new Outer().hello).toBe('hello'); |
31 changes: 31 additions & 0 deletions
31
...in-proposal-class-properties/test/fixtures/nested-class/super-call-in-decorator/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 |
---|---|---|
@@ -0,0 +1,31 @@ | ||
"use strict"; | ||
|
||
let Hello = /*#__PURE__*/babelHelpers.createClass(function Hello() { | ||
babelHelpers.classCallCheck(this, Hello); | ||
return () => () => "hello"; | ||
}); | ||
|
||
let Outer = /*#__PURE__*/function (_Hello) { | ||
babelHelpers.inherits(Outer, _Hello); | ||
|
||
var _super = babelHelpers.createSuper(Outer); | ||
|
||
function Outer() { | ||
var _dec, _init_hello; | ||
|
||
var _this; | ||
|
||
babelHelpers.classCallCheck(this, Outer); | ||
_dec = _this = _super.call(this); | ||
let Inner = /*#__PURE__*/babelHelpers.createClass(function Inner() { | ||
babelHelpers.classCallCheck(this, Inner); | ||
babelHelpers.defineProperty(this, "hello", _init_hello(this)); | ||
}); | ||
[_init_hello] = babelHelpers.applyDecs(Inner, [[_dec, 0, "hello"]], []); | ||
return babelHelpers.possibleConstructorReturn(_this, new Inner()); | ||
} | ||
|
||
return babelHelpers.createClass(Outer); | ||
}(Hello); | ||
|
||
expect(new Outer().hello).toBe('hello'); |
19 changes: 19 additions & 0 deletions
19
...oposal-class-properties/test/fixtures/nested-class/super-property-in-accessor-key/exec.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 |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"use strict"; | ||
class Hello { | ||
toString() { | ||
return 'hello'; | ||
} | ||
} | ||
|
||
class Outer extends Hello { | ||
constructor() { | ||
super(); | ||
class Inner { | ||
accessor [super.toString()] = 'hello'; | ||
} | ||
|
||
return new Inner(); | ||
} | ||
} | ||
|
||
expect(new Outer().hello).toBe('hello'); |
19 changes: 19 additions & 0 deletions
19
...posal-class-properties/test/fixtures/nested-class/super-property-in-accessor-key/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 |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"use strict"; | ||
class Hello { | ||
toString() { | ||
return 'hello'; | ||
} | ||
} | ||
|
||
class Outer extends Hello { | ||
constructor() { | ||
super(); | ||
class Inner { | ||
accessor [super.toString()] = 'hello'; | ||
} | ||
|
||
return new Inner(); | ||
} | ||
} | ||
|
||
expect(new Outer().hello).toBe('hello'); |
8 changes: 8 additions & 0 deletions
8
...l-class-properties/test/fixtures/nested-class/super-property-in-accessor-key/options.json
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 |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"plugins": [ | ||
["proposal-decorators", { "version": "2021-12" }], | ||
"proposal-class-static-block", | ||
"proposal-class-properties", | ||
"transform-classes" | ||
] | ||
} |
64 changes: 64 additions & 0 deletions
64
...osal-class-properties/test/fixtures/nested-class/super-property-in-accessor-key/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 |
---|---|---|
@@ -0,0 +1,64 @@ | ||
"use strict"; | ||
|
||
let Hello = /*#__PURE__*/function () { | ||
function Hello() { | ||
babelHelpers.classCallCheck(this, Hello); | ||
} | ||
|
||
babelHelpers.createClass(Hello, [{ | ||
key: "toString", | ||
value: function toString() { | ||
return 'hello'; | ||
} | ||
}]); | ||
return Hello; | ||
}(); | ||
|
||
let Outer = /*#__PURE__*/function (_Hello) { | ||
babelHelpers.inherits(Outer, _Hello); | ||
|
||
var _super = babelHelpers.createSuper(Outer); | ||
|
||
function Outer() { | ||
let _babelHelpers$get$cal, _babelHelpers$get$cal2; | ||
|
||
var _thisSuper, _this; | ||
|
||
babelHelpers.classCallCheck(this, Outer); | ||
_this = _super.call(this); | ||
|
||
var _A = /*#__PURE__*/new WeakMap(); | ||
|
||
_babelHelpers$get$cal = babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Outer.prototype)), "toString", _thisSuper).call(_thisSuper); | ||
_babelHelpers$get$cal2 = babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Outer.prototype)), "toString", _thisSuper).call(_thisSuper); | ||
|
||
let Inner = /*#__PURE__*/function () { | ||
function Inner() { | ||
babelHelpers.classCallCheck(this, Inner); | ||
babelHelpers.classPrivateFieldInitSpec(this, _A, { | ||
writable: true, | ||
value: 'hello' | ||
}); | ||
} | ||
|
||
babelHelpers.createClass(Inner, [{ | ||
key: _babelHelpers$get$cal, | ||
get: function () { | ||
return babelHelpers.classPrivateFieldGet(this, _A); | ||
} | ||
}, { | ||
key: _babelHelpers$get$cal2, | ||
set: function (v) { | ||
babelHelpers.classPrivateFieldSet(this, _A, v); | ||
} | ||
}]); | ||
return Inner; | ||
}(); | ||
|
||
return babelHelpers.possibleConstructorReturn(_this, new Inner()); | ||
} | ||
|
||
return babelHelpers.createClass(Outer); | ||
}(Hello); | ||
|
||
expect(new Outer().hello).toBe('hello'); |
17 changes: 17 additions & 0 deletions
17
...-proposal-class-properties/test/fixtures/nested-class/super-property-in-decorator/exec.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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
class Hello { | ||
dec() { return () => "hello" } | ||
} | ||
|
||
class Outer extends Hello { | ||
constructor() { | ||
super(); | ||
class Inner { | ||
@(super.dec) hello; | ||
} | ||
|
||
return new Inner(); | ||
} | ||
} | ||
|
||
expect(new Outer().hello).toBe('hello'); |
17 changes: 17 additions & 0 deletions
17
...proposal-class-properties/test/fixtures/nested-class/super-property-in-decorator/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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
class Hello { | ||
dec() { return () => "hello" } | ||
} | ||
|
||
class Outer extends Hello { | ||
constructor() { | ||
super(); | ||
class Inner { | ||
@(super.dec) hello; | ||
} | ||
|
||
return new Inner(); | ||
} | ||
} | ||
|
||
expect(new Outer().hello).toBe('hello'); |
41 changes: 41 additions & 0 deletions
41
...roposal-class-properties/test/fixtures/nested-class/super-property-in-decorator/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 |
---|---|---|
@@ -0,0 +1,41 @@ | ||
"use strict"; | ||
|
||
let Hello = /*#__PURE__*/function () { | ||
function Hello() { | ||
babelHelpers.classCallCheck(this, Hello); | ||
} | ||
|
||
babelHelpers.createClass(Hello, [{ | ||
key: "dec", | ||
value: function dec() { | ||
return () => "hello"; | ||
} | ||
}]); | ||
return Hello; | ||
}(); | ||
|
||
let Outer = /*#__PURE__*/function (_Hello) { | ||
babelHelpers.inherits(Outer, _Hello); | ||
|
||
var _super = babelHelpers.createSuper(Outer); | ||
|
||
function Outer() { | ||
var _dec, _init_hello; | ||
|
||
var _thisSuper, _this; | ||
|
||
babelHelpers.classCallCheck(this, Outer); | ||
_this = _super.call(this); | ||
_dec = babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Outer.prototype)), "dec", _thisSuper); | ||
let Inner = /*#__PURE__*/babelHelpers.createClass(function Inner() { | ||
babelHelpers.classCallCheck(this, Inner); | ||
babelHelpers.defineProperty(this, "hello", _init_hello(this)); | ||
}); | ||
[_init_hello] = babelHelpers.applyDecs(Inner, [[_dec, 0, "hello"]], []); | ||
return babelHelpers.possibleConstructorReturn(_this, new Inner()); | ||
} | ||
|
||
return babelHelpers.createClass(Outer); | ||
}(Hello); | ||
|
||
expect(new Outer().hello).toBe('hello'); |
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.