[decorators] Only transform declarations to expressions when needed (#7124)
This commit is contained in:
parent
bb17b72f4f
commit
b93184e430
@ -63,11 +63,11 @@ export default function() {
|
|||||||
* with the proper decorated behavior.
|
* with the proper decorated behavior.
|
||||||
*/
|
*/
|
||||||
function applyClassDecorators(classPath) {
|
function applyClassDecorators(classPath) {
|
||||||
|
if (!hasClassDecorators(classPath.node)) return;
|
||||||
|
|
||||||
const decorators = classPath.node.decorators || [];
|
const decorators = classPath.node.decorators || [];
|
||||||
classPath.node.decorators = null;
|
classPath.node.decorators = null;
|
||||||
|
|
||||||
if (decorators.length === 0) return;
|
|
||||||
|
|
||||||
const name = classPath.scope.generateDeclaredUidIdentifier("class");
|
const name = classPath.scope.generateDeclaredUidIdentifier("class");
|
||||||
|
|
||||||
return decorators
|
return decorators
|
||||||
@ -82,30 +82,30 @@ export default function() {
|
|||||||
}, classPath.node);
|
}, classPath.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasClassDecorators(classNode) {
|
||||||
|
return !!(classNode.decorators && classNode.decorators.length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a class expression with method-level decorators, create a new expression
|
* Given a class expression with method-level decorators, create a new expression
|
||||||
* with the proper decorated behavior.
|
* with the proper decorated behavior.
|
||||||
*/
|
*/
|
||||||
function applyMethodDecorators(path, state) {
|
function applyMethodDecorators(path, state) {
|
||||||
const hasMethodDecorators = path.node.body.body.some(function(node) {
|
if (!hasMethodDecorators(path.node.body.body)) return;
|
||||||
return (node.decorators || []).length > 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!hasMethodDecorators) return;
|
|
||||||
|
|
||||||
return applyTargetDecorators(path, state, path.node.body.body);
|
return applyTargetDecorators(path, state, path.node.body.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasMethodDecorators(body) {
|
||||||
|
return body.some(node => node.decorators && node.decorators.length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an object expression with property decorators, create a new expression
|
* Given an object expression with property decorators, create a new expression
|
||||||
* with the proper decorated behavior.
|
* with the proper decorated behavior.
|
||||||
*/
|
*/
|
||||||
function applyObjectDecorators(path, state) {
|
function applyObjectDecorators(path, state) {
|
||||||
const hasMethodDecorators = path.node.properties.some(function(node) {
|
if (!hasMethodDecorators(path.node.properties)) return;
|
||||||
return (node.decorators || []).length > 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!hasMethodDecorators) return;
|
|
||||||
|
|
||||||
return applyTargetDecorators(path, state, path.node.properties);
|
return applyTargetDecorators(path, state, path.node.properties);
|
||||||
}
|
}
|
||||||
@ -215,32 +215,29 @@ export default function() {
|
|||||||
inherits: syntaxDecorators,
|
inherits: syntaxDecorators,
|
||||||
|
|
||||||
visitor: {
|
visitor: {
|
||||||
ExportDefaultDeclaration(path) {
|
|
||||||
if (!path.get("declaration").isClassDeclaration()) return;
|
|
||||||
|
|
||||||
const { node } = path;
|
|
||||||
const ref =
|
|
||||||
node.declaration.id || path.scope.generateUidIdentifier("default");
|
|
||||||
node.declaration.id = ref;
|
|
||||||
|
|
||||||
// Split the class declaration and the export into two separate statements.
|
|
||||||
path.replaceWith(node.declaration);
|
|
||||||
path.insertAfter(
|
|
||||||
t.exportNamedDeclaration(null, [
|
|
||||||
t.exportSpecifier(ref, t.identifier("default")),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
ClassDeclaration(path) {
|
ClassDeclaration(path) {
|
||||||
const { node } = path;
|
const { node } = path;
|
||||||
|
|
||||||
const ref = node.id || path.scope.generateUidIdentifier("class");
|
if (!hasClassDecorators(node) && !hasMethodDecorators(node.body.body)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
path.replaceWith(
|
const ref = node.id || path.scope.generateUidIdentifier("class");
|
||||||
t.variableDeclaration("let", [
|
const letDeclaration = t.variableDeclaration("let", [
|
||||||
t.variableDeclarator(ref, t.toExpression(node)),
|
t.variableDeclarator(ref, t.toExpression(node)),
|
||||||
]),
|
]);
|
||||||
);
|
|
||||||
|
if (path.parentPath.isExportDefaultDeclaration()) {
|
||||||
|
// Split the class declaration and the export into two separate statements.
|
||||||
|
path.parentPath.replaceWithMultiple([
|
||||||
|
letDeclaration,
|
||||||
|
t.exportNamedDeclaration(null, [
|
||||||
|
t.exportSpecifier(ref, t.identifier("default")),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
path.replaceWith(letDeclaration);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ClassExpression(path, state) {
|
ClassExpression(path, state) {
|
||||||
// Create a replacement for the class node if there is one. We do one pass to replace classes with
|
// Create a replacement for the class node if there is one. We do one pass to replace classes with
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
export default @dec class A {}
|
||||||
|
@dec class B {}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
var _class, _class2;
|
||||||
|
|
||||||
|
export default dec(_class = class A {}) || _class;
|
||||||
|
|
||||||
|
let B = dec(_class2 = class B {}) || _class2;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export default class A {
|
||||||
|
@dec foo() {}
|
||||||
|
}
|
||||||
|
class B {
|
||||||
|
@dec foo() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
var _class, _class2;
|
||||||
|
|
||||||
|
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object['ke' + 'ys'](descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object['define' + 'Property'](target, property, desc); desc = null; } return desc; }
|
||||||
|
|
||||||
|
let A = (_class2 = class A {
|
||||||
|
foo() {}
|
||||||
|
|
||||||
|
}, (_applyDecoratedDescriptor(_class2.prototype, "foo", [dec], Object.getOwnPropertyDescriptor(_class2.prototype, "foo"), _class2.prototype)), _class2);
|
||||||
|
export { A as default };
|
||||||
|
let B = (_class = class B {
|
||||||
|
foo() {}
|
||||||
|
|
||||||
|
}, (_applyDecoratedDescriptor(_class.prototype, "foo", [dec], Object.getOwnPropertyDescriptor(_class.prototype, "foo"), _class.prototype)), _class);
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export default class A {
|
||||||
|
foo() {}
|
||||||
|
}
|
||||||
|
class B {
|
||||||
|
foo() {}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
export default class A {
|
||||||
|
foo() {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
foo() {}
|
||||||
|
|
||||||
|
}
|
||||||
4
packages/babel-plugin-proposal-decorators/test/fixtures/decl-to-expression/options.json
vendored
Normal file
4
packages/babel-plugin-proposal-decorators/test/fixtures/decl-to-expression/options.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"presets": [],
|
||||||
|
"plugins": ["proposal-decorators"]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user