Extract traversers outside methods
This commit is contained in:
parent
cfd028288f
commit
3d9d842a0d
@ -3,19 +3,21 @@
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
var traverser = {
|
||||
enter: function (node, parent, scope, context) {
|
||||
if (t.isFunction(node)) context.skip();
|
||||
|
||||
if (t.isAwaitExpression(node)) {
|
||||
node.type = "YieldExpression";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function (node, callId) {
|
||||
node.async = false;
|
||||
node.generator = true;
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node, parent, scope, context) {
|
||||
if (t.isFunction(node)) context.skip();
|
||||
|
||||
if (t.isAwaitExpression(node)) {
|
||||
node.type = "YieldExpression";
|
||||
}
|
||||
}
|
||||
});
|
||||
traverse(node, traverser);
|
||||
|
||||
var call = t.callExpression(callId, [node]);
|
||||
|
||||
|
||||
@ -103,6 +103,34 @@ ReplaceSupers.prototype.replace = function () {
|
||||
this.traverseLevel(this.methodNode.value, true);
|
||||
};
|
||||
|
||||
var traverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
var topLevel = state.topLevel;
|
||||
var self = state.self;
|
||||
|
||||
if (t.isFunction(node) && !t.isArrowFunctionExpression(node)) {
|
||||
// we need to call traverseLevel again so we're context aware
|
||||
self.traverseLevel(node, false);
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (t.isProperty(node, { method: true }) || t.isMethodDefinition(node)) {
|
||||
// break on object methods
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
var getThisReference = topLevel ?
|
||||
// top level so `this` is the instance
|
||||
t.thisExpression :
|
||||
// not in the top level so we need to create a reference
|
||||
self.getThisReference;
|
||||
|
||||
var callback = self.specHandle;
|
||||
if (self.isLoose) callback = self.looseHandle;
|
||||
return callback.call(self, getThisReference, node, parent);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
@ -111,36 +139,8 @@ ReplaceSupers.prototype.replace = function () {
|
||||
*/
|
||||
|
||||
ReplaceSupers.prototype.traverseLevel = function (node, topLevel) {
|
||||
var self = this;
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node, parent, scope, context) {
|
||||
if (t.isFunction(node) && !t.isArrowFunctionExpression(node)) {
|
||||
// we need to call traverseLevel again so we're context aware
|
||||
self.traverseLevel(node, false);
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (t.isProperty(node, { method: true }) || t.isMethodDefinition(node)) {
|
||||
// break on object methods
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
var getThisReference = function () {
|
||||
if (topLevel) {
|
||||
// top level so `this` is the instance
|
||||
return t.thisExpression();
|
||||
} else {
|
||||
// not in the top level so we need to create a reference
|
||||
return self.getThisReference();
|
||||
}
|
||||
};
|
||||
|
||||
var callback = self.specHandle;
|
||||
if (self.isLoose) callback = self.looseHandle;
|
||||
return callback.call(self, getThisReference, node, parent);
|
||||
}
|
||||
});
|
||||
var state = { self: this, topLevel: topLevel };
|
||||
traverse(node, traverser, null, state);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -47,8 +47,21 @@ DefaultFormatter.prototype.getLocalImports = function () {
|
||||
return localImports;
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.isLocalReference = function (node) {
|
||||
var localImports = this.localImports;
|
||||
return t.isIdentifier(node) && _.has(localImports, node.name) && localImports[node.name] !== node;
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.checkLocalReference = function (node) {
|
||||
var file = this.file;
|
||||
if (this.isLocalReference(node)) {
|
||||
throw file.errorWithNode(node, "Illegal assignment of module import");
|
||||
}
|
||||
};
|
||||
|
||||
var collissionsTraverser = {
|
||||
enter: function (node, parent, scope, context, check) {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
var self = state.self;
|
||||
if (t.isAssignmentExpression(node)) {
|
||||
|
||||
var left = node.left;
|
||||
@ -56,30 +69,17 @@ var collissionsTraverser = {
|
||||
while (left.object) left = left.object;
|
||||
}
|
||||
|
||||
check(left);
|
||||
self.checkLocalReference(left);
|
||||
} else if (t.isDeclaration(node)) {
|
||||
_.each(t.getIds(node, true), check);
|
||||
_.each(t.getIds(node, true), self.checkLocalReference);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.checkCollisions = function () {
|
||||
// todo: all check export collissions
|
||||
|
||||
var localImports = this.localImports;
|
||||
var file = this.file;
|
||||
|
||||
var isLocalReference = function (node) {
|
||||
return t.isIdentifier(node) && _.has(localImports, node.name) && localImports[node.name] !== node;
|
||||
};
|
||||
|
||||
var check = function (node) {
|
||||
if (isLocalReference(node)) {
|
||||
throw file.errorWithNode(node, "Illegal assignment of module import");
|
||||
}
|
||||
};
|
||||
|
||||
traverse(file.ast, collissionsTraverser, null, check);
|
||||
var state = { self: this };
|
||||
traverse(this.file.ast, collissionsTraverser, null, state);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.remapExportAssignment = function (node) {
|
||||
@ -94,51 +94,53 @@ DefaultFormatter.prototype.remapExportAssignment = function (node) {
|
||||
);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.remapAssignments = function () {
|
||||
DefaultFormatter.prototype.isLocalReference = function (node, scope) {
|
||||
var localExports = this.localExports;
|
||||
var self = this;
|
||||
var name = node.name;
|
||||
return t.isIdentifier(node) && localExports[name] && localExports[name] === scope.get(name, true);
|
||||
};
|
||||
|
||||
var isLocalReference = function (node, scope) {
|
||||
var name = node.name;
|
||||
return t.isIdentifier(node) && localExports[name] && localExports[name] === scope.get(name, true);
|
||||
};
|
||||
var remapTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
var self = state.self;
|
||||
if (t.isUpdateExpression(node) && self.isLocalReference(node.argument, scope)) {
|
||||
context.skip();
|
||||
|
||||
traverse(this.file.ast, {
|
||||
enter: function (node, parent, scope, context, isLocalReference) {
|
||||
if (t.isUpdateExpression(node) && isLocalReference(node.argument, scope)) {
|
||||
context.skip();
|
||||
// expand to long file assignment expression
|
||||
var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1));
|
||||
|
||||
// expand to long file assignment expression
|
||||
var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1));
|
||||
// remap this assignment expression
|
||||
var remapped = self.remapExportAssignment(assign);
|
||||
|
||||
// remap this assignment expression
|
||||
var remapped = self.remapExportAssignment(assign);
|
||||
|
||||
// we don't need to change the result
|
||||
if (t.isExpressionStatement(parent) || node.prefix) {
|
||||
return remapped;
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
nodes.push(remapped);
|
||||
|
||||
var operator;
|
||||
if (node.operator === "--") {
|
||||
operator = "+";
|
||||
} else { // "++"
|
||||
operator = "-";
|
||||
}
|
||||
nodes.push(t.binaryExpression(operator, node.argument, t.literal(1)));
|
||||
|
||||
return t.sequenceExpression(nodes);
|
||||
// we don't need to change the result
|
||||
if (t.isExpressionStatement(parent) || node.prefix) {
|
||||
return remapped;
|
||||
}
|
||||
|
||||
if (t.isAssignmentExpression(node) && isLocalReference(node.left, scope)) {
|
||||
context.skip();
|
||||
return self.remapExportAssignment(node);
|
||||
var nodes = [];
|
||||
nodes.push(remapped);
|
||||
|
||||
var operator;
|
||||
if (node.operator === "--") {
|
||||
operator = "+";
|
||||
} else { // "++"
|
||||
operator = "-";
|
||||
}
|
||||
nodes.push(t.binaryExpression(operator, node.argument, t.literal(1)));
|
||||
|
||||
return t.sequenceExpression(nodes);
|
||||
}
|
||||
}, null, isLocalReference);
|
||||
|
||||
if (t.isAssignmentExpression(node) && self.isLocalReference(node.left, scope)) {
|
||||
context.skip();
|
||||
return self.remapExportAssignment(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.remapAssignments = function () {
|
||||
var state = { self: this };
|
||||
traverse(this.file.ast, remapTraverser, null, state);
|
||||
};
|
||||
|
||||
DefaultFormatter.prototype.getModuleName = function () {
|
||||
|
||||
@ -8,16 +8,19 @@ var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var traverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isExportDeclaration(node) && !node.default) state.hasNonDefaultExports = true;
|
||||
}
|
||||
};
|
||||
|
||||
function CommonJSFormatter(file) {
|
||||
DefaultFormatter.apply(this, arguments);
|
||||
|
||||
var hasNonDefaultExports = false;
|
||||
traverse(file.ast, {
|
||||
enter: function (node) {
|
||||
if (t.isExportDeclaration(node) && !node.default) hasNonDefaultExports = true;
|
||||
}
|
||||
});
|
||||
this.hasNonDefaultExports = hasNonDefaultExports;
|
||||
var state = { hasNonDefaultExports: false };
|
||||
traverse(file.ast, traverser, null, state);
|
||||
|
||||
this.hasNonDefaultExports = state.hasNonDefaultExports;
|
||||
}
|
||||
|
||||
util.inherits(CommonJSFormatter, DefaultFormatter);
|
||||
|
||||
@ -63,36 +63,91 @@ SystemFormatter.prototype.importSpecifier = function (specifier, node, nodes) {
|
||||
this._addImportSource(_.last(nodes), node);
|
||||
};
|
||||
|
||||
var runnerSettersTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (node._importSource === state.source) {
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
_.each(node.declarations, function (declar) {
|
||||
state.hoistDeclarators.push(t.variableDeclarator(declar.id));
|
||||
state.nodes.push(t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.id, declar.init)
|
||||
));
|
||||
});
|
||||
} else {
|
||||
state.nodes.push(node);
|
||||
}
|
||||
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.buildRunnerSetters = function (block, hoistDeclarators) {
|
||||
return t.arrayExpression(_.map(this.ids, function (uid, source) {
|
||||
var state = {
|
||||
nodes: [],
|
||||
source: source,
|
||||
nodes: [],
|
||||
hoistDeclarators: hoistDeclarators
|
||||
};
|
||||
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (node._importSource === source) {
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
_.each(node.declarations, function (declar) {
|
||||
state.hoistDeclarators.push(t.variableDeclarator(declar.id));
|
||||
state.nodes.push(t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.id, declar.init)
|
||||
));
|
||||
});
|
||||
} else {
|
||||
state.nodes.push(node);
|
||||
}
|
||||
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
}, null, state);
|
||||
traverse(block, runnerSettersTraverser, null, state);
|
||||
|
||||
return t.functionExpression(null, [uid], t.blockStatement(state.nodes));
|
||||
}));
|
||||
};
|
||||
|
||||
var hoistVariablesTraverser = {
|
||||
enter: function (node, parent, scope, context, hoistDeclarators) {
|
||||
if (t.isFunction(node)) {
|
||||
// nothing inside is accessible
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
if (node.kind !== "var" && !t.isProgram(parent)) { // let, const
|
||||
// can't be accessed
|
||||
return;
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
|
||||
_.each(node.declarations, function (declar) {
|
||||
hoistDeclarators.push(t.variableDeclarator(declar.id));
|
||||
if (declar.init) {
|
||||
// no initializer so we can just hoist it as-is
|
||||
var assign = t.expressionStatement(t.assignmentExpression("=", declar.id, declar.init));
|
||||
nodes.push(assign);
|
||||
}
|
||||
});
|
||||
|
||||
// for (var i in test)
|
||||
// for (var i = 0;;)
|
||||
if (t.isFor(parent)) {
|
||||
if (parent.left === node) {
|
||||
return node.declarations[0].id;
|
||||
}
|
||||
|
||||
if (parent.init === node) {
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var hoistFunctionsTraverser = {
|
||||
enter: function (node, parent, scope, context, handlerBody) {
|
||||
if (t.isFunction(node)) context.skip();
|
||||
|
||||
if (t.isFunctionDeclaration(node) || node._blockHoist) {
|
||||
handlerBody.push(node);
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SystemFormatter.prototype.transform = function (ast) {
|
||||
var program = ast.program;
|
||||
|
||||
@ -116,46 +171,7 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
var returnStatement = handlerBody.pop();
|
||||
|
||||
// hoist up all variable declarations
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope, context, hoistDeclarators) {
|
||||
if (t.isFunction(node)) {
|
||||
// nothing inside is accessible
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
if (node.kind !== "var" && !t.isProgram(parent)) { // let, const
|
||||
// can't be accessed
|
||||
return;
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
|
||||
_.each(node.declarations, function (declar) {
|
||||
hoistDeclarators.push(t.variableDeclarator(declar.id));
|
||||
if (declar.init) {
|
||||
// no initializer so we can just hoist it as-is
|
||||
var assign = t.expressionStatement(t.assignmentExpression("=", declar.id, declar.init));
|
||||
nodes.push(assign);
|
||||
}
|
||||
});
|
||||
|
||||
// for (var i in test)
|
||||
// for (var i = 0;;)
|
||||
if (t.isFor(parent)) {
|
||||
if (parent.left === node) {
|
||||
return node.declarations[0].id;
|
||||
}
|
||||
|
||||
if (parent.init === node) {
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}, null, hoistDeclarators);
|
||||
traverse(block, hoistVariablesTraverser, null, hoistDeclarators);
|
||||
|
||||
if (hoistDeclarators.length) {
|
||||
var hoistDeclar = t.variableDeclaration("var", hoistDeclarators);
|
||||
@ -164,16 +180,7 @@ SystemFormatter.prototype.transform = function (ast) {
|
||||
}
|
||||
|
||||
// hoist up function declarations for circular references
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope, context, handlerBody) {
|
||||
if (t.isFunction(node)) context.skip();
|
||||
|
||||
if (t.isFunctionDeclaration(node) || node._blockHoist) {
|
||||
handlerBody.push(node);
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
}, null, handlerBody);
|
||||
traverse(block, hoistFunctionsTraverser, null, handlerBody);
|
||||
|
||||
handlerBody.push(returnStatement);
|
||||
|
||||
|
||||
@ -6,25 +6,6 @@ var traverse = require("../traverse");
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function noop() { }
|
||||
|
||||
function enter(node, parent, scope, context, args) {
|
||||
var fns = args[1][node.type];
|
||||
if (!fns) return;
|
||||
return fns.enter(node, parent, scope, context, args[0]);
|
||||
}
|
||||
|
||||
function exit(node, parent, scope, context, args) {
|
||||
var fns = args[1][node.type];
|
||||
if (!fns) return;
|
||||
return fns.exit(node, parent, scope, context, args[0]);
|
||||
}
|
||||
|
||||
var traverseOpts = {
|
||||
enter: enter,
|
||||
exit: exit
|
||||
};
|
||||
|
||||
function Transformer(key, transformer, opts) {
|
||||
this.manipulateOptions = transformer.manipulateOptions;
|
||||
this.experimental = !!transformer.experimental;
|
||||
@ -53,8 +34,8 @@ Transformer.prototype.normalise = function (transformer) {
|
||||
|
||||
if (!_.isObject(fns)) return;
|
||||
|
||||
if (!fns.enter) fns.enter = noop;
|
||||
if (!fns.exit) fns.exit = noop;
|
||||
if (!fns.enter) fns.enter = _.noop;
|
||||
if (!fns.exit) fns.exit = _.noop;
|
||||
|
||||
transformer[type] = fns;
|
||||
|
||||
@ -77,9 +58,26 @@ Transformer.prototype.astRun = function (file, key) {
|
||||
}
|
||||
};
|
||||
|
||||
var transformTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
var fns = state.transformer[node.type];
|
||||
if (!fns) return;
|
||||
return fns.enter(node, parent, scope, context, state.file);
|
||||
},
|
||||
|
||||
exit: function (node, parent, scope, context, state) {
|
||||
var fns = state.transformer[node.type];
|
||||
if (!fns) return;
|
||||
return fns.exit(node, parent, scope, context, state.file);
|
||||
}
|
||||
};
|
||||
|
||||
Transformer.prototype.transform = function (file) {
|
||||
this.astRun(file, "before");
|
||||
traverse(file.ast, traverseOpts, null, [file, this.transformer]);
|
||||
|
||||
var state = { file: file, transformer: this.transformer };
|
||||
traverse(file.ast, transformTraverser, null, state);
|
||||
|
||||
this.astRun(file, "after");
|
||||
};
|
||||
|
||||
|
||||
@ -4,6 +4,17 @@ var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var traverser = {
|
||||
enter: function (child, parent, scope, context, state) {
|
||||
if (child._ignoreConstant) return;
|
||||
if (t.isVariableDeclaration(child)) return;
|
||||
|
||||
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
|
||||
state.check(parent, state.getIds(child), scope);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.Program =
|
||||
exports.BlockStatement =
|
||||
exports.ForInStatement =
|
||||
@ -71,19 +82,6 @@ exports.ForStatement = function (node, parent, scope, context, file) {
|
||||
|
||||
if (!hasConstants) return;
|
||||
|
||||
var state = {
|
||||
check: check,
|
||||
getIds: getIds
|
||||
};
|
||||
|
||||
traverse(node, {
|
||||
enter: function (child, parent, scope, context, state) {
|
||||
if (child._ignoreConstant) return;
|
||||
if (t.isVariableDeclaration(child)) return;
|
||||
|
||||
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
|
||||
state.check(parent, state.getIds(child), scope);
|
||||
}
|
||||
}
|
||||
}, null, state);
|
||||
var state = { check: check, getIds: getIds };
|
||||
traverse(node, traverser, null, state);
|
||||
};
|
||||
|
||||
@ -4,6 +4,22 @@ 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");
|
||||
}
|
||||
|
||||
if (scope.has(node.name, true)) {
|
||||
state.iife = true;
|
||||
}
|
||||
}
|
||||
|
||||
var checkTDZTraverser = {
|
||||
enter: checkTDZ
|
||||
};
|
||||
|
||||
exports.Function = function (node, parent, scope, context, file) {
|
||||
if (!node.defaults || !node.defaults.length) return;
|
||||
t.ensureBlock(node);
|
||||
@ -12,27 +28,10 @@ exports.Function = function (node, parent, scope, context, file) {
|
||||
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 });
|
||||
}
|
||||
var state = {
|
||||
file: file,
|
||||
iife: false
|
||||
};
|
||||
|
||||
for (var i = 0; i < node.defaults.length; i++) {
|
||||
@ -44,14 +43,21 @@ exports.Function = function (node, parent, scope, context, file) {
|
||||
// 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]);
|
||||
state.ids = rightIds[i2];
|
||||
|
||||
checkTDZ(def, node, scope, context, state);
|
||||
|
||||
if (!t.isPattern(param)) {
|
||||
traverse(def, checkTDZTraverser, 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) {
|
||||
iife = true;
|
||||
state.iife = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +88,7 @@ exports.Function = function (node, parent, scope, context, file) {
|
||||
// we need to cut off all trailing default parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (iife) {
|
||||
if (state.iife) {
|
||||
var container = t.functionExpression(null, [], node.body, node.generator);
|
||||
container._aliasFunction = true;
|
||||
|
||||
|
||||
@ -112,6 +112,31 @@ LetScoping.prototype.run = function () {
|
||||
}
|
||||
};
|
||||
|
||||
function replace(node, parent, scope, context, remaps) {
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
var remap = remaps[node.name];
|
||||
if (!remap) return;
|
||||
|
||||
var own = scope.get(node.name, true);
|
||||
if (own === remap.node) {
|
||||
node.name = remap.uid;
|
||||
} else {
|
||||
// scope already has it's own declaration that doesn't
|
||||
// match the one we have a stored replacement for
|
||||
if (context) context.skip();
|
||||
}
|
||||
}
|
||||
|
||||
var replaceTraverser = {
|
||||
enter: replace
|
||||
};
|
||||
|
||||
function traverseReplace(node, parent, scope, remaps) {
|
||||
replace(node, parent, scope, null, remaps);
|
||||
traverse(node, replaceTraverser, scope, remaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
@ -149,35 +174,14 @@ LetScoping.prototype.remap = function () {
|
||||
|
||||
//
|
||||
|
||||
var replace = function (node, parent, scope, context, remaps) {
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
var remap = remaps[node.name];
|
||||
if (!remap) return;
|
||||
|
||||
var own = scope.get(node.name, true);
|
||||
if (own === remap.node) {
|
||||
node.name = remap.uid;
|
||||
} else {
|
||||
// scope already has it's own declaration that doesn't
|
||||
// match the one we have a stored replacement for
|
||||
if (context) context.skip();
|
||||
}
|
||||
};
|
||||
|
||||
var traverseReplace = function (node, parent) {
|
||||
replace(node, parent, scope, null, remaps);
|
||||
traverse(node, { enter: replace }, scope, remaps);
|
||||
};
|
||||
|
||||
var loopParent = this.loopParent;
|
||||
if (loopParent) {
|
||||
traverseReplace(loopParent.right, loopParent);
|
||||
traverseReplace(loopParent.test, loopParent);
|
||||
traverseReplace(loopParent.update, loopParent);
|
||||
traverseReplace(loopParent.right, loopParent, scope, remaps);
|
||||
traverseReplace(loopParent.test, loopParent, scope, remaps);
|
||||
traverseReplace(loopParent.update, loopParent, scope, remaps);
|
||||
}
|
||||
|
||||
traverse(this.block, { enter: replace }, scope, remaps);
|
||||
traverse(this.block, replaceTraverser, scope, remaps);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -217,6 +221,31 @@ LetScoping.prototype.needsClosure = function () {
|
||||
this.build(ret, call);
|
||||
};
|
||||
|
||||
var letReferenceFunctionTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
// not a direct reference
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
// this scope has a variable with the same name so it couldn't belong
|
||||
// to our let scope
|
||||
if (scope.hasOwn(node.name, true)) return;
|
||||
|
||||
// not a part of our scope
|
||||
if (!state.letReferences[node.name]) return;
|
||||
|
||||
state.closurify = true;
|
||||
}
|
||||
};
|
||||
|
||||
var letReferenceBlockTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, letReferenceFunctionTraverser, scope, state);
|
||||
return context.skip();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
@ -264,33 +293,42 @@ LetScoping.prototype.getLetReferences = function () {
|
||||
|
||||
// traverse through this block, stopping on functions and checking if they
|
||||
// contain any local let references
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
// not a direct reference
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
// this scope has a variable with the same name so it couldn't belong
|
||||
// to our let scope
|
||||
if (scope.hasOwn(node.name, true)) return;
|
||||
|
||||
// not a part of our scope
|
||||
if (!state.letReferences[node.name]) return;
|
||||
|
||||
state.closurify = true;
|
||||
}
|
||||
}, scope, state);
|
||||
|
||||
return context.skip();
|
||||
}
|
||||
}
|
||||
}, this.scope, state);
|
||||
traverse(this.block, letReferenceBlockTraverser, this.scope, state);
|
||||
|
||||
return state.closurify;
|
||||
};
|
||||
|
||||
var loopTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
var replace;
|
||||
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return context.skip();
|
||||
}
|
||||
|
||||
if (node && !node.label) {
|
||||
if (t.isBreakStatement(node)) {
|
||||
if (t.isSwitchCase(parent)) return;
|
||||
|
||||
state.hasBreak = true;
|
||||
replace = t.returnStatement(t.literal("break"));
|
||||
} else if (t.isContinueStatement(node)) {
|
||||
state.hasContinue = true;
|
||||
replace = t.returnStatement(t.literal("continue"));
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isReturnStatement(node)) {
|
||||
state.hasReturn = true;
|
||||
replace = t.returnStatement(t.objectExpression([
|
||||
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
|
||||
]));
|
||||
}
|
||||
|
||||
if (replace) return t.inherits(replace, node);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If we're inside of a loop then traverse it and check if it has one of
|
||||
* the following node types `ReturnStatement`, `BreakStatement`,
|
||||
@ -301,44 +339,32 @@ LetScoping.prototype.getLetReferences = function () {
|
||||
*/
|
||||
|
||||
LetScoping.prototype.checkLoop = function () {
|
||||
var has = {
|
||||
var state = {
|
||||
hasContinue: false,
|
||||
hasReturn: false,
|
||||
hasBreak: false,
|
||||
};
|
||||
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent, scope, context) {
|
||||
var replace;
|
||||
traverse(this.block, loopTraverser, this.scope, state);
|
||||
return state;
|
||||
};
|
||||
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return context.skip();
|
||||
var hoistVarDeclarationsTraverser = {
|
||||
enter: function (node, parent, scope, context, self) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init, node)) {
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
}
|
||||
|
||||
if (node && !node.label) {
|
||||
if (t.isBreakStatement(node)) {
|
||||
if (t.isSwitchCase(parent)) return;
|
||||
|
||||
has.hasBreak = true;
|
||||
replace = t.returnStatement(t.literal("break"));
|
||||
} else if (t.isContinueStatement(node)) {
|
||||
has.hasContinue = true;
|
||||
replace = t.returnStatement(t.literal("continue"));
|
||||
}
|
||||
} else if (t.isFor(node)) {
|
||||
if (isVar(node.left, node)) {
|
||||
node.left = node.left.declarations[0].id;
|
||||
}
|
||||
|
||||
if (t.isReturnStatement(node)) {
|
||||
has.hasReturn = true;
|
||||
replace = t.returnStatement(t.objectExpression([
|
||||
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
|
||||
]));
|
||||
}
|
||||
|
||||
if (replace) return t.inherits(replace, node);
|
||||
} else if (isVar(node, parent)) {
|
||||
return self.pushDeclar(node).map(t.expressionStatement);
|
||||
} else if (t.isFunction(node)) {
|
||||
return context.skip();
|
||||
}
|
||||
}, this.scope, has);
|
||||
|
||||
return has;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -347,23 +373,7 @@ LetScoping.prototype.checkLoop = function () {
|
||||
*/
|
||||
|
||||
LetScoping.prototype.hoistVarDeclarations = function () {
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent, scope, context, self) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init, node)) {
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
}
|
||||
} else if (t.isFor(node)) {
|
||||
if (isVar(node.left, node)) {
|
||||
node.left = node.left.declarations[0].id;
|
||||
}
|
||||
} else if (isVar(node, parent)) {
|
||||
return self.pushDeclar(node).map(t.expressionStatement);
|
||||
} else if (t.isFunction(node)) {
|
||||
return context.skip();
|
||||
}
|
||||
}
|
||||
}, this.scope, this);
|
||||
traverse(this.block, hoistVarDeclarationsTraverser, this.scope, this);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -1,6 +1,36 @@
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
var traverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
var declared = state.letRefs[node.name];
|
||||
if (!declared) return;
|
||||
|
||||
// declared node is different in this scope
|
||||
if (scope.get(node.name, true) !== declared) return;
|
||||
|
||||
var declaredLoc = declared.loc;
|
||||
var referenceLoc = node.loc;
|
||||
|
||||
if (!declaredLoc || !referenceLoc) return;
|
||||
|
||||
// does this reference appear on a line before the declaration?
|
||||
var before = referenceLoc.start.line < declaredLoc.start.line;
|
||||
|
||||
if (referenceLoc.start.line === declaredLoc.start.line) {
|
||||
// this reference appears on the same line
|
||||
// check it appears before the declaration
|
||||
before = referenceLoc.start.col < declaredLoc.start.col;
|
||||
}
|
||||
|
||||
if (before) {
|
||||
throw state.file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.optional = true;
|
||||
|
||||
exports.Loop =
|
||||
@ -11,36 +41,8 @@ exports.BlockStatement = function (node, parent, scope, context, file) {
|
||||
|
||||
var state = {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
file: file
|
||||
};
|
||||
|
||||
traverse(node, {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (!t.isReferencedIdentifier(node, parent)) return;
|
||||
|
||||
var declared = state.letRefs[node.name];
|
||||
if (!declared) return;
|
||||
|
||||
// declared node is different in this scope
|
||||
if (scope.get(node.name, true) !== declared) return;
|
||||
|
||||
var declaredLoc = declared.loc;
|
||||
var referenceLoc = node.loc;
|
||||
|
||||
if (!declaredLoc || !referenceLoc) return;
|
||||
|
||||
// does this reference appear on a line before the declaration?
|
||||
var before = referenceLoc.start.line < declaredLoc.start.line;
|
||||
|
||||
if (referenceLoc.start.line === declaredLoc.start.line) {
|
||||
// this reference appears on the same line
|
||||
// check it appears before the declaration
|
||||
before = referenceLoc.start.col < declaredLoc.start.col;
|
||||
}
|
||||
|
||||
if (before) {
|
||||
throw state.file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
}
|
||||
}, scope, state);
|
||||
traverse(node, traverser, scope, state);
|
||||
};
|
||||
|
||||
@ -19,6 +19,45 @@ var ALIASABLE_CONSTRUCTORS = [
|
||||
"WeakSet"
|
||||
];
|
||||
|
||||
var astTraverser = {
|
||||
enter: function (node, parent, scope, context, file) {
|
||||
var prop;
|
||||
|
||||
if (t.isMemberExpression(node) && t.isReferenced(node, parent)) {
|
||||
// Array.from -> _core.Array.from
|
||||
var obj = node.object;
|
||||
prop = node.property;
|
||||
|
||||
if (!t.isReferenced(obj, node)) return;
|
||||
|
||||
if (!node.computed && coreHas(obj) && _.has(core[obj.name], prop.name)) {
|
||||
context.skip();
|
||||
return t.prependToMemberExpression(node, file.get("coreIdentifier"));
|
||||
}
|
||||
} else if (t.isReferencedIdentifier(node, parent) && !t.isMemberExpression(parent) && _.contains(ALIASABLE_CONSTRUCTORS, node.name)) {
|
||||
// Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
|
||||
return t.memberExpression(file.get("coreIdentifier"), node);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
// arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
|
||||
|
||||
if (node.arguments.length) return;
|
||||
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!callee.computed) return;
|
||||
|
||||
prop = callee.property;
|
||||
if (!t.isIdentifier(prop.object, { name: "Symbol" })) return;
|
||||
if (!t.isIdentifier(prop.property, { name: "iterator" })) return;
|
||||
|
||||
return util.template("corejs-iterator", {
|
||||
CORE_ID: file.get("coreIdentifier"),
|
||||
VALUE: callee.object
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.optional = true;
|
||||
|
||||
exports.ast = {
|
||||
@ -29,44 +68,7 @@ exports.ast = {
|
||||
},
|
||||
|
||||
exit: function (ast, file) {
|
||||
traverse(ast, {
|
||||
enter: function (node, parent, scope, context) {
|
||||
var prop;
|
||||
|
||||
if (t.isMemberExpression(node) && t.isReferenced(node, parent)) {
|
||||
// Array.from -> _core.Array.from
|
||||
var obj = node.object;
|
||||
prop = node.property;
|
||||
|
||||
if (!t.isReferenced(obj, node)) return;
|
||||
|
||||
if (!node.computed && coreHas(obj) && _.has(core[obj.name], prop.name)) {
|
||||
context.skip();
|
||||
return t.prependToMemberExpression(node, file.get("coreIdentifier"));
|
||||
}
|
||||
} else if (t.isReferencedIdentifier(node, parent) && !t.isMemberExpression(parent) && _.contains(ALIASABLE_CONSTRUCTORS, node.name)) {
|
||||
// Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
|
||||
return t.memberExpression(file.get("coreIdentifier"), node);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
// arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
|
||||
|
||||
if (node.arguments.length) return;
|
||||
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!callee.computed) return;
|
||||
|
||||
prop = callee.property;
|
||||
if (!t.isIdentifier(prop.object, { name: "Symbol" })) return;
|
||||
if (!t.isIdentifier(prop.property, { name: "iterator" })) return;
|
||||
|
||||
return util.template("corejs-iterator", {
|
||||
CORE_ID: file.get("coreIdentifier"),
|
||||
VALUE: callee.object
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
traverse(ast, astTraverser, null, file);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -3,6 +3,20 @@
|
||||
var traverse = require("../../traverse");
|
||||
var t = require("../../types");
|
||||
|
||||
var traverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFunction(node)) return;
|
||||
|
||||
if (t.isReturnStatement(node) && node.argument) {
|
||||
node.argument = t.memberExpression(t.callExpression(state.file.addHelper("define-property"), [
|
||||
t.thisExpression(),
|
||||
state.key,
|
||||
node.argument
|
||||
]), state.key, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.Property =
|
||||
exports.MethodDefinition = function (node, parent, scope, context, file) {
|
||||
if (node.kind !== "memo") return;
|
||||
@ -17,17 +31,10 @@ exports.MethodDefinition = function (node, parent, scope, context, file) {
|
||||
key = t.literal(key.name);
|
||||
}
|
||||
|
||||
traverse(value, {
|
||||
enter: function (node) {
|
||||
if (t.isFunction(node)) return;
|
||||
var state = {
|
||||
key: key,
|
||||
file: file
|
||||
};
|
||||
|
||||
if (t.isReturnStatement(node) && node.argument) {
|
||||
node.argument = t.memberExpression(t.callExpression(file.addHelper("define-property"), [
|
||||
t.thisExpression(),
|
||||
key,
|
||||
node.argument
|
||||
]), key, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
traverse(value, traverser, null, state);
|
||||
};
|
||||
|
||||
@ -8,8 +8,6 @@ var Scope = require("./scope");
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function noop() { }
|
||||
|
||||
function TraversalContext() {
|
||||
this.shouldFlatten = false;
|
||||
this.shouldRemove = false;
|
||||
@ -167,8 +165,8 @@ function traverse(parent, opts, scope, state) {
|
||||
if (!parent) return;
|
||||
|
||||
if (!opts) opts = {};
|
||||
if (!opts.enter) opts.enter = noop;
|
||||
if (!opts.exit) opts.exit = noop;
|
||||
if (!opts.enter) opts.enter = _.noop;
|
||||
if (!opts.exit) opts.exit = _.noop;
|
||||
|
||||
// array of nodes
|
||||
if (Array.isArray(parent)) {
|
||||
@ -180,35 +178,46 @@ function traverse(parent, opts, scope, state) {
|
||||
}
|
||||
}
|
||||
|
||||
traverse.removeProperties = function (tree) {
|
||||
var clear = function (node) {
|
||||
node._declarations = null;
|
||||
node.extendedRange = null;
|
||||
node._scopeInfo = null;
|
||||
node.tokens = null;
|
||||
node.range = null;
|
||||
node.start = null;
|
||||
node.end = null;
|
||||
node.loc = null;
|
||||
node.raw = null;
|
||||
function clearNode(node) {
|
||||
node._declarations = null;
|
||||
node.extendedRange = null;
|
||||
node._scopeInfo = null;
|
||||
node.tokens = null;
|
||||
node.range = null;
|
||||
node.start = null;
|
||||
node.end = null;
|
||||
node.loc = null;
|
||||
node.raw = null;
|
||||
|
||||
if (Array.isArray(node.trailingComments))
|
||||
clearComments(node.trailingComments);
|
||||
|
||||
if (Array.isArray(node.leadingComments))
|
||||
clearComments(node.leadingComments);
|
||||
};
|
||||
}
|
||||
|
||||
var clearComments = function (comments) {
|
||||
_.each(comments, clear);
|
||||
};
|
||||
var clearTraverser = { enter: clearNode };
|
||||
|
||||
clear(tree);
|
||||
traverse(tree, { enter: clear });
|
||||
function clearComments(comments) {
|
||||
for (var i = 0; i < comments.length; i++)
|
||||
clearNode(comments[i]);
|
||||
}
|
||||
|
||||
traverse.removeProperties = function (tree) {
|
||||
clearNode(tree);
|
||||
traverse(tree, clearTraverser);
|
||||
|
||||
return tree;
|
||||
};
|
||||
|
||||
traverse.hasType = function (tree, type, blacklistTypes) {
|
||||
blacklistTypes = [].concat(blacklistTypes || []);
|
||||
function hasBlacklistedType(node, parent, scope, context, state) {
|
||||
if (node.type === state.type) {
|
||||
state.has = true;
|
||||
context.skip();
|
||||
}
|
||||
}
|
||||
|
||||
traverse.hasType = function (tree, type, blacklistTypes) {
|
||||
// the node we're searching in is blacklisted
|
||||
if (_.contains(blacklistTypes, tree.type)) return false;
|
||||
|
||||
@ -216,17 +225,13 @@ traverse.hasType = function (tree, type, blacklistTypes) {
|
||||
if (tree.type === type) return true;
|
||||
|
||||
var state = {
|
||||
has: false
|
||||
has: false,
|
||||
type: type
|
||||
};
|
||||
|
||||
traverse(tree, {
|
||||
blacklist: blacklistTypes,
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (node.type === type) {
|
||||
state.has = true;
|
||||
context.skip();
|
||||
}
|
||||
}
|
||||
enter: hasBlacklistedType
|
||||
}, null, state);
|
||||
|
||||
return state.has;
|
||||
|
||||
@ -119,6 +119,34 @@ Scope.prototype.generateTempBasedOnNode = function (node, file) {
|
||||
return id;
|
||||
};
|
||||
|
||||
var functionVariableTraverser = {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFor(node)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
if (t.isVar(declar)) state.add(declar);
|
||||
});
|
||||
}
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return context.skip();
|
||||
|
||||
// function identifier doesn't belong to this scope
|
||||
if (state.blockId && node === state.blockId) return;
|
||||
|
||||
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
|
||||
state.add(node, true);
|
||||
}
|
||||
|
||||
// we've ran into a declaration!
|
||||
// we'll let the BlockStatement scope deal with `let` declarations unless
|
||||
if (t.isDeclaration(node) && !t.isBlockScoped(node)) {
|
||||
state.add(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.getInfo = function () {
|
||||
var parent = this.parent;
|
||||
var block = this.block;
|
||||
@ -176,36 +204,10 @@ Scope.prototype.getInfo = function () {
|
||||
if (t.isProgram(block) || t.isFunction(block)) {
|
||||
var state = {
|
||||
blockId: block.id,
|
||||
add: add
|
||||
add: add
|
||||
};
|
||||
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope, context, state) {
|
||||
if (t.isFor(node)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
if (t.isVar(declar)) add(declar);
|
||||
});
|
||||
}
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return context.skip();
|
||||
|
||||
// function identifier doesn't belong to this scope
|
||||
if (state.blockId && node === state.blockId) return;
|
||||
|
||||
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
|
||||
state.add(node, true);
|
||||
}
|
||||
|
||||
// we've ran into a declaration!
|
||||
// we'll let the BlockStatement scope deal with `let` declarations unless
|
||||
if (t.isDeclaration(node) && !t.isBlockScoped(node)) {
|
||||
state.add(node);
|
||||
}
|
||||
}
|
||||
}, this, state);
|
||||
traverse(block, functionVariableTraverser, this, state);
|
||||
}
|
||||
|
||||
// Function - params, rest
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user