"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert_1 = require("assert");
const lodash_1 = require("lodash");
const createDebug = require("debug");
const debug = createDebug('tardis');
function verifyNode(node) {
Iif (typeof node.type !== 'string' || !node.type) {
throw new Error('Node is missing a valid type');
}
Iif (typeof node.children !== 'function') {
throw new Error(`Invalid node of type ${node.type}: missing a valid children function`);
}
if (typeof node.toString !== 'function' || node.toString === {}.toString) {
node.toString = () => {
throw new Error(`Invalid node of type ${node.type}: missing a valid toString() function - will not generate`);
};
}
Iif (typeof node.validate === 'function') {
node.validate();
}
}
function isInteger(str) {
try {
return !Number.isNaN(parseInt(str, 10));
}
catch (err) {
return false;
}
}
function verifyPath(pathToChild) {
const path = pathToChild.split('.');
for (let i = 0; i < path.length - 1; ++i) {
Iif (isInteger(path[i])) {
throw new Error(`Found an index partway through a child path in "${pathToChild}".` +
`Indexes are only supported at the end of a child path.`);
}
}
}
class Path {
constructor(node, parentPath, childPath) {
this.node = node;
this.parentPath = parentPath;
this.childPath = childPath;
this.unshifts = Object.create(null);
this.shifts = Object.create(null);
this.removals = Object.create(null);
verifyNode(node);
if (childPath) {
verifyPath(childPath);
}
}
replaceWith(node) {
Iif (!node) {
throw new Error('Node removal attempted with .replaceWith() - please use .remove() instead');
}
verifyNode(node);
this.node = node;
return this;
}
remove() {
this.node = undefined;
if (this.parentPath !== undefined) {
const path = (this.childPath || '').split('.');
const index = path.pop();
if (isInteger(index)) {
const subpath = path.join('.');
debug('marking %s for removal on parent of type %s', this.childPath, this.parentPath.node.type);
this.parentPath.removals[subpath] = this.parentPath.removals[subpath] || [];
this.parentPath.removals[subpath].push(parseInt(index, 10));
}
else {
lodash_1.set(this.parentPath.node, this.childPath, undefined);
verifyNode(this.parentPath.node);
}
}
return this;
}
findParent(parentType) {
debug('checking %s node for parent of %s', this.node.type, parentType);
Iif (!this.parentPath) {
return;
}
if (this.parentPath.node.type === parentType) {
return this.parentPath;
}
return this.parentPath.findParent(parentType);
}
unshiftContainer(property, node) {
this.unshifts[property] = this.unshifts[property] || [];
this.unshifts[property].push(node);
assert_1.ok(Array.isArray(this.node[property]), 'Could not like an Array-like property to insert into');
assert_1.ok(node, 'node is a required property');
this.node[property].unshift(node);
return this;
}
pushContainer(property, node) {
this.shifts[property] = this.shifts[property] || [];
this.shifts[property].push(node);
assert_1.ok(Array.isArray(this.node[property]), 'Could not like an Array-like property to insert into');
assert_1.ok(node, 'node is a required property');
this.node[property].push(node);
return this;
}
added() {
const results = [];
for (const property in this.unshifts) {
Eif (this.unshifts[property] !== undefined) {
for (let i = 0; i < this.unshifts[property].length; ++i) {
results.push({
pathToChild: `${property}.${i}`,
child: this.unshifts[property][i],
});
}
}
}
for (const property in this.shifts) {
Eif (this.shifts[property] !== undefined) {
for (let i = 0; i < this.shifts[property].length; ++i) {
results.push({
pathToChild: `${property}.${i}`,
child: this.shifts[property][i],
});
}
}
}
return results;
}
removed() {
debug('starting child cleanup at %s =>', this.childPath, this.removals);
for (const path in this.removals) {
if (this.removals[path] !== undefined) {
const removals = this.removals[path];
E debug('cleaning up children at %s', path);
this.node[path] = this.node[path].filter(function filterChildren(_, index) {
return removals.indexOf(index) === -1;
});
}
}
}
}
exports.Path = Path;
//# sourceMappingURL=path.js.map |