handle path contexts MUCH better, they're now only held during the traversal iteration and the previous context is released upon completion, also verify path keys and try and obtain a new one if invalid - fixes #1545
This commit is contained in:
parent
9908e331b7
commit
375689a1ff
@ -463,7 +463,7 @@ export default class File {
|
||||
}
|
||||
|
||||
_addAst(ast) {
|
||||
this.path = TraversalPath.get(null, null, ast, ast, "program", this);
|
||||
this.path = TraversalPath.get(null, ast, ast, "program", this).setContext(null, this);
|
||||
this.scope = this.path.scope;
|
||||
this.ast = ast;
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ export function JSXElement(node, parent, scope, file) {
|
||||
this.traverse(immutabilityVisitor, state);
|
||||
|
||||
if (state.isImmutable) {
|
||||
return this.hoist();
|
||||
this.hoist();
|
||||
} else {
|
||||
node._hoisted = true;
|
||||
}
|
||||
|
||||
@ -16,7 +16,9 @@ export default class TraversalContext {
|
||||
}
|
||||
|
||||
create(node, obj, key) {
|
||||
return TraversalPath.get(this.parentPath, this, node, obj, key);
|
||||
var path = TraversalPath.get(this.parentPath, node, obj, key);
|
||||
path.unshiftContext(this);
|
||||
return path;
|
||||
}
|
||||
|
||||
visitMultiple(nodes, node, key) {
|
||||
@ -37,25 +39,32 @@ export default class TraversalContext {
|
||||
}
|
||||
|
||||
// visit the queue
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
var path = queue[i];
|
||||
for (let path of (queue: Array)) {
|
||||
path.update();
|
||||
|
||||
if (visited.indexOf(path.node) >= 0) continue;
|
||||
visited.push(path.node);
|
||||
|
||||
path.setContext(this.parentPath, this, path.key);
|
||||
|
||||
if (path.visit()) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let path of (queue: Array)) {
|
||||
path.shiftContext();
|
||||
}
|
||||
|
||||
this.queue = null;
|
||||
|
||||
return stop;
|
||||
}
|
||||
|
||||
visitSingle(node, key) {
|
||||
if (this.shouldVisit(node[key])) {
|
||||
return this.create(node, node, key).visit();
|
||||
var path = this.create(node, node, key);
|
||||
path.visit();
|
||||
path.shiftContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -125,6 +125,6 @@ export default class PathHoister {
|
||||
uid = t.jSXExpressionContainer(uid);
|
||||
}
|
||||
|
||||
return uid;
|
||||
this.path.replaceWith(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ var hoistVariablesVisitor = explode({
|
||||
export default class TraversalPath {
|
||||
constructor(parent, container) {
|
||||
this.container = container;
|
||||
this.contexts = [];
|
||||
this.parent = parent;
|
||||
this.data = {};
|
||||
}
|
||||
@ -53,7 +54,7 @@ export default class TraversalPath {
|
||||
* Description
|
||||
*/
|
||||
|
||||
static get(parentPath: TraversalPath, context?: TraversalContext, parent, container, key, file?: File) {
|
||||
static get(parentPath: TraversalPath, parent, container, key) {
|
||||
var targetNode = container[key];
|
||||
var paths = container._paths = container._paths || [];
|
||||
var path;
|
||||
@ -71,7 +72,7 @@ export default class TraversalPath {
|
||||
paths.push(path);
|
||||
}
|
||||
|
||||
path.setContext(parentPath, context, key, file);
|
||||
path.setup(parentPath, key);
|
||||
|
||||
return path;
|
||||
}
|
||||
@ -178,8 +179,10 @@ export default class TraversalPath {
|
||||
*/
|
||||
|
||||
queueNode(path) {
|
||||
if (this.context && this.context.queue) {
|
||||
this.context.queue.push(path);
|
||||
for (var context of (this.contexts: Array)) {
|
||||
if (context.queue) {
|
||||
context.queue.push(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +228,7 @@ export default class TraversalPath {
|
||||
paths.push(path);
|
||||
this.queueNode(path);
|
||||
} else {
|
||||
paths.push(TraversalPath.get(this, null, node, this.container, to));
|
||||
paths.push(TraversalPath.get(this, node, this.container, to));
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,6 +347,8 @@ export default class TraversalPath {
|
||||
*/
|
||||
|
||||
setScope(file?) {
|
||||
if (this.opts && this.opts.noScope) return;
|
||||
|
||||
var target = this.context || this.parentPath;
|
||||
this.scope = TraversalPath.getScope(this, target && target.scope, file);
|
||||
}
|
||||
@ -352,35 +357,87 @@ export default class TraversalPath {
|
||||
* Description
|
||||
*/
|
||||
|
||||
clearContext() {
|
||||
this.context = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
setContext(parentPath, context, key, file?) {
|
||||
setContext(context, file) {
|
||||
this.shouldSkip = false;
|
||||
this.shouldStop = false;
|
||||
this.removed = false;
|
||||
|
||||
this.parentPath = parentPath || this.parentPath;
|
||||
this.key = key;
|
||||
|
||||
if (context) {
|
||||
this.context = context;
|
||||
this.state = context.state;
|
||||
this.opts = context.opts;
|
||||
}
|
||||
|
||||
this.node = this.container[this.key];
|
||||
this.type = this.node && this.node.type;
|
||||
|
||||
var log = file && this.type === "Program";
|
||||
if (log) file.log.debug("Start scope building");
|
||||
this.setScope(file);
|
||||
if (log) file.log.debug("End scope building");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
update() {
|
||||
if (this.node === this.container[this.key]) return;
|
||||
|
||||
// grrr, path key is out of sync. this is likely due to a modification to the AST
|
||||
// not through our path APIs
|
||||
|
||||
if (Array.isArray(this.container)) {
|
||||
for (var i = 0; i < this.container.length; i++) {
|
||||
if (this.container[i] === this.node) {
|
||||
return this.setKey(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var key in this.container) {
|
||||
if (this.container[key] === this.node) {
|
||||
return this.setKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Where did we go?!?!?!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
shiftContext() {
|
||||
this.contexts.shift();
|
||||
this.setContext(this.contexts[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
unshiftContext(context) {
|
||||
this.contexts.unshift(context);
|
||||
this.setContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
setup(parentPath, key) {
|
||||
this.parentPath = parentPath || this.parentPath;
|
||||
this.setKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
setKey(key) {
|
||||
this.key = key;
|
||||
this.node = this.container[this.key];
|
||||
this.type = this.node && this.node.type;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -554,7 +611,7 @@ export default class TraversalPath {
|
||||
// doesn't matter, our nodes will be inserted anyway
|
||||
|
||||
var container = this.node[containerKey];
|
||||
var path = TraversalPath.get(this, null, this.node, container, 0);
|
||||
var path = TraversalPath.get(this, this.node, container, 0);
|
||||
|
||||
return path.insertBefore(nodes);
|
||||
}
|
||||
@ -571,7 +628,7 @@ export default class TraversalPath {
|
||||
|
||||
var container = this.node[containerKey];
|
||||
var i = container.length;
|
||||
var path = TraversalPath.get(this, null, this.node, container, i);
|
||||
var path = TraversalPath.get(this, this.node, container, i);
|
||||
|
||||
return path.replaceWith(nodes, true);
|
||||
}
|
||||
@ -767,9 +824,10 @@ export default class TraversalPath {
|
||||
var node = this.node;
|
||||
if (!node) return;
|
||||
|
||||
var previousType = this.type;
|
||||
|
||||
// call the function with the params (node, parent, scope, state)
|
||||
var replacement = fn.call(this, node, this.parent, this.scope, this.state);
|
||||
var previousType = this.type;
|
||||
|
||||
if (replacement) {
|
||||
this.replaceWith(replacement, true);
|
||||
@ -777,7 +835,7 @@ export default class TraversalPath {
|
||||
|
||||
if (this.shouldStop || this.shouldSkip || this.removed) return;
|
||||
|
||||
if (replacement && previousType !== this.type) {
|
||||
if (previousType !== this.type) {
|
||||
this.queueNode(this);
|
||||
return;
|
||||
}
|
||||
@ -831,7 +889,7 @@ export default class TraversalPath {
|
||||
*/
|
||||
|
||||
getSibling(key) {
|
||||
return TraversalPath.get(this.parentPath, null, this.parent, this.container, key, this.file);
|
||||
return TraversalPath.get(this.parentPath, this.parent, this.container, key, this.file);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -858,10 +916,10 @@ export default class TraversalPath {
|
||||
if (Array.isArray(container)) {
|
||||
// requested a container so give them all the paths
|
||||
return container.map((_, i) => {
|
||||
return TraversalPath.get(this, null, node, container, i);
|
||||
return TraversalPath.get(this, node, container, i).setContext();
|
||||
});
|
||||
} else {
|
||||
return TraversalPath.get(this, null, node, node, key);
|
||||
return TraversalPath.get(this, node, node, key).setContext();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1095,6 +1153,7 @@ export default class TraversalPath {
|
||||
*/
|
||||
|
||||
traverse(visitor, state) {
|
||||
if (!this.scope) console.log(this.contexts);
|
||||
traverse(this.node, visitor, this.scope, state, this);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user