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:
parent
8c3aab9a26
commit
9dacde6d07
@ -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;
|
||||
}
|
||||
|
||||
5
src/babel/traversal/hub.js
Normal file
5
src/babel/traversal/hub.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default class Hub {
|
||||
constructor(file) {
|
||||
this.file = 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 = {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user