[decorators] Only transform declarations to expressions when needed (#7124)

This commit is contained in:
Nicolò Ribaudo 2018-01-06 16:38:28 +01:00 committed by GitHub
parent bb17b72f4f
commit b93184e430
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 76 additions and 34 deletions

View File

@ -63,11 +63,11 @@ export default function() {
* with the proper decorated behavior.
*/
function applyClassDecorators(classPath) {
if (!hasClassDecorators(classPath.node)) return;
const decorators = classPath.node.decorators || [];
classPath.node.decorators = null;
if (decorators.length === 0) return;
const name = classPath.scope.generateDeclaredUidIdentifier("class");
return decorators
@ -82,30 +82,30 @@ export default function() {
}, classPath.node);
}
function hasClassDecorators(classNode) {
return !!(classNode.decorators && classNode.decorators.length);
}
/**
* Given a class expression with method-level decorators, create a new expression
* with the proper decorated behavior.
*/
function applyMethodDecorators(path, state) {
const hasMethodDecorators = path.node.body.body.some(function(node) {
return (node.decorators || []).length > 0;
});
if (!hasMethodDecorators) return;
if (!hasMethodDecorators(path.node.body.body)) return;
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
* with the proper decorated behavior.
*/
function applyObjectDecorators(path, state) {
const hasMethodDecorators = path.node.properties.some(function(node) {
return (node.decorators || []).length > 0;
});
if (!hasMethodDecorators) return;
if (!hasMethodDecorators(path.node.properties)) return;
return applyTargetDecorators(path, state, path.node.properties);
}
@ -215,32 +215,29 @@ export default function() {
inherits: syntaxDecorators,
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) {
const { node } = path;
const ref = node.id || path.scope.generateUidIdentifier("class");
if (!hasClassDecorators(node) && !hasMethodDecorators(node.body.body)) {
return;
}
path.replaceWith(
t.variableDeclaration("let", [
t.variableDeclarator(ref, t.toExpression(node)),
]),
);
const ref = node.id || path.scope.generateUidIdentifier("class");
const letDeclaration = t.variableDeclaration("let", [
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) {
// Create a replacement for the class node if there is one. We do one pass to replace classes with

View File

@ -0,0 +1,2 @@
export default @dec class A {}
@dec class B {}

View File

@ -0,0 +1,5 @@
var _class, _class2;
export default dec(_class = class A {}) || _class;
let B = dec(_class2 = class B {}) || _class2;

View File

@ -0,0 +1,6 @@
export default class A {
@dec foo() {}
}
class B {
@dec foo() {}
}

View File

@ -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);

View File

@ -0,0 +1,6 @@
export default class A {
foo() {}
}
class B {
foo() {}
}

View File

@ -0,0 +1,9 @@
export default class A {
foo() {}
}
class B {
foo() {}
}

View File

@ -0,0 +1,4 @@
{
"presets": [],
"plugins": ["proposal-decorators"]
}