add ability to explode a list of statements when trying to replace an expression - damn this is powerful and allows some SUPER cool scenarios
This commit is contained in:
parent
30b1c0154d
commit
70d068226a
@ -33,8 +33,7 @@ export default function (exports, opts) {
|
||||
var nodes = [];
|
||||
var exploded = explode(node.left, nodes, file, scope);
|
||||
nodes.push(buildAssignment(exploded.ref, opts.build(exploded.uid, node.right)));
|
||||
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.BinaryExpression = function (node) {
|
||||
|
||||
@ -40,6 +40,6 @@ export default function (exports, opts) {
|
||||
// todo: duplicate expression node
|
||||
nodes.push(exploded.ref);
|
||||
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
return nodes;
|
||||
};
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@ import * as t from "../../types";
|
||||
|
||||
|
||||
function isIllegalBareSuper(node, parent) {
|
||||
if (!t.isSuperExpression(node)) return false;
|
||||
if (!t.isSuper(node)) return false;
|
||||
if (t.isMemberExpression(parent, { computed: false })) return false;
|
||||
if (t.isCallExpression(parent, { callee: node })) return false;
|
||||
return true;
|
||||
@ -189,13 +189,13 @@ export default class ReplaceSupers {
|
||||
|
||||
looseHandle(path: TraversalPath, getThisReference: Function) {
|
||||
var node = path.node;
|
||||
if (path.isSuperExpression()) {
|
||||
if (path.isSuper()) {
|
||||
this.hasSuper = true;
|
||||
return this.getLooseSuperProperty(node, path.parent);
|
||||
} else if (path.isCallExpression()) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (!t.isSuperExpression(callee.object)) return;
|
||||
if (!t.isSuper(callee.object)) return;
|
||||
|
||||
// super.test(); -> objectRef.prototype.MethodName.call(this);
|
||||
this.hasSuper = true;
|
||||
@ -224,7 +224,7 @@ export default class ReplaceSupers {
|
||||
|
||||
if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (t.isSuperExpression(callee)) {
|
||||
if (t.isSuper(callee)) {
|
||||
// super(); -> _get(Object.getPrototypeOf(objectRef), "MethodName", this).call(this);
|
||||
property = methodNode.key;
|
||||
computed = methodNode.computed;
|
||||
@ -237,17 +237,17 @@ export default class ReplaceSupers {
|
||||
var methodName = methodNode.key.name || "METHOD_NAME";
|
||||
throw this.file.errorWithNode(node, messages.get("classesIllegalSuperCall", methodName));
|
||||
}
|
||||
} else if (t.isMemberExpression(callee) && t.isSuperExpression(callee.object)) {
|
||||
} else if (t.isMemberExpression(callee) && t.isSuper(callee.object)) {
|
||||
// super.test(); -> _get(Object.getPrototypeOf(objectRef.prototype), "test", this).call(this);
|
||||
property = callee.property;
|
||||
computed = callee.computed;
|
||||
args = node.arguments;
|
||||
}
|
||||
} else if (t.isMemberExpression(node) && t.isSuperExpression(node.object)) {
|
||||
} else if (t.isMemberExpression(node) && t.isSuper(node.object)) {
|
||||
// super.name; -> _get(Object.getPrototypeOf(objectRef.prototype), "name", this);
|
||||
property = node.property;
|
||||
computed = node.computed;
|
||||
} else if (t.isAssignmentExpression(node) && t.isSuperExpression(node.left.object) && methodNode.kind === "set") {
|
||||
} else if (t.isAssignmentExpression(node) && t.isSuper(node.left.object) && methodNode.kind === "set") {
|
||||
// super.name = "val"; -> _set(Object.getPrototypeOf(objectRef.prototype), "name", this);
|
||||
this.hasSuper = true;
|
||||
return this.setSuperProperty(node.left.property, node.right, node.left.computed, getThisReference());
|
||||
|
||||
@ -5,9 +5,8 @@ export var check = t.isArrowFunctionExpression;
|
||||
export function ArrowFunctionExpression(node) {
|
||||
t.ensureBlock(node);
|
||||
|
||||
node._aliasFunction = "arrow";
|
||||
node.expression = false;
|
||||
node.type = "FunctionExpression";
|
||||
node.type = "ShadowFunctionExpression";
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -354,8 +354,7 @@ class BlockScoping {
|
||||
var params = values(outsideRefs);
|
||||
|
||||
// build the closure that we're going to wrap the block with
|
||||
var fn = t.functionExpression(null, params, t.blockStatement(block.body));
|
||||
fn._aliasFunction = true;
|
||||
var fn = t.shadowFunctionExpression(null, params, t.blockStatement(block.body));
|
||||
|
||||
// replace the current block body with the one we're going to build
|
||||
block.body = this.body;
|
||||
|
||||
@ -33,7 +33,7 @@ var verifyConstructorVisitor = traverse.explode({
|
||||
|
||||
CallExpression: {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.get("callee").isSuperExpression()) {
|
||||
if (this.get("callee").isSuper()) {
|
||||
state.hasBareSuper = true;
|
||||
|
||||
if (!state.hasSuper) {
|
||||
|
||||
@ -113,22 +113,13 @@ export function ExpressionStatement(node, parent, scope, file) {
|
||||
if (!t.isPattern(expr.left)) return;
|
||||
if (file.isConsequenceExpressionStatement(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var ref = scope.generateUidIdentifier("ref");
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ref, expr.right)
|
||||
]));
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
operator: expr.operator,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
scope: scope,
|
||||
file: file,
|
||||
});
|
||||
destructuring.init(expr.left, ref);
|
||||
|
||||
return nodes;
|
||||
return destructuring.init(expr.left, expr.right);
|
||||
}
|
||||
|
||||
export function AssignmentExpression(node, parent, scope, file) {
|
||||
@ -138,7 +129,7 @@ export function AssignmentExpression(node, parent, scope, file) {
|
||||
scope.push({ id: ref });
|
||||
|
||||
var nodes = [];
|
||||
nodes.push(t.assignmentExpression("=", ref, node.right));
|
||||
nodes.push(t.expressionStatement(t.assignmentExpression("=", ref, node.right)));
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
operator: node.operator,
|
||||
@ -148,9 +139,9 @@ export function AssignmentExpression(node, parent, scope, file) {
|
||||
});
|
||||
destructuring.init(node.left, ref);
|
||||
|
||||
nodes.push(ref);
|
||||
nodes.push(t.expressionStatement(ref));
|
||||
|
||||
return t.toSequenceExpression(nodes, scope);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function variableDeclarationHasPattern(node) {
|
||||
@ -218,20 +209,29 @@ export function VariableDeclaration(node, parent, scope, file) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
var hasRest = function (pattern) {
|
||||
function hasRest(pattern) {
|
||||
for (var i = 0; i < pattern.elements.length; i++) {
|
||||
if (t.isRestElement(pattern.elements[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var arrayUnpackVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isReferencedIdentifier() && state.bindings[node.name]) {
|
||||
state.deopt = true;
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DestructuringTransformer {
|
||||
constructor(opts) {
|
||||
this.blockHoist = opts.blockHoist;
|
||||
this.operator = opts.operator;
|
||||
this.nodes = opts.nodes;
|
||||
this.nodes = opts.nodes || [];
|
||||
this.scope = opts.scope;
|
||||
this.file = opts.file;
|
||||
this.kind = opts.kind;
|
||||
@ -393,7 +393,11 @@ class DestructuringTransformer {
|
||||
if (!pattern.elements[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// deopt on reference to left side identifiers
|
||||
var bindings = t.getBindingIdentifiers(pattern);
|
||||
var state = { deopt: false, bindings };
|
||||
this.scope.traverse(arr, arrayUnpackVisitor, state);
|
||||
return !state.deopt;
|
||||
}
|
||||
|
||||
pushUnpackedArrayPattern(pattern, arr) {
|
||||
@ -474,14 +478,19 @@ class DestructuringTransformer {
|
||||
// trying to destructure a value that we can't evaluate more than once so we
|
||||
// need to save it to a variable
|
||||
|
||||
if (!t.isArrayExpression(ref) && !t.isMemberExpression(ref) && !t.isIdentifier(ref)) {
|
||||
var key = this.scope.generateUidBasedOnNode(ref);
|
||||
this.nodes.push(this.buildVariableDeclaration(key, ref));
|
||||
ref = key;
|
||||
var shouldMemoise = true;
|
||||
if (!t.isArrayExpression(ref) && !t.isMemberExpression(ref)) {
|
||||
var memo = this.scope.generateMemoisedReference(ref, true);
|
||||
if (memo) {
|
||||
this.nodes.push(this.buildVariableDeclaration(memo, ref));
|
||||
ref = memo;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this.push(pattern, ref);
|
||||
|
||||
return this.nodes;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import ReplaceSupers from "../../helpers/replace-supers";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var check = t.isSuperExpression;
|
||||
export var check = t.isSuper;
|
||||
|
||||
function Property(node, scope, getObjectRef, file) {
|
||||
if (!node.method) return;
|
||||
|
||||
@ -31,7 +31,7 @@ exports.Function = function (node, parent, scope, file) {
|
||||
var body = [];
|
||||
|
||||
var argsIdentifier = t.identifier("arguments");
|
||||
argsIdentifier._ignoreAliasFunctions = true;
|
||||
argsIdentifier._shadowedFunctionLiteral = true;
|
||||
|
||||
var lastNonDefaultParam = 0;
|
||||
|
||||
@ -91,8 +91,7 @@ exports.Function = function (node, parent, scope, file) {
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (state.iife) {
|
||||
var container = t.functionExpression(null, [], node.body, node.generator);
|
||||
container._aliasFunction = true;
|
||||
var container = t.shadowFunctionExpression(null, [], node.body, node.generator);
|
||||
|
||||
body.push(t.returnStatement(t.callExpression(container, [])));
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ exports.Function = function (node, parent, scope, file) {
|
||||
var argsId = t.identifier("arguments");
|
||||
|
||||
// otherwise `arguments` will be remapped in arrow functions
|
||||
argsId._ignoreAliasFunctions = true;
|
||||
argsId._shadowedFunctionLiteral = true;
|
||||
|
||||
// support patterns
|
||||
if (t.isPattern(rest)) {
|
||||
|
||||
@ -104,8 +104,6 @@ export function ObjectExpression(node, parent, scope, file) {
|
||||
//
|
||||
|
||||
var body = [];
|
||||
var container = t.functionExpression(null, [], t.blockStatement(body));
|
||||
container._aliasFunction = true;
|
||||
|
||||
//
|
||||
|
||||
@ -121,7 +119,7 @@ export function ObjectExpression(node, parent, scope, file) {
|
||||
t.variableDeclarator(objId, t.objectExpression(initProps))
|
||||
]));
|
||||
|
||||
body.push(t.returnStatement(objId));
|
||||
body.push(t.expressionStatement(objId));
|
||||
|
||||
return t.callExpression(container, []);
|
||||
return body;
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ export function CallExpression(node, parent, scope) {
|
||||
var callee = node.callee;
|
||||
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.generateTempBasedOnNode(callee.object);
|
||||
var temp = scope.generateMemoisedReference(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
contextLiteral = temp;
|
||||
|
||||
@ -16,8 +16,7 @@ export function ComprehensionExpression(node, parent, scope, file) {
|
||||
|
||||
function generator(node) {
|
||||
var body = [];
|
||||
var container = t.functionExpression(null, [], t.blockStatement(body), true);
|
||||
container._aliasFunction = true;
|
||||
var container = t.shadowFunctionExpression(null, [], t.blockStatement(body), true);
|
||||
|
||||
body.push(buildComprehension(node, function () {
|
||||
return t.expressionStatement(t.yieldExpression(node.body));
|
||||
@ -32,7 +31,7 @@ function array(node, parent, scope, file) {
|
||||
var container = util.template("array-comprehension-container", {
|
||||
KEY: uid
|
||||
});
|
||||
container.callee._aliasFunction = true;
|
||||
container.callee.type = "ShadowFunctionExpression";
|
||||
|
||||
var block = container.callee.body;
|
||||
var body = block.body;
|
||||
|
||||
@ -8,9 +8,6 @@ export default {
|
||||
"validation.undeclaredVariableCheck": require("./validation/undeclared-variable-check"),
|
||||
"validation.react": require("./validation/react"),
|
||||
|
||||
// needs to be before `_aliasFunction`
|
||||
"es6.arrowFunctions": require("./es6/arrow-functions"),
|
||||
|
||||
// this goes at the start so we only transform the original user code
|
||||
"spec.functionName": require("./spec/function-name"),
|
||||
|
||||
@ -22,7 +19,7 @@ export default {
|
||||
_modules: require("./internal/modules"),
|
||||
|
||||
// needs to be before `regenerator` due to generator comprehensions
|
||||
// needs to be before `_aliasFunction`
|
||||
// needs to be before `_shadowFunctions`
|
||||
"es7.comprehensions": require("./es7/comprehensions"),
|
||||
|
||||
"es6.classes": require("./es6/classes"),
|
||||
@ -38,10 +35,10 @@ export default {
|
||||
"es5.properties.mutators": require("./es5/properties.mutators"),
|
||||
"es6.properties.shorthand": require("./es6/properties.shorthand"),
|
||||
|
||||
// needs to be before `_aliasFunction` due to define property closure
|
||||
// needs to be before `_shadowFunctions` due to define property closure
|
||||
"es6.properties.computed": require("./es6/properties.computed"),
|
||||
|
||||
"optimisation.es6.forOf": require("./optimisation/flow.for-of"),
|
||||
"optimisation.flow.forOf": require("./optimisation/flow.for-of"),
|
||||
"es6.forOf": require("./es6/for-of"),
|
||||
|
||||
"es6.regex.sticky": require("./es6/regex.sticky"),
|
||||
@ -61,7 +58,7 @@ export default {
|
||||
// needs to be before `es6.blockScoping` as let variables may be produced
|
||||
"es6.destructuring": require("./es6/destructuring"),
|
||||
|
||||
// needs to be before `_aliasFunction` due to block scopes sometimes being wrapped in a
|
||||
// needs to be before `_shadowFunctions` due to block scopes sometimes being wrapped in a
|
||||
// closure
|
||||
"es6.blockScoping": require("./es6/block-scoping"),
|
||||
|
||||
@ -88,7 +85,10 @@ export default {
|
||||
|
||||
_declarations: require("./internal/declarations"),
|
||||
|
||||
_aliasFunctions: require("./internal/alias-functions"),
|
||||
// needs to be before `_shadowFunctions`
|
||||
"es6.arrowFunctions": require("./es6/arrow-functions"),
|
||||
|
||||
_shadowFunctions: require("./internal/alias-functions"),
|
||||
|
||||
"es6.symbols": require("./es6/symbols"),
|
||||
"spec.undefinedToVoid": require("./spec/undefined-to-void"),
|
||||
|
||||
@ -2,11 +2,11 @@ import * as t from "../../../types";
|
||||
|
||||
var functionChildrenVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (this.isFunction() && !node._aliasFunction) {
|
||||
if (this.isFunction()) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (node._ignoreAliasFunctions) return this.skip();
|
||||
if (node._shadowedFunctionLiteral) return this.skip();
|
||||
|
||||
var getId;
|
||||
|
||||
@ -24,18 +24,18 @@ var functionChildrenVisitor = {
|
||||
|
||||
var functionVisitor = {
|
||||
enter(node, parent, scope, state) {
|
||||
if (!node._aliasFunction) {
|
||||
if (this.isFunction()) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return this.skip();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (this.isFunction()) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return this.skip();
|
||||
} else if (!this.isShadowFunctionExpression()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
this.traverse(functionChildrenVisitor, state);
|
||||
|
||||
node.type = "FunctionExpression";
|
||||
|
||||
return this.skip();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export { bare as FunctionExpression } from "../../helpers/name-method";
|
||||
export { bare as ArrowFunctionExpression } from "../../helpers/name-method";
|
||||
|
||||
@ -24,13 +24,13 @@ export function AssignmentExpression(node, parent, scope, file) {
|
||||
|
||||
var nodes = [];
|
||||
var left = node.left.object;
|
||||
var temp = scope.generateTempBasedOnNode(node.left.object);
|
||||
var temp = scope.generateMemoisedReference(left);
|
||||
|
||||
nodes.push(t.expressionStatement(t.assignmentExpression("=", temp, left)));
|
||||
nodes.push(buildDefaultsCallExpression(node, temp, file));
|
||||
if (temp) nodes.push(temp);
|
||||
|
||||
return t.toSequenceExpression(nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExpressionStatement(node, parent, scope, file) {
|
||||
|
||||
@ -9,6 +9,36 @@ import extend from "lodash/object/extend";
|
||||
import Scope from "../scope";
|
||||
import * as t from "../../types";
|
||||
|
||||
var hoistVariablesVisitor = {
|
||||
enter(node, parent, scope ) {
|
||||
if (this.isFunction()) {
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
if (this.isVariableDeclaration() && node.kind === "var") {
|
||||
var bindings = this.getBindingIdentifiers();
|
||||
for (var key in bindings) {
|
||||
scope.push({
|
||||
id: bindings[key].identifiers
|
||||
});
|
||||
}
|
||||
|
||||
var exprs = [];
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var declar = node.declarations[i];
|
||||
if (declar.init) {
|
||||
exprs.push(t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.id, declar.init)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return exprs;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default class TraversalPath {
|
||||
constructor(parent, container) {
|
||||
this.container = container;
|
||||
@ -86,6 +116,8 @@ export default class TraversalPath {
|
||||
}
|
||||
|
||||
this.setScope(file);
|
||||
|
||||
this.type = this.node && this.node.type;
|
||||
}
|
||||
|
||||
remove() {
|
||||
@ -130,16 +162,28 @@ export default class TraversalPath {
|
||||
set node(replacement) {
|
||||
if (!replacement) return this.remove();
|
||||
|
||||
var oldNode = this.node;
|
||||
var isArray = Array.isArray(replacement);
|
||||
var oldNode = this.node;
|
||||
|
||||
var isArray = Array.isArray(replacement);
|
||||
if (isArray && replacement.length === 1) {
|
||||
isArray = false;
|
||||
replacement = replacement[0];
|
||||
}
|
||||
|
||||
var replacements = isArray ? replacement : [replacement];
|
||||
|
||||
// inherit comments from original node to the first replacement node
|
||||
var inheritTo = replacements[0];
|
||||
if (inheritTo) t.inheritsComments(inheritTo, oldNode);
|
||||
|
||||
//
|
||||
if (t.isStatement(replacements[0]) && t.isType(this.type, "Expression")) {
|
||||
return this.setStatementsToExpression(replacements);
|
||||
}
|
||||
|
||||
// replace the node
|
||||
this.container[this.key] = replacement;
|
||||
this.type = replacement.type;
|
||||
|
||||
// potentially create new scope
|
||||
this.setScope();
|
||||
@ -162,6 +206,50 @@ export default class TraversalPath {
|
||||
}
|
||||
}
|
||||
|
||||
getLastStatements(): Array<TraversalPath> {
|
||||
var paths = [];
|
||||
|
||||
var add = function (path) {
|
||||
paths = paths.concat(path.getLastStatements());
|
||||
};
|
||||
|
||||
if (this.isIfStatement()) {
|
||||
add(this.get("consequent"));
|
||||
add(this.get("alternate"));
|
||||
} else if (this.isFor() || this.isWhile()) {
|
||||
add(this.get("body"));
|
||||
} else if (this.isProgram() || this.isBlockStatement()) {
|
||||
add(this.get("body").pop());
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
setStatementsToExpression(nodes: Array) {
|
||||
var toSequenceExpression = t.toSequenceExpression(nodes, this.scope);
|
||||
|
||||
if (toSequenceExpression) {
|
||||
return this.node = toSequenceExpression;
|
||||
} else {
|
||||
var container = t.shadowFunctionExpression(null, [], t.blockStatement(nodes));
|
||||
|
||||
this.node = t.callExpression(container, []);
|
||||
|
||||
// add implicit returns to all ending expression statements
|
||||
var last = this.getLastStatements();
|
||||
for (var i = 0; i < last.length; i++) {
|
||||
var lastNode = last[i];
|
||||
if (lastNode.isExpressionStatement()) {
|
||||
lastNode.node = t.returnStatement(lastNode.node.expression);
|
||||
}
|
||||
}
|
||||
|
||||
this.traverse(hoistVariablesVisitor);
|
||||
|
||||
return this.node;
|
||||
}
|
||||
}
|
||||
|
||||
call(key) {
|
||||
var node = this.node;
|
||||
if (!node) return;
|
||||
|
||||
@ -198,8 +198,8 @@ export default class Scope {
|
||||
* Description
|
||||
*/
|
||||
|
||||
generateTempBasedOnNode(node: Object): ?Object {
|
||||
if (t.isThisExpression(node) || t.isSuperExpression(node)) {
|
||||
generateMemoisedReference(node: Object, dontPush?: boolean): ?Object {
|
||||
if (t.isThisExpression(node) || t.isSuper(node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -208,10 +208,7 @@ export default class Scope {
|
||||
}
|
||||
|
||||
var id = this.generateUidBasedOnNode(node);
|
||||
this.push({
|
||||
key: id.name,
|
||||
id: id
|
||||
});
|
||||
if (!dontPush) this.push({ id });
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -513,7 +510,7 @@ export default class Scope {
|
||||
|
||||
getFunctionParent() {
|
||||
var scope = this;
|
||||
while (scope.parent && !t.isFunction(scope.block)) {
|
||||
while (scope.parent && !t.isFunction(scope.block) && !t.isShadowFunctionExpression(scope.block)) {
|
||||
scope = scope.parent;
|
||||
}
|
||||
return scope;
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
"ArrayExpression": ["Expression"],
|
||||
"AssignmentExpression": ["Expression"],
|
||||
"AwaitExpression": ["Expression"],
|
||||
"ShadowFunctionExpression": ["Expression"],
|
||||
"CallExpression": ["Expression"],
|
||||
"ComprehensionExpression": ["Expression", "Scopable"],
|
||||
"ConditionalExpression": ["Expression"],
|
||||
@ -64,7 +65,7 @@
|
||||
"SequenceExpression": ["Expression"],
|
||||
"TaggedTemplateExpression": ["Expression"],
|
||||
"ThisExpression": ["Expression"],
|
||||
"SuperExpression": ["Expression"],
|
||||
"Super": ["Expression"],
|
||||
"UpdateExpression": ["Expression"],
|
||||
"JSXEmptyExpression": ["Expression"],
|
||||
"JSXMemberExpression": ["Expression"],
|
||||
|
||||
@ -45,6 +45,13 @@
|
||||
"tokens": null
|
||||
},
|
||||
|
||||
"ShadowFunctionExpression": {
|
||||
"id": null,
|
||||
"params": null,
|
||||
"body": null,
|
||||
"generator": false
|
||||
},
|
||||
|
||||
"FunctionExpression": {
|
||||
"id": null,
|
||||
"params": null,
|
||||
|
||||
@ -27,31 +27,46 @@ export function toComputedKey(node: Object, key: Object = node.key || node.prope
|
||||
*/
|
||||
|
||||
export function toSequenceExpression(nodes: Array<Object>, scope: Scope): Object {
|
||||
var exprs = [];
|
||||
var declars = [];
|
||||
var exprs = [];
|
||||
|
||||
each(nodes, function (node) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
if (t.isExpression(node)) {
|
||||
exprs.push(node);
|
||||
} if (t.isExpressionStatement(node)) {
|
||||
} else if (t.isExpressionStatement(node)) {
|
||||
exprs.push(node.expression);
|
||||
} else if (t.isVariableDeclaration(node)) {
|
||||
if (node.kind !== "var") return; // bailed
|
||||
|
||||
each(node.declarations, function (declar) {
|
||||
scope.push({
|
||||
declars.push({
|
||||
kind: node.kind,
|
||||
id: declar.id
|
||||
});
|
||||
exprs.push(t.assignmentExpression("=", declar.id, declar.init));
|
||||
});
|
||||
} else if (t.isIfStatement(node)) {
|
||||
return t.conditionalExpression(
|
||||
exprs.push(t.conditionalExpression(
|
||||
node.test,
|
||||
node.consequent ? t.toSequenceExpression([node.consequent]) : t.identifier("undefined"),
|
||||
node.alternate ? t.toSequenceExpression([node.alternate]) : t.identifier("undefined")
|
||||
);
|
||||
));
|
||||
} else if (t.isBlockStatement(node)) {
|
||||
return t.toSequenceExpression(node.body);
|
||||
exprs.push(t.toSequenceExpression(node.body));
|
||||
} else {
|
||||
// bailed, we can't understand this
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
for (let i = 0; i < declars.length; i++) {
|
||||
scope.push(declars[i]);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
if (exprs.length === 1) {
|
||||
return exprs[0];
|
||||
|
||||
@ -24,7 +24,6 @@ function registerType(type: string, skipAliasCheck?: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export var STATEMENT_OR_BLOCK_KEYS = ["consequent", "body", "alternate"];
|
||||
export var NATIVE_TYPE_NAMES = ["Array", "Object", "Number", "Boolean", "Date", "Array", "String", "Promise", "Set", "Map", "WeakMap", "WeakSet", "Uint16Array", "ArrayBuffer", "DataView", "Int8Array", "Uint8Array", "Uint8ClampedArray", "Uint32Array", "Int32Array", "Float32Array", "Int16Array", "Float64Array"];
|
||||
export var FLATTENABLE_KEYS = ["body", "expressions"];
|
||||
@ -65,25 +64,23 @@ export const TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_AL
|
||||
export function is(type: string, node: Object, opts?: Object, skipAliasCheck?: boolean): boolean {
|
||||
if (!node) return false;
|
||||
|
||||
var typeMatches = type === node.type;
|
||||
var matches = isType(node.type, type);
|
||||
if (!matches) return false;
|
||||
|
||||
if (!typeMatches && !skipAliasCheck) {
|
||||
var aliases = t.FLIPPED_ALIAS_KEYS[type];
|
||||
|
||||
if (typeof aliases !== "undefined") {
|
||||
typeMatches = aliases.indexOf(node.type) > -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeMatches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof opts !== "undefined") {
|
||||
if (typeof opts === "undefined") {
|
||||
return true;
|
||||
} else {
|
||||
return t.shallowEqual(node, opts);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
export function isType(nodeType, targetType) {
|
||||
if (nodeType === targetType) return true;
|
||||
|
||||
var aliases = t.FLIPPED_ALIAS_KEYS[targetType];
|
||||
if (aliases) return aliases.indexOf(nodeType) > -1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
each(t.VISITOR_KEYS, function (keys, type) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user