Simeon Willbanks 93d438cf01 Fix misspelling
2016-03-16 22:17:09 -07:00

203 lines
5.1 KiB
JavaScript

/* eslint max-len: 0 */
import type Hub from "../hub";
import type TraversalContext from "../context";
import * as virtualTypes from "./lib/virtual-types";
import buildDebug from "debug";
import invariant from "invariant";
import traverse from "../index";
import assign from "lodash/object/assign";
import Scope from "../scope";
import * as t from "babel-types";
import { path as pathCache } from "../cache";
let debug = buildDebug("babel");
export default class NodePath {
constructor(hub: Hub, parent: Object) {
this.parent = parent;
this.hub = hub;
this.contexts = [];
this.data = {};
this.shouldSkip = false;
this.shouldStop = false;
this.removed = false;
this.state = null;
this.opts = null;
this.skipKeys = null;
this.parentPath = null;
this.context = null;
this.container = null;
this.listKey = null;
this.inList = false;
this.parentKey = null;
this.key = null;
this.node = null;
this.scope = null;
this.type = null;
this.typeAnnotation = null;
}
parent: Object;
hub: Hub;
contexts: Array<TraversalContext>;
data: Object;
shouldSkip: boolean;
shouldStop: boolean;
removed: boolean;
state: any;
opts: ?Object;
skipKeys: ?Object;
parentPath: ?NodePath;
context: TraversalContext;
container: ?Object | Array<Object>;
listKey: ?string;
inList: boolean;
parentKey: ?string;
key: ?string;
node: ?Object;
scope: Scope;
type: ?string;
typeAnnotation: ?Object;
static get({ hub, parentPath, parent, container, listKey, key }): NodePath {
if (!hub && parentPath) {
hub = parentPath.hub;
}
invariant(parent, "To get a node path the parent needs to exist");
let targetNode = container[key];
let paths = pathCache.get(parent) || [];
if (!pathCache.has(parent)) {
pathCache.set(parent, paths);
}
let path;
for (let i = 0; i < paths.length; i++) {
let pathCheck = paths[i];
if (pathCheck.node === targetNode) {
path = pathCheck;
break;
}
}
if (path && !(path instanceof NodePath)) {
if (path.constructor.name === "NodePath") {
// we're going to absolutley thrash the tree and allocate way too many node paths
// than is necessary but there's no way around this as the node module resolution
// algorithm is ridiculous
path = null;
} else {
// badly deserialised probably
throw new Error("We found a path that isn't a NodePath instance. Possibly due to bad serialisation.");
}
}
if (!path) {
path = new NodePath(hub, parent);
paths.push(path);
}
path.setup(parentPath, container, listKey, key);
return path;
}
getScope(scope: Scope) {
let ourScope = scope;
// we're entering a new scope so let's construct it!
if (this.isScope()) {
ourScope = new Scope(this, scope);
}
return ourScope;
}
setData(key: string, val: any): any {
return this.data[key] = val;
}
getData(key: string, def?: any): any {
let val = this.data[key];
if (!val && def) val = this.data[key] = def;
return val;
}
buildCodeFrameError(msg: string, Error: typeof Error = SyntaxError): Error {
return this.hub.file.buildCodeFrameError(this.node, msg, Error);
}
traverse(visitor: Object, state?: any) {
traverse(this.node, visitor, this.scope, state, this);
}
mark(type: string, message: string) {
this.hub.file.metadata.marked.push({
type,
message,
loc: this.node.loc
});
}
set(key: string, node: Object) {
t.validate(this.node, key, node);
this.node[key] = node;
}
getPathLocation(): string {
let parts = [];
let path = this;
do {
let key = path.key;
if (path.inList) key = `${path.listKey}[${key}]`;
parts.unshift(key);
} while (path = path.parentPath);
return parts.join(".");
}
debug(buildMessage: Function) {
if (!debug.enabled) return;
debug(`${this.getPathLocation()} ${this.type}: ${buildMessage()}`);
}
}
assign(NodePath.prototype, require("./ancestry"));
assign(NodePath.prototype, require("./inference"));
assign(NodePath.prototype, require("./replacement"));
assign(NodePath.prototype, require("./evaluation"));
assign(NodePath.prototype, require("./conversion"));
assign(NodePath.prototype, require("./introspection"));
assign(NodePath.prototype, require("./context"));
assign(NodePath.prototype, require("./removal"));
assign(NodePath.prototype, require("./modification"));
assign(NodePath.prototype, require("./family"));
assign(NodePath.prototype, require("./comments"));
for (let type of (t.TYPES: Array<string>)) {
let typeKey = `is${type}`;
NodePath.prototype[typeKey] = function (opts) {
return t[typeKey](this.node, opts);
};
NodePath.prototype[`assert${type}`] = function (opts) {
if (!this[typeKey](opts)) {
throw new TypeError(`Expected node path of type ${type}`);
}
};
}
for (let type in virtualTypes) {
if (type[0] === "_") continue;
if (t.TYPES.indexOf(type) < 0) t.TYPES.push(type);
let virtualType = virtualTypes[type];
NodePath.prototype[`is${type}`] = function (opts) {
return virtualType.checkPath(this, opts);
};
}