98 lines
2.5 KiB
JavaScript
98 lines
2.5 KiB
JavaScript
"use strict";
|
|
|
|
var traverse = require("../../../traverse");
|
|
var util = require("../../../util");
|
|
var t = require("../../../types");
|
|
|
|
exports.Function = function (node, parent, scope, context, file) {
|
|
if (!node.defaults || !node.defaults.length) return;
|
|
t.ensureBlock(node);
|
|
|
|
var ids = node.params.map(function (param) {
|
|
return t.getIds(param);
|
|
});
|
|
|
|
var iife = false;
|
|
var def;
|
|
|
|
var checkTDZ = function (param, def, ids) {
|
|
var check = function (node, parent) {
|
|
if (!t.isReferencedIdentifier(node, parent)) return;
|
|
|
|
if (ids.indexOf(node.name) >= 0) {
|
|
throw file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
|
}
|
|
|
|
if (scope.has(node.name, true)) {
|
|
iife = true;
|
|
}
|
|
};
|
|
|
|
check(def, node);
|
|
|
|
if (!t.isPattern(param)) {
|
|
traverse(def, { enter: check });
|
|
}
|
|
};
|
|
|
|
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++) {
|
|
checkTDZ(param, def, rightIds[i2]);
|
|
}
|
|
|
|
// 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) {
|
|
iife = true;
|
|
}
|
|
}
|
|
|
|
var body = [];
|
|
|
|
var argsIdentifier = t.identifier("arguments");
|
|
argsIdentifier._ignoreAliasFunctions = true;
|
|
|
|
var lastNonDefaultParam = 0;
|
|
|
|
for (i = 0; i < node.defaults.length; i++) {
|
|
def = node.defaults[i];
|
|
if (!def) {
|
|
lastNonDefaultParam = +i + 1;
|
|
continue;
|
|
}
|
|
|
|
var defNode = util.template("default-parameter", {
|
|
VARIABLE_NAME: node.params[i],
|
|
DEFAULT_VALUE: def,
|
|
ARGUMENT_KEY: t.literal(+i),
|
|
ARGUMENTS: argsIdentifier
|
|
}, true);
|
|
defNode._blockHoist = node.defaults.length - i;
|
|
body.push(defNode);
|
|
}
|
|
|
|
// we need to cut off all trailing default parameters
|
|
node.params = node.params.slice(0, lastNonDefaultParam);
|
|
|
|
if (iife) {
|
|
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 = [];
|
|
};
|