further implement the concept of a "Hub" that all traversal paths get access to, also add in some assertions to confirm path state when performing manipulation

This commit is contained in:
Sebastian McKenzie 2015-06-06 03:34:08 +01:00
parent 8c3aab9a26
commit 9dacde6d07
6 changed files with 63 additions and 23 deletions

View File

@ -14,6 +14,7 @@ import codeFrame from "../../helpers/code-frame";
import defaults from "lodash/object/defaults";
import includes from "lodash/collection/includes";
import traverse from "../../traversal";
import Hub from "../../traversal/hub";
import assign from "lodash/object/assign";
import Logger from "./logger";
import parse from "../../helpers/parse";
@ -44,6 +45,8 @@ export default class File {
this.ast = {};
this.buildTransformers();
this.hub = new Hub(this);
}
static helpers = [
@ -467,11 +470,12 @@ export default class File {
_addAst(ast) {
this.path = NodePath.get({
hub: this.hub,
parentPath: null,
parent: ast,
container: ast,
key: "program"
}).setContext(null, this);
}).setContext();
this.scope = this.path.scope;
this.ast = ast;
}

View File

@ -0,0 +1,5 @@
export default class Hub {
constructor(file) {
this.file = file;
}
}

View File

@ -54,13 +54,6 @@ function clearNode(node) {
let key = CLEAR_KEYS[i];
if (node[key] != null) node[key] = null;
}
for (let key in node) {
var val = node[key];
if (Array.isArray(val)) {
delete val._paths;
}
}
}
var clearVisitor = {

View File

@ -1,4 +1,3 @@
import * as messages from "../../messages";
import NodePath from "./index";
import traverse from "../index";
@ -111,11 +110,11 @@ export function stop() {
* Description
*/
export function setScope(file?) {
export function setScope() {
if (this.opts && this.opts.noScope) return;
var target = this.context || this.parentPath;
this.scope = NodePath.getScope(this, target && target.scope, file);
this.scope = NodePath.getScope(this, target && target.scope, this.hub);
if (this.scope) this.scope.init();
}
@ -123,7 +122,7 @@ export function setScope(file?) {
* Description
*/
export function setContext(context, file) {
export function setContext(context) {
this.shouldSkip = false;
this.shouldStop = false;
this.removed = false;
@ -135,10 +134,7 @@ export function setContext(context, file) {
this.opts = context.opts;
}
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");
this.setScope();
return this;
}
@ -152,11 +148,21 @@ export function setContext(context, file) {
export function resync() {
if (this.removed) return;
this._resyncParent();
this._resyncContainer();
this._resyncKey();
//this._resyncRemoved();
}
export function _resyncParent() {
if (this.parentPath) {
this.parent = this.parentPath.node;
}
}
export function _resyncKey() {
if (!this.container) return;
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
@ -176,7 +182,7 @@ export function _resyncKey() {
}
}
throw new Error(messages.get("lostTrackNodePath"));
this.key = null;
}
export function _resyncContainer() {
@ -185,11 +191,21 @@ export function _resyncContainer() {
if (!containerKey || !parentPath) return;
var newContainer = parentPath.node[containerKey];
if (!newContainer || this.container === newContainer) return;
if (this.container === newContainer) return;
// container is out of sync. this is likely the result of it being reassigned
this.container = newContainer;
if (newContainer) {
this.container = newContainer;
} else {
this.container = null;
}
}
export function _resyncRemoved() {
if (this.key == null || !this.container || this.container[this.key] !== this.node) {
this._markRemoved();
}
}
/**
@ -214,7 +230,10 @@ export function unshiftContext(context) {
* Description
*/
export function setup(parentPath, key) {
export function setup(parentPath, container, containerKey, key) {
this.containerKey = containerKey;
this.container = container;
this.parentPath = parentPath || this.parentPath;
this.setKey(key);
}

View File

@ -7,6 +7,8 @@ import * as t from "../../types";
*/
export function insertBefore(nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
if (this.parentPath.isExpressionStatement() || this.parentPath.isLabeledStatement()) {
@ -27,6 +29,7 @@ export function insertBefore(nodes) {
} else {
throw new Error("No clue what to do with this node type.");
}
return [this];
}
@ -78,6 +81,8 @@ export function _maybePopFromStatements(nodes) {
*/
export function insertAfter(nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
if (this.parentPath.isExpressionStatement() || this.parentPath.isLabeledStatement()) {
@ -102,6 +107,7 @@ export function insertAfter(nodes) {
} else {
throw new Error("No clue what to do with this node type.");
}
return [this];
}
@ -110,7 +116,7 @@ export function insertAfter(nodes) {
*/
export function updateSiblingKeys(fromIndex, incrementBy) {
var paths = this.container._paths;
var paths = this.parent._paths;
for (var i = 0; i < paths.length; i++) {
let path = paths[i];
if (path.key >= fromIndex) {
@ -153,6 +159,8 @@ export function _verifyNodeList(nodes) {
*/
export function unshiftContainer(containerKey, nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
// get the first path and insert our nodes before it, if it doesn't exist then it
@ -175,6 +183,8 @@ export function unshiftContainer(containerKey, nodes) {
*/
export function pushContainer(containerKey, nodes) {
this._assertUnremoved();
nodes = this._verifyNodeList(nodes);
// get an invisible path that represents the last node + 1 and replace it with our

View File

@ -15,6 +15,8 @@ export function remove() {
*/
export function dangerouslyRemove() {
this._assertUnremoved();
this.resync();
if (this._callRemovalHooks("pre")) {
@ -45,8 +47,15 @@ export function _remove() {
}
export function _markRemoved() {
this.node = null;
this.removed = true;
this.shouldSkip = true;
this.removed = true;
this.node = null;
}
export function _assertUnremoved() {
if (this.removed) {
throw this.errorWithNode("NodePath has been removed so is read-only.");
}
}
/**