Utilities for ESLint plugins providing AST manipulation, static analysis, and rule development helpers.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Sophisticated system for tracking variable and module references across different import/export patterns. The ReferenceTracker class enables ESLint rules to understand cross-module dependencies and trace variable usage through complex import/export scenarios.
Core class for tracking references across modules and scopes.
/**
* The reference tracker for tracking variable references across modules
* @param globalScope - The global scope to start tracking from
* @param options - Optional configuration for tracking behavior
*/
class ReferenceTracker {
constructor(globalScope: Scope, options?: ReferenceTrackerOptions);
/**
* Iterate the references of global variables
* @param traceMap - Map defining what to track
* @returns Iterator of reference results
*/
iterateGlobalReferences(traceMap: TraceMap): IterableIterator<ReferenceResult>;
/**
* Iterate the references of CommonJS modules
* @param traceMap - Map defining what to track
* @returns Iterator of reference results
*/
iterateCjsReferences(traceMap: TraceMap): IterableIterator<ReferenceResult>;
/**
* Iterate the references of ES modules
* @param traceMap - Map defining what to track
* @returns Iterator of reference results
*/
iterateEsmReferences(traceMap: TraceMap): IterableIterator<ReferenceResult>;
}
interface ReferenceTrackerOptions {
mode?: "legacy" | "strict";
globalObjectNames?: string[];
}
interface ReferenceResult {
node: Node;
path: string[];
type: symbol;
info: any;
}
interface TraceMap {
[key: string]: {
[READ]?: any;
[CALL]?: any;
[CONSTRUCT]?: any;
[key: string]: TraceMap | any;
};
}Symbols used to specify what types of references to track.
/**
* Symbol representing read access tracking
*/
const READ: symbol;
/**
* Symbol representing function call tracking
*/
const CALL: symbol;
/**
* Symbol representing constructor call tracking
*/
const CONSTRUCT: symbol;
/**
* Symbol representing ECMAScript module tracking
*/
const ESM: symbol;Static Properties:
ReferenceTracker class also provides these constants as static properties:
/**
* Static property for read access tracking
*/
static READ: symbol;
/**
* Static property for function call tracking
*/
static CALL: symbol;
/**
* Static property for constructor call tracking
*/
static CONSTRUCT: symbol;
/**
* Static property for ECMAScript module tracking
*/
static ESM: symbol;Static Access:
// Available as static properties
ReferenceTracker.READ
ReferenceTracker.CALL
ReferenceTracker.CONSTRUCT
ReferenceTracker.ESMTrack usage of global variables and objects.
import { ReferenceTracker, READ, CALL } from "eslint-utils";
create(context) {
return {
Program() {
const scope = context.getScope();
const tracker = new ReferenceTracker(scope);
const traceMap = {
console: {
[READ]: true,
log: { [CALL]: true },
warn: { [CALL]: true },
error: { [CALL]: true }
},
setTimeout: { [CALL]: true },
setInterval: { [CALL]: true }
};
for (const { node, path, type } of tracker.iterateGlobalReferences(traceMap)) {
if (type === READ) {
context.report(node, `Reading global: ${path.join('.')}`);
} else if (type === CALL) {
context.report(node, `Calling global: ${path.join('.')}`);
}
}
}
};
}Track CommonJS require() calls and their usage.
import { ReferenceTracker, READ, CALL, CONSTRUCT } from "eslint-utils";
create(context) {
return {
Program() {
const scope = context.getScope();
const tracker = new ReferenceTracker(scope);
const traceMap = {
"lodash": {
[READ]: true,
map: { [CALL]: true },
filter: { [CALL]: true },
reduce: { [CALL]: true }
},
"express": {
[CALL]: true, // express()
Router: { [CONSTRUCT]: true } // new express.Router()
},
"fs": {
readFile: { [CALL]: true },
writeFile: { [CALL]: true }
}
};
for (const { node, path, type } of tracker.iterateCjsReferences(traceMap)) {
if (path[0] === "lodash" && type === CALL) {
context.report(node, `Using lodash.${path.slice(1).join('.')}`);
} else if (path[0] === "fs") {
context.report(node, `File system operation: ${path.join('.')}`);
}
}
}
};
}Track ES6 import statements and their usage.
import { ReferenceTracker, READ, CALL, ESM } from "eslint-utils";
create(context) {
return {
Program() {
const scope = context.getScope();
const tracker = new ReferenceTracker(scope);
const traceMap = {
"react": {
[ESM]: true, // Mark as ES module
createElement: { [CALL]: true },
useState: { [CALL]: true },
useEffect: { [CALL]: true },
Component: { [READ]: true }
},
"vue": {
[ESM]: true,
createApp: { [CALL]: true },
ref: { [CALL]: true },
computed: { [CALL]: true }
}
};
for (const { node, path, type } of tracker.iterateEsmReferences(traceMap)) {
if (path[0] === "react" && path[1] === "useState" && type === CALL) {
context.report(node, "useState hook detected");
} else if (path[0] === "vue" && type === CALL) {
context.report(node, `Vue composition API: ${path.slice(1).join('.')}`);
}
}
}
};
}Complex trace maps with nested structures.
import { ReferenceTracker, READ, CALL, CONSTRUCT } from "eslint-utils";
create(context) {
return {
Program() {
const scope = context.getScope();
const tracker = new ReferenceTracker(scope, {
mode: "strict",
globalObjectNames: ["window", "global", "globalThis"]
});
const traceMap = {
"axios": {
[CALL]: { info: "axios direct call" },
get: { [CALL]: { info: "axios.get" } },
post: { [CALL]: { info: "axios.post" } },
create: {
[CALL]: { info: "axios.create" },
// Track methods on axios instances
"*": {
get: { [CALL]: { info: "instance.get" } },
post: { [CALL]: { info: "instance.post" } }
}
}
},
"jquery": {
[CALL]: { info: "jQuery function" },
[READ]: { info: "jQuery object" },
ajax: { [CALL]: { info: "jQuery.ajax" } },
fn: {
[READ]: { info: "jQuery.fn" },
extend: { [CALL]: { info: "jQuery.fn.extend" } }
}
}
};
// Track CommonJS requires
for (const { node, path, type, info } of tracker.iterateCjsReferences(traceMap)) {
context.report({
node,
message: `${info}: ${path.join('.')} (${type.toString()})`
});
}
// Track ES module imports
for (const { node, path, type, info } of tracker.iterateEsmReferences(traceMap)) {
context.report({
node,
message: `ES Module ${info}: ${path.join('.')}`
});
}
}
};
}Handle destructuring patterns in imports.
import { ReferenceTracker, READ, CALL } from "eslint-utils";
create(context) {
return {
Program() {
const scope = context.getScope();
const tracker = new ReferenceTracker(scope);
// This will track:
// const { readFile, writeFile } = require('fs');
// import { useState, useEffect } from 'react';
const traceMap = {
"fs": {
readFile: { [CALL]: true },
writeFile: { [CALL]: true },
promises: {
readFile: { [CALL]: true },
writeFile: { [CALL]: true }
}
},
"react": {
[ESM]: true,
useState: { [CALL]: true },
useEffect: { [CALL]: true },
useMemo: { [CALL]: true }
}
};
for (const { node, path, type } of tracker.iterateCjsReferences(traceMap)) {
if (path.length > 1 && type === CALL) {
context.report(node, `Destructured call: ${path.join('.')}`);
}
}
for (const { node, path, type } of tracker.iterateEsmReferences(traceMap)) {
if (path[0] === "react" && type === CALL) {
context.report(node, `React hook: ${path[1]}`);
}
}
}
};
}Control how the tracker handles import declarations:
const tracker = new ReferenceTracker(scope, { mode: "legacy" });Customize which global object names to consider:
const tracker = new ReferenceTracker(scope, {
globalObjectNames: ["window", "global", "globalThis", "self"]
});const traceMap = {
"deprecated-lib": {
[READ]: { deprecated: true },
"*": { [CALL]: { deprecated: true } }
}
};
for (const { node, info } of tracker.iterateCjsReferences(traceMap)) {
if (info.deprecated) {
context.report(node, "This library is deprecated");
}
}const traceMap = {
"eval": { [CALL]: { security: "dangerous" } },
"child_process": {
exec: { [CALL]: { security: "review-required" } },
spawn: { [CALL]: { security: "review-required" } }
}
};const traceMap = {
"heavy-library": {
[READ]: { performance: "expensive" },
heavyOperation: { [CALL]: { performance: "very-expensive" } }
}
};