AST Node Conditional Tester
The `ast-test` library provides a utility for conditionally evaluating individual nodes within an Abstract Syntax Tree (AST) against a set of user-defined rules. It operates on ASTs conforming to the ESTree specification, typically generated by parsers such as `esprima` or `@babel/parser`. Its core functionality revolves around a `test` function that evaluates a given AST node against a rule object. This object maps AST node types (e.g., `AssignmentExpression`, `Expression`) to predicate functions, which return `true` if the node matches the condition and `false` otherwise. Currently at version 1.1.1, the package had its last release in 2017. Given its age and complete lack of recent updates or maintenance, its release cadence is dormant, indicating it is an abandoned project. It offers a simple, rule-based approach for selective AST node inspection, which can be useful in niche scenarios for static analysis, linting, or identifying specific code patterns without full AST traversal utilities.
Common errors
-
ReferenceError: require is not defined in ES module scope
cause Attempting to use `require('ast-test')` directly within a JavaScript file that is treated as an ES module (e.g., due to `"type": "module"` in `package.json` or a `.mjs` extension).fixFor Node.js, rename your file to `.cjs` or change your `package.json` `"type"` field to `"commonjs"`. Alternatively, use `import { createRequire } from 'module'; const require = createRequire(import.meta.url); const test = require('ast-test');` in an ES module. -
TypeError: Cannot read properties of undefined (reading 'name') at AssignmentExpression
cause A rule function for a specific AST node type (e.g., `AssignmentExpression`) assumes a property exists (e.g., `node.left.name`), but the AST node passed to it, while matching the type, might have a different structure where that property is missing or `undefined` (e.g., `node.left` might be a `MemberExpression` or `ArrayPattern` instead of an `Identifier`).fixImplement robust checks within your rule functions to ensure properties exist before attempting to access them. For example, `if (node.left && node.left.type === 'Identifier' && node.left.name === 'foo')` instead of just `node.left.name === 'foo'`.
Warnings
- breaking The `ast-test` package is abandoned, with its last release in 2017. It is highly unlikely to be compatible with modern Node.js versions (e.g., Node.js 16+), newer JavaScript syntax features (e.g., private class fields, top-level await), or recent ESTree specification changes. Using it in a modern project may lead to parsing errors or unexpected behavior.
- gotcha This library is distributed exclusively as a CommonJS module. It does not provide an ESM export, meaning it cannot be directly `import`ed in an ES module environment without specific loader configurations or bundler adaptations, which is a common footgun for older packages.
- gotcha The package does not ship with TypeScript type definitions. Developers using TypeScript will need to create their own declaration files (`.d.ts`) to get type inference and checking, which increases development overhead and reduces type safety.
- gotcha The package displays an 'unstable' badge in its README, indicating it was never considered production-ready or feature-complete by its original author. This suggests potential for unannounced breaking changes, API instability, or unaddressed bugs even prior to its abandonment.
Install
-
npm install ast-test -
yarn add ast-test -
pnpm add ast-test
Imports
- test
import test from 'ast-test';
const test = require('ast-test');
Quickstart
const parse = require('esprima').parse;
const test = require('ast-test');
// Define a rule set to identify specific AST patterns.
// This rule will match 'AssignmentExpression' nodes where 'foo' is assigned
// and 'Literal' nodes with the value '1'.
const rules = {
AssignmentExpression: function (node) {
if (node.operator !== '=') return false;
// Ensure node.left is an Identifier and its name is 'foo'
return node.left && node.left.type === 'Identifier' && node.left.name === 'foo';
},
Expression: function (node) {
// A broader rule to catch Literal expressions with specific values.
// Note: 'Expression' is a supertype, so rules for specific subtypes like
// 'AssignmentExpression' will be checked first if defined.
return node.type === 'Literal' && node.value === 1;
}
};
// Test various AST nodes against the defined rules.
const ast1 = parse('foo = 1;').body[0]; // Variable assignment 'foo = 1;'
const ast2 = parse('var foo = 1;').body[0]; // Variable declaration 'var foo = 1;'
const ast3 = parse('bar = 2;').body[0]; // Variable assignment 'bar = 2;'
const ast4 = parse('1;').body[0].expression; // Literal expression '1;'
const ast5 = parse('2;').body[0].expression; // Literal expression '2;'
console.log("Testing 'foo = 1;' (AssignmentExpression):", test(ast1, rules)); // Expected: true
console.log("Testing 'var foo = 1;' (VariableDeclaration):", test(ast2, rules)); // Expected: false (not an AssignmentExpression)
console.log("Testing 'bar = 2;' (AssignmentExpression, different LHS):", test(ast3, rules)); // Expected: false
console.log("Testing '1;' (Literal Expression):", test(ast4, rules)); // Expected: true
console.log("Testing '2;' (Literal Expression):", test(ast5, rules)); // Expected: false