Sebastian McKenzie ae7d5367f1 6.0.0
I'm extremely stupid and didn't commit as I go. To anyone reading this
I'm extremely sorry. A lot of these changes are very broad and I plan on
releasing Babel 6.0.0 today live on stage at Ember Camp London so I'm
afraid I couldn't wait. If you're ever in London I'll buy you a beer
(or assorted beverage!) to make up for it, also I'll kiss your feet and
give you a back massage, maybe.
2015-10-29 17:51:24 +00:00

107 lines
2.9 KiB
JavaScript

import template from "babel-template";
let buildWrapper = template(`
let CLASS_REF = CLASS;
var CALL_REF = CALL;
var WRAPPER_REF = function (...args) {
if (this instanceof WRAPPER_REF) {
return Reflect.construct(CLASS_REF, args);
} else {
return CALL_REF.apply(this, args);
}
};
WRAPPER_REF.__proto__ = CLASS_REF;
WRAPPER_REF;
`);
let buildSuperWrapper = template(`
let CLASS_REF = CLASS;
var WRAPPER_REF = function (...args) {
if (this instanceof WRAPPER_REF) {
return Reflect.construct(CLASS_REF, args);
} else {
return SUPER_REF.apply(this, args);
}
};
WRAPPER_REF.__proto__ = CLASS_REF;
WRAPPER_REF;
`);
export default function ({ types: t }) {
let ALREADY_VISITED = Symbol();
function findConstructorCall(path): ?Object {
let methods: Array<Object> = path.get("body.body");
for (let method of methods) {
if (method.node.kind === "constructorCall") {
return method;
}
}
return null;
}
function handleClassWithCall(constructorCall, classPath) {
let ref = classPath.node.id || classPath.scope.generateUidIdentifier("class");
classPath.replaceWithMultiple(buildWrapper({
CLASS_REF: classPath.scope.generateUidIdentifier(ref.name),
CALL_REF: classPath.scope.generateUidIdentifier(`${ref.name}Call`),
CALL: t.functionExpression(null, constructorCall.node.params, constructorCall.node.body),
CLASS: t.toExpression(classPath.node),
WRAPPER_REF: ref
}));
constructorCall.remove();
}
function handleClassWithSuper(path) {
// we could be inheriting from a class that has a call handler
let ref = path.node.id || path.scope.generateUidIdentifier("class");
let nodes = [];
let superRef;
// we're going to be duplicating the reference to the super class so memoise it
// if necessary
if (path.get("superClass").isStatic()) {
superRef = path.node.superClass;
} else {
superRef = path.scope.generateUidIdentifier("super");
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(superRef, path.node.superClass)
]));
path.node.superClass = superRef;
}
path.replaceWithMultiple(nodes.concat(buildSuperWrapper({
CLASS_REF: path.scope.generateUidIdentifier(ref.name),
SUPER_REF: superRef,
CLASS: t.toExpression(path.node),
WRAPPER_REF: ref
})));
}
return {
inherits: require("babel-plugin-syntax-class-constructor-call"),
visitor: {
Class(path) {
if (path.node[ALREADY_VISITED]) return;
path.node[ALREADY_VISITED] = true;
let constructorCall = findConstructorCall(path);
if (constructorCall) {
handleClassWithCall(constructorCall, path);
} else if (path.has("superClass")) {
handleClassWithSuper(path);
} else {
return;
}
}
}
};
}