Babel plugin that throws compile-time errors on references to undeclared variables with helpful suggestions
npx @tessl/cli install tessl/npm-babel-plugin-undeclared-variables-check@6.22.0This Babel plugin provides compile-time validation for JavaScript code by detecting references to undeclared variables and throwing detailed error messages with helpful suggestions. It analyzes the abstract syntax tree during Babel's transformation process and throws ReferenceErrors with code frames pointing to undeclared variables, helping developers catch typos and missing declarations early in the build process.
npm install --save-dev babel-plugin-undeclared-variables-checkThis is a Babel plugin that is configured rather than imported directly in code:
.babelrc
{
"plugins": ["undeclared-variables-check"]
}For programmatic usage:
const babel = require("babel-core");
babel.transform(code, {
plugins: ["undeclared-variables-check"]
});The plugin automatically detects undeclared variables during compilation and throws helpful errors:
Input Code:
function calculateTotal(price, tax) {
return price + tex; // typo: 'tex' instead of 'tax'
}Plugin Output:
ReferenceError: Line 2: Reference to undeclared variable "tex" - did you mean "tax"?
1 | function calculateTotal(price, tax) {
> 2 | return price + tex;
| ^
3 | }{
"plugins": ["undeclared-variables-check"]
}babel --plugins undeclared-variables-check script.jsrequire("babel-core").transform(code, {
plugins: ["undeclared-variables-check"]
});The main export is a plugin factory function that creates a Babel plugin instance.
/**
* Creates a Babel plugin for detecting undeclared variables
* @param {Object} options - Babel plugin options
* @param {Messages} options.messages - Babel message localization object
* @returns {BabelPlugin} Babel plugin object with visitor pattern
*/
function pluginFactory({ messages }): BabelPlugin;The plugin implements the Babel visitor pattern to process AST nodes.
interface BabelPlugin {
visitor: {
ReferencedIdentifier(path: NodePath): void;
};
}Processes each referenced identifier to check for undeclared variables.
/**
* Babel AST visitor method that processes ReferencedIdentifier nodes
* @param {Object} path - Babel AST path object
* @param {Object} path.node - The AST node being visited
* @param {Object} path.scope - Scope information for the current context
* @throws {ReferenceError} When undeclared variable is found
*/
ReferencedIdentifier(path: {
node: { name: string },
scope: BabelScope,
buildCodeFrameError: (message: string, ErrorType: Function) => Error,
parentPath: { isFlow(): boolean }
}): void;The plugin throws ReferenceError exceptions with detailed code frames in these cases:
When a variable is referenced but not declared in any accessible scope:
// Input
function test() {
return undeclaredVar; // throws ReferenceError
}
// Error: ReferenceError: Reference to undeclared variable "undeclaredVar"When a similar variable name exists (Levenshtein distance ≤ 3):
// Input
function test() {
const userName = "john";
return username; // typo: lowercase 'n'
}
// Error: ReferenceError: Reference to undeclared variable "username" - did you mean "userName"?When Flow type bindings are used outside type annotations:
// Input (with Flow)
type MyType = string;
const value: MyType = "test"; // correct usage
const invalid = MyType; // incorrect - throws undeclaredVariableType error
// Error: ReferenceError: Reference to undeclared variable type "MyType"The plugin uses the Levenshtein distance algorithm (via the leven package) to suggest corrections:
The plugin analyzes variable scope using Babel's scope system:
scope.hasBinding() to verify variable declarationbinding.kind === "type" to identify Flow typespath.parentPath.isFlow() to verify Flow annotation contextscope.getAllBindings() to get suggestion candidatesThe plugin uses specific message keys from Babel's message system:
/**
* Message keys used by the plugin for error reporting
*/
interface PluginMessageKeys {
/** "Reference to undeclared variable $1" */
undeclaredVariable: string;
/** "Referencing a type alias outside of a type annotation" */
undeclaredVariableType: string;
/** "Reference to undeclared variable $1 - did you mean $2?" */
undeclaredVariableSuggestion: string;
}/**
* Levenshtein distance calculation for variable name suggestions
* @param {string} a - First string
* @param {string} b - Second string
* @returns {number} Edit distance between strings
*/
import leven from "leven";Package: leven@^1.0.2
Purpose: Calculate string similarity for generating variable name suggestions
Usage: leven(undeclaredVar, candidateVar) returns edit distance
The plugin integrates with Babel's message system for localized error reporting:
/**
* Example usage of Babel's message system within the plugin
*/
const errorMessage = messages.get("undeclaredVariable", variableName);
const suggestionMessage = messages.get("undeclaredVariableSuggestion", variableName, suggestion);
const typeMessage = messages.get("undeclaredVariableType", variableName);interface BabelScope {
/**
* Check if a variable name has a binding in current or parent scopes
* @param {string} name - Variable name to check
* @returns {boolean} True if binding exists
*/
hasBinding(name: string): boolean;
/**
* Get binding information for a variable name
* @param {string} name - Variable name
* @returns {Binding|undefined} Binding object or undefined if not found
*/
getBinding(name: string): Binding | undefined;
/**
* Get all variable bindings in current scope
* @returns {Object} Object with variable names as keys
*/
getAllBindings(): Record<string, Binding>;
}
interface Binding {
/** Type of binding: "var", "let", "const", "param", "type", etc. */
kind: string;
}
interface Messages {
/**
* Get localized message with placeholder substitution
* @param {string} key - Message key
* @param {...any} args - Arguments to substitute in message placeholders
* @returns {string} Formatted message string
*/
get(key: string, ...args: any[]): string;
}
interface NodePath {
/** AST node being visited */
node: { name: string };
/** Scope information for current context */
scope: BabelScope;
/** Parent path for context checking */
parentPath: { isFlow(): boolean };
/** Build error with code frame */
buildCodeFrameError(message: string, ErrorType: Function): Error;
}This plugin is designed for development workflows and should be included in development builds only:
{
"env": {
"development": {
"plugins": ["undeclared-variables-check"]
}
}
}The plugin helps catch errors early in the development cycle, preventing runtime ReferenceError exceptions from reaching production code.