implement temporal dead zone for default parameters - fixes #169
This commit is contained in:
@@ -1,21 +1,70 @@
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.Function = function (node) {
|
||||
exports.Function = function (node, parent, file, scope) {
|
||||
if (!node.defaults || !node.defaults.length) return;
|
||||
t.ensureBlock(node);
|
||||
|
||||
var ids = node.params.map(function (param) {
|
||||
return t.getIds(param);
|
||||
});
|
||||
|
||||
var closure = false;
|
||||
|
||||
_.each(node.defaults, function (def, i) {
|
||||
if (!def) return;
|
||||
|
||||
var param = node.params[i];
|
||||
|
||||
node.body.body.unshift(util.template("if-undefined-set-to", {
|
||||
VARIABLE: param,
|
||||
DEFAULT: def
|
||||
// temporal dead zone check - here we prevent accessing of params that
|
||||
// are to the right - ie. uninitialized parameters
|
||||
_.each(ids.slice(i), function (ids, i) {
|
||||
var check = function (node, parent) {
|
||||
if (!t.isIdentifier(node) || !t.isReferenced(node, parent)) return;
|
||||
|
||||
if (_.contains(ids, node.name)) {
|
||||
throw file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
|
||||
if (scope.has(node.name)) {
|
||||
closure = true;
|
||||
}
|
||||
};
|
||||
|
||||
check(def, node);
|
||||
traverse(def, check);
|
||||
});
|
||||
|
||||
// we're accessing a variable that's already defined within this function
|
||||
var has = scope.get(param.name);
|
||||
if (has && !_.contains(node.params, has)) {
|
||||
closure = true;
|
||||
}
|
||||
});
|
||||
|
||||
var body = [];
|
||||
|
||||
_.each(node.defaults, function (def, i) {
|
||||
if (!def) return;
|
||||
|
||||
body.push(util.template("if-undefined-set-to", {
|
||||
VARIABLE: node.params[i],
|
||||
DEFAULT: def
|
||||
}, true));
|
||||
});
|
||||
|
||||
if (closure) {
|
||||
var container = t.functionExpression(null, [], node.body, node.generator);
|
||||
container._aliasFunction = true;
|
||||
|
||||
body.push(t.returnStatement(t.callExpression(container, [])));
|
||||
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
|
||||
node.defaults = [];
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
var t = function (t, f) {
|
||||
if (f === undefined) f = 5;
|
||||
if (t === undefined) t = "foo";
|
||||
if (f === undefined) f = 5;
|
||||
return t + " bar " + f;
|
||||
};
|
||||
|
||||
|
||||
1
test/fixtures/transformation/default-parameters/tdz-2/actual.js
vendored
Normal file
1
test/fixtures/transformation/default-parameters/tdz-2/actual.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
function foo(a=b, b) {}
|
||||
3
test/fixtures/transformation/default-parameters/tdz-2/options.json
vendored
Normal file
3
test/fixtures/transformation/default-parameters/tdz-2/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Temporal dead zone - accessing a variable before it's initialized"
|
||||
}
|
||||
4
test/fixtures/transformation/default-parameters/tdz-3/exec.js
vendored
Normal file
4
test/fixtures/transformation/default-parameters/tdz-3/exec.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
assert.equal((function(a, b=a++){
|
||||
function b(){}
|
||||
return a;
|
||||
})(1), 2);
|
||||
1
test/fixtures/transformation/default-parameters/tdz/actual.js
vendored
Normal file
1
test/fixtures/transformation/default-parameters/tdz/actual.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
function foo(a=a) {}
|
||||
3
test/fixtures/transformation/default-parameters/tdz/options.json
vendored
Normal file
3
test/fixtures/transformation/default-parameters/tdz/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Temporal dead zone - accessing a variable before it's initialized"
|
||||
}
|
||||
Reference in New Issue
Block a user