Added spec arrow transformer.

Enforces:
* `new arrowFn(...)` is disallowed;
* `arrowFn.prototype` does not exist.
This commit is contained in:
Ingvar Stepanyan 2015-06-09 18:18:44 +03:00
parent eaaa279aa5
commit 15ae0b669b
10 changed files with 75 additions and 6 deletions

View File

@ -85,6 +85,7 @@ export default class File {
"get",
"set",
"class-call-check",
"new-arrow-check",
"object-destructuring-empty",
"temporal-undefined",
"temporal-assert-defined",

View File

@ -0,0 +1,5 @@
(function (instance, arrowFn) {
if (instance instanceof arrowFn) {
throw new TypeError("Cannot instantiate an arrow function");
}
});

View File

@ -5,5 +5,5 @@ export function ArrowFunctionExpression(node) {
node.expression = false;
node.type = "FunctionExpression";
node.shadow = true;
node.shadow = node.shadow || true;
}

View File

@ -0,0 +1,26 @@
import * as t from "../../../types";
export var metadata = {
optional: true
};
export function ArrowFunctionExpression(node, parent, scope, file) {
if (node.shadow) return;
node.shadow = { this: false };
var {id} = node;
var expr = node;
if (!id) {
id = scope.parent.generateDeclaredUidIdentifier("arrow");
expr = t.assignmentExpression("=", id, expr);
}
// make sure that arrow function won't be instantiated
t.ensureBlock(node).body.unshift(t.expressionStatement(t.callExpression(file.addHelper("new-arrow-check"), [
t.thisExpression(),
id
])));
return t.callExpression(t.memberExpression(expr, t.identifier("bind")), [t.thisExpression()]);
}

View File

@ -26,6 +26,7 @@ export default {
"es7.decorators": require("./es7/decorators"),
"validation.undeclaredVariableCheck": require("./validation/undeclared-variable-check"),
"validation.react": require("./validation/react"),
"es6.spec.arrowFunctions": require("./es6/spec.arrow-functions"),
"es6.arrowFunctions": require("./es6/arrow-functions"),
"spec.blockScopedFunctions": require("./spec/block-scoped-functions"),
"optimisation.react.constantElements": require("./optimisation/react.constant-elements"),

View File

@ -6,7 +6,7 @@ export var metadata = {
function remap(path, key, create) {
// ensure that we're shadowed
if (!path.inShadow()) return;
if (!path.inShadow(key)) return;
var fnPath = path.findParent((path) => !path.is("shadow") && (path.isFunction() || path.isProgram()));
@ -22,8 +22,10 @@ function remap(path, key, create) {
return id;
}
export function ThisExpression() {
return remap(this, "this", () => t.thisExpression());
export function ThisExpression(node) {
if (!node._shadowedFunctionLiteral) {
return remap(this, "this", () => t.thisExpression());
}
}
export function ReferencedIdentifier(node) {

View File

@ -62,11 +62,12 @@ export function inType(types) {
* Description
*/
export function inShadow() {
export function inShadow(key) {
var path = this;
while (path) {
if (path.isFunction()) {
if (path.node.shadow) {
var {shadow} = path.node;
if (shadow && (shadow === true || shadow[key] !== false)) {
return path;
} else {
return null;

View File

@ -0,0 +1,5 @@
arr.map(x => x * x);
var f = (x, y) => x * y;
(function () {
return () => this;
})();

View File

@ -0,0 +1,25 @@
"use strict";
var _arrow;
function _newArrowCheck(instance, arrowFn) { if (instance instanceof arrowFn) { throw new TypeError("Cannot instantiate an arrow function"); } }
arr.map((_arrow = function (x) {
_newArrowCheck(this, _arrow);
return x * x;
}).bind(this));
var f = (function f(x, y) {
_newArrowCheck(this, f);
return x * y;
}).bind(this);
(function () {
var _arrow2;
return (_arrow2 = function () {
_newArrowCheck(this, _arrow2);
return this;
}).bind(this);
})();

View File

@ -0,0 +1,3 @@
{
"optional": ["es6.spec.arrowFunctions"]
}