or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

ast-utils.mdindex.mdpattern-matching.mdreference-tracking.mdstatic-analysis.mdtoken-predicates.md
tile.json

reference-tracking.mddocs/

Reference Tracking

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.

Capabilities

Reference Tracker Class

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;
  };
}

Reference Type Constants

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.ESM

Usage Examples

Basic Global Reference Tracking

Track 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('.')}`);
        }
      }
    }
  };
}

CommonJS Module Tracking

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('.')}`);
        }
      }
    }
  };
}

ES Module Tracking

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('.')}`);
        }
      }
    }
  };
}

Advanced Trace Maps

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('.')}`
        });
      }
    }
  };
}

Tracking Destructured Imports

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]}`);
        }
      }
    }
  };
}

Configuration Options

Mode Setting

Control how the tracker handles import declarations:

  • "strict": Only track explicit default imports for CJS modules
  • "legacy": Track both default and named imports for CJS modules
const tracker = new ReferenceTracker(scope, { mode: "legacy" });

Global Object Names

Customize which global object names to consider:

const tracker = new ReferenceTracker(scope, {
  globalObjectNames: ["window", "global", "globalThis", "self"]
});

Common Patterns

Library Deprecation Warnings

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");
  }
}

Security Auditing

const traceMap = {
  "eval": { [CALL]: { security: "dangerous" } },
  "child_process": {
    exec: { [CALL]: { security: "review-required" } },
    spawn: { [CALL]: { security: "review-required" } }
  }
};

Performance Monitoring

const traceMap = {
  "heavy-library": {
    [READ]: { performance: "expensive" },
    heavyOperation: { [CALL]: { performance: "very-expensive" } }
  }
};