switch rest and default parameters to new ast type
This commit is contained in:
@@ -59,9 +59,6 @@ _.each({
|
||||
"playground.memoizationOperator": require("./transformers/playground/memoization-operator"),
|
||||
"playground.objectGetterMemoization": require("./transformers/playground/object-getter-memoization"),
|
||||
|
||||
asyncToGenerator: require("./transformers/other/async-to-generator"),
|
||||
bluebirdCoroutines: require("./transformers/other/bluebird-coroutines"),
|
||||
|
||||
react: require("./transformers/other/react"),
|
||||
|
||||
// needs to be before `_blockHoist` due to function hoisting etc
|
||||
@@ -76,6 +73,9 @@ _.each({
|
||||
|
||||
"es6.classes": require("./transformers/es6/classes"),
|
||||
|
||||
asyncToGenerator: require("./transformers/other/async-to-generator"),
|
||||
bluebirdCoroutines: require("./transformers/other/bluebird-coroutines"),
|
||||
|
||||
"es7.objectSpread": require("./transformers/es7/object-spread"),
|
||||
"es7.exponentiationOperator": require("./transformers/es7/exponentiation-operator"),
|
||||
"es6.spread": require("./transformers/es6/spread"),
|
||||
|
||||
@@ -253,8 +253,6 @@ Class.prototype.pushConstructor = function (method) {
|
||||
t.inheritsComments(construct, method);
|
||||
|
||||
construct._ignoreUserWhitespace = true;
|
||||
construct.defaults = fn.defaults;
|
||||
construct.params = fn.params;
|
||||
construct.body = fn.body;
|
||||
construct.rest = fn.rest;
|
||||
};
|
||||
|
||||
@@ -4,63 +4,19 @@ var traverse = require("../../../traverse");
|
||||
var util = require("../../../util");
|
||||
var t = require("../../../types");
|
||||
|
||||
function checkTDZ(node, parent, scope, context, state) {
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
if (state.ids.indexOf(node.name) >= 0) {
|
||||
throw state.file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
var hasDefaults = function (node) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
if (t.isAssignmentPattern(node.params[i])) return true;
|
||||
}
|
||||
|
||||
if (scope.has(node.name, true)) {
|
||||
state.iife = true;
|
||||
}
|
||||
}
|
||||
|
||||
var checkTDZVisitor = {
|
||||
enter: checkTDZ
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
if (!node.defaults || !node.defaults.length) return;
|
||||
if (!hasDefaults(node)) return;
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
var ids = node.params.map(function (param) {
|
||||
return t.getIds(param);
|
||||
});
|
||||
|
||||
var def;
|
||||
var state = {
|
||||
file: file,
|
||||
iife: false
|
||||
};
|
||||
|
||||
for (var i = 0; i < node.defaults.length; i++) {
|
||||
def = node.defaults[i];
|
||||
if (!def) continue;
|
||||
|
||||
var param = node.params[i];
|
||||
|
||||
// temporal dead zone check - here we prevent accessing of params that
|
||||
// are to the right - ie. uninitialized parameters
|
||||
var rightIds = ids.slice(i);
|
||||
|
||||
for (var i2 = 0; i2 < rightIds.length; i2++) {
|
||||
state.ids = rightIds[i2];
|
||||
|
||||
checkTDZ(def, node, scope, context, state);
|
||||
|
||||
if (!t.isPattern(param)) {
|
||||
traverse(def, checkTDZVisitor, scope, state);
|
||||
}
|
||||
}
|
||||
|
||||
// we're accessing a variable that's already defined within this function
|
||||
var has = scope.get(param.name, true);
|
||||
if (has && node.params.indexOf(has) < 0) {
|
||||
state.iife = true;
|
||||
}
|
||||
}
|
||||
|
||||
var iife = false;
|
||||
var body = [];
|
||||
|
||||
var argsIdentifier = t.identifier("arguments");
|
||||
@@ -68,27 +24,39 @@ exports.Function = function (node, parent, scope, context, file) {
|
||||
|
||||
var lastNonDefaultParam = 0;
|
||||
|
||||
for (i = 0; i < node.defaults.length; i++) {
|
||||
def = node.defaults[i];
|
||||
if (!def) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
var param = node.params[i];
|
||||
|
||||
if (!t.isAssignmentPattern(param)) {
|
||||
lastNonDefaultParam = +i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.left;
|
||||
var right = param.right;
|
||||
|
||||
node.params[i] = scope.generateUidIdentifier("x")
|
||||
|
||||
// we're accessing a variable that's already defined within this function
|
||||
var localDeclar = scope.get(left.name, true);
|
||||
if (localDeclar !== left) {
|
||||
iife = true;
|
||||
}
|
||||
|
||||
var defNode = util.template("default-parameter", {
|
||||
VARIABLE_NAME: node.params[i],
|
||||
DEFAULT_VALUE: def,
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right,
|
||||
ARGUMENT_KEY: t.literal(+i),
|
||||
ARGUMENTS: argsIdentifier
|
||||
}, true);
|
||||
defNode._blockHoist = node.defaults.length - i;
|
||||
defNode._blockHoist = node.params.length - i;
|
||||
body.push(defNode);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (state.iife) {
|
||||
if (iife) {
|
||||
var container = t.functionExpression(null, [], node.body, node.generator);
|
||||
container._aliasFunction = true;
|
||||
|
||||
@@ -98,6 +66,4 @@ exports.Function = function (node, parent, scope, context, file) {
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
|
||||
node.defaults = [];
|
||||
};
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
var util = require("../../../util");
|
||||
var t = require("../../../types");
|
||||
|
||||
exports.Function = function (node, parent, scope) {
|
||||
if (!node.rest) return;
|
||||
var hasRest = function (node) {
|
||||
return t.isRestElement(node.params[node.params.length - 1]);
|
||||
};
|
||||
|
||||
var rest = node.rest;
|
||||
node.rest = null;
|
||||
exports.Function = function (node, parent, scope) {
|
||||
if (!hasRest(node)) return;
|
||||
|
||||
var rest = node.params.pop().argument;
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
|
||||
@@ -250,7 +250,6 @@ Scope.prototype.getInfo = function () {
|
||||
// Function - params, rest
|
||||
|
||||
if (t.isFunction(block)) {
|
||||
if (block.rest) add(block.rest);
|
||||
_.each(block.params, function (param) {
|
||||
add(param);
|
||||
});
|
||||
|
||||
@@ -237,8 +237,14 @@ t.isReferenced = function (node, parent) {
|
||||
// we're a function param
|
||||
if (_.contains(parent.params, node)) return false;
|
||||
|
||||
// we're a rest parameter
|
||||
if (parent.rest === node) return false;
|
||||
for (var i = 0; i < parent.params.length; i++) {
|
||||
var param = parent.params[i];
|
||||
if (param === node) {
|
||||
return false;
|
||||
} else if (t.isRestElement(param) && param.argument === node) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isMethodDefinition(parent) && parent.key === node && !parent.computed) {
|
||||
|
||||
Reference in New Issue
Block a user