esgraph
Version:
creates a control flow graph from an esprima abstract syntax tree
64 lines (55 loc) • 1.53 kB
JavaScript
const { parse } = require('espree');
const walkes = require('walkes');
const esgraph = require('../');
process.stdin.resume();
process.stdin.setEncoding('utf8');
let data = '';
process.stdin.on('data', (chunk) => {
data += chunk;
});
process.stdin.on('end', () => {
let source = data;
// filter out hashbangs
if (source.startsWith('#!')) {
source = `//${source.substring(2)}`;
}
try {
const fullAst = parse(source, { range: true });
const functions = findFunctions(fullAst);
console.log('digraph cfg {');
console.log('node [shape="box"]');
const options = { counter: 0, source };
functions.concat(fullAst).forEach((ast, i) => {
let cfg;
let label = '[[main]]';
if (ast.type.includes('Function')) {
cfg = esgraph(ast.body);
const name = (ast.id && ast.id.name) || '';
const params = ast.params.map(p => p.name);
label = `function ${name}(${params})`;
} else {
cfg = esgraph(ast);
}
console.log(`subgraph cluster_${i}{`);
console.log(`label = "${label}"`);
console.log(esgraph.dot(cfg, options));
console.log('}');
});
console.log('}');
} catch (e) {
console.log(e.message);
}
});
function findFunctions(ast) {
const functions = [];
function handleFunction(node, recurse) {
functions.push(node);
recurse(node.body);
}
walkes(ast, {
FunctionDeclaration: handleFunction,
FunctionExpression: handleFunction,
});
return functions;
}