Instrument JavaScript code

Have you ever wondered how code coverage tools are getting various values out of the code? AST is the answer. Instrumentation is basically wrapping parts of code with special functions which will collect information about how code is being executed.

Let’s see how to log execution order of JavaScript code. We will use JavaScript parser, traversal lib, code generator and AST types helper lib.

import { builders as b, namedTypes as n} from 'ast-types';
import { replace } from 'estraverse';
import { parse } from 'acorn';
import { generate } from 'escodegen';
function wrap(fnName, code) {
  const visited = [];
  // Parse JavaScript into AST
const ast = parse(code, { ecmaVersion: 6 });
  // Traverse syntax tree
const instrumentedAST = replace(ast, {

enter(node) {
      // If the current node is a fn call
// and we haven't visited it yet,
// wrap it with `log` fn call,
//add fn name to the list of arguments
// and add the node to the list of visited nodes
if (n.CallExpression.check(node) && !visited.includes(node)) {
return b.callExpression(
[, node]);
  // Generate and return JavaScript code out of modified AST
return generate(instrumentedAST);

We need a wrapper function which will be used in instrumented code. The first parameter is the name of the function which is being executed and the second one is the returning value of that function. Wrapping function must always return returned value, because we don’t want to break the code.

function log(name, x) {

console.log(name, x);

return x;

Evaluating instrumented code will log into the console pairs of function name which was called during execution and its returning value.

const instrumentedCode = wrap('log',
'function add(1, b) { return a + b; } add(1, add(2, 3););');

eval(instrumentedCode); // add 5, add 6

Code instrumentation can be used not only for code coverage and logging, but also for visualisation of execution. Check the tool called loupe. Press Save + Run button and watch how code is executed step by step.