You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.8 KiB
JavaScript

'use strict';
const archy = require("archy");
const chalk = require("chalk");
const memoizee = require("memoizee");
const assureArray = require("assure-array");
const util = require("util");
const colorizedNodeType = require("./render/colorize-type");
const shortDescription = require("./render/short-description");
const sectionTag = require("./render/section-tag");
module.exports = function visualizeAST(ast) {
let indexedItems = []; // NOTE: Impure, but is necessary to make getItemAtIndex work...
function sectionLabel(name, items) {
return {
label: chalk.yellow(`${name}:`),
nodes: items
}
}
function convertChildNodes(key, childNodes) {
let arrayifiedNodes = assureArray(childNodes);
let treeNodes = arrayifiedNodes.map((node) => {
let treeNode = astNodeToTreeNode(node);
treeNode.label = sectionTag(key, {isArray: Array.isArray(childNodes)}) + " " + treeNode.label;
return treeNode;
});
return treeNodes;
}
function astNodeToTreeNode(astNode) {
indexedItems.push(astNode);
let nodeLabel = `${chalk.bold(colorizedNodeType(astNode))} ${shortDescription(astNode)}`;
let primitiveProperties = [], singleChildren = [], multipleChildren = [];
Object.keys(astNode).forEach((key) => {
if (key === "loc" || key === "range") {
/* These are Esprima annotations. */
return;
}
let value = astNode[key];
if (typeof value === "string" || typeof value === "boolean" || typeof value === "number" || value == null) {
primitiveProperties.push(key);
} else if (Array.isArray(value)) {
if (value.length > 0) {
multipleChildren.push(key);
}
} else if (typeof value === "object" && value.type != null) {
singleChildren.push(key);
} else {
throw new Error(`Encountered unrecognized value type in AST: ${typeof value} -- ${util.inspect(value)}`);
}
});
let childNodes = (singleChildren.concat(multipleChildren)).map((key) => {
return convertChildNodes(key, astNode[key]);
}).reduce((combined, array) => {
return combined.concat(array);
}, []);
return {
label: nodeLabel,
nodes: childNodes
}
}
return {
getString: memoizee(function getString() {
let treeNodes = astNodeToTreeNode(ast);
return archy(treeNodes);
}),
getLines: function getLines() {
return this.getString().split("\n");
},
getItemAtIndex: function getItemAtIndex(index) {
return indexedItems[index];
}
}
}