Scope Analyzer

2.1.2 · active · verified Sun Apr 19

scope-analyzer is a JavaScript library designed for performing basic scope analysis on JavaScript Abstract Syntax Trees (ASTs). It tracks variable scopes and collects references to variables within a given AST, enabling tasks like refactoring, renaming, and understanding variable usage patterns. The current stable version is 2.1.2. The package has seen consistent minor and patch releases, indicating active maintenance, though its stability badge still labels it as "experimental." A key differentiator is its focus on simplicity and direct manipulation of AST nodes, providing methods to crawl the tree, create, delete, and inspect scopes, and retrieve bindings and references. It is particularly useful for tools that need to understand the lexical environment of JavaScript code. It expects AST nodes to have a `.parent` property, often requiring a pre-processing step with utilities like `estree-assign-parent`.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to parse a JavaScript string into an AST using Acorn, prepare it for `scope-analyzer` (potentially by assigning parent nodes), then define global variables with `createScope` and analyze the AST with `crawl`. It illustrates how to retrieve a specific binding (e.g., `exports`) and iterate over its references, as well as how to find undeclared names within a given scope.

const parse = require('acorn').parse;
const scan = require('scope-analyzer');

// Example JavaScript source code
const code = `
  function greet(name) {
    const message = 'Hello, ' + name;
    console.log(message);
    exports.greeting = message; // Example of an 'exports' reference
  }
  greet('World');
  var globalVar = 10;
`;

// Parse the code into an AST. 'acorn' is a common choice.
// Ensure to specify ecmaVersion and sourceType for accurate parsing.
const ast = parse(code, { ecmaVersion: 2020, sourceType: 'script' });

// IMPORTANT: scope-analyzer expects AST nodes to have a `node.parent` property.
// Most parsers (like Acorn) do not add this by default.
// Uncomment the following line and install 'estree-assign-parent' if your AST lacks parent pointers:
// require('estree-assign-parent')(ast);

// Initialize the root scope with common Node.js global variables
// This makes 'exports' a known binding for analysis.
scan.createScope(ast, ['module', 'exports', '__dirname', '__filename', 'console']);

// Crawl the AST to analyze all scopes and collect variable references.
scan.crawl(ast);

// Example 1: Find all references to the 'exports' binding
const exportsBinding = scan.getBinding(ast, 'exports');

if (exportsBinding) {
  console.log('--- References to "exports" ---');
  exportsBinding.getReferences().forEach(function (reference) {
    // Assuming references like `exports.property = value`
    if (reference.parent && reference.parent.type === 'MemberExpression' && reference.parent.property) {
      console.log(`- Exported property: '${reference.parent.property.name}' at line ${reference.loc.start.line}`);
    } else {
      console.log(`- General reference at line ${reference.loc.start.line}`);
    }
  });
} else {
  console.log('No binding found for "exports".');
}

// Example 2: Find undeclared names in the root scope
const rootScope = scan.scope(ast);
if (rootScope) {
  const undeclared = rootScope.getUndeclaredNames();
  if (undeclared.length > 0) {
    console.log('\n--- Undeclared names in root scope ---');
    console.log(`- ${undeclared.join(', ')}`);
  } else {
    console.log('\nNo undeclared names found in root scope.');
  }
}

view raw JSON →