CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-typescript-eslint--experimental-utils

(Experimental) Utilities for working with TypeScript + ESLint together

Pending
Overview
Eval results
Files

ast-utils.mddocs/

AST Utilities

Tools for manipulating and analyzing TypeScript Abstract Syntax Trees, including type guards, predicates, helper functions, and pattern matching utilities.

Capabilities

Node Type Guards

Type guards for checking AST node types with full TypeScript type safety.

/**
 * Creates a type guard function for a specific AST node type
 * @param nodeType - The AST node type to check for
 * @returns Type guard function that narrows the node type
 */
function isNodeOfType<NodeType extends TSESTree.AST_NODE_TYPES>(
  nodeType: NodeType
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeType }>;

/**
 * Creates a type guard function for multiple AST node types
 * @param nodeTypes - Array of AST node types to check for
 * @returns Type guard function that narrows to one of the specified types
 */
function isNodeOfTypes<NodeTypes extends readonly TSESTree.AST_NODE_TYPES[]>(
  nodeTypes: NodeTypes
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeTypes[number] }>;

/**
 * Creates a conditional type guard with additional constraints
 * @param nodeType - The AST node type to check for
 * @param conditions - Additional property conditions to match
 * @returns Type guard function with type and condition checking
 */
function isNodeOfTypeWithConditions<
  NodeType extends TSESTree.AST_NODE_TYPES,
  Conditions extends Partial<Extract<TSESTree.Node, { type: NodeType }>>
>(
  nodeType: NodeType,
  conditions: Conditions
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeType }> & Conditions;

/**
 * Creates a conditional type guard for tokens
 * @param tokenType - Token type to check for
 * @param conditions - Additional token conditions
 * @returns Type guard function for tokens
 */
function isTokenOfTypeWithConditions<
  TokenType extends TSESTree.AST_TOKEN_TYPES,
  Conditions extends Partial<Extract<TSESTree.Token, { type: TokenType }>>
>(
  tokenType: TokenType,
  conditions: Conditions
): (token: TSESTree.Token | null | undefined) => token is Extract<TSESTree.Token, { type: TokenType }> & Conditions;

/**
 * Creates a negated conditional type guard for tokens
 * @param tokenType - Token type to exclude
 * @param conditions - Additional token conditions to exclude
 * @returns Negated type guard function
 */
function isNotTokenOfTypeWithConditions<
  TokenType extends TSESTree.AST_TOKEN_TYPES,
  Conditions extends Partial<Extract<TSESTree.Token, { type: TokenType }>>
>(
  tokenType: TokenType,
  conditions: Conditions
): (token: TSESTree.Token | null | undefined) => token is Exclude<TSESTree.Token, Extract<TSESTree.Token, { type: TokenType }> & Conditions>;

Node Predicates

Predicate functions for identifying specific types of AST nodes.

/**
 * Checks if a node is an optional call expression (foo?.())
 */
function isOptionalCallExpression(node: TSESTree.Node | null | undefined): node is TSESTree.CallExpression & { optional: true };

/**
 * Checks if a node is a logical OR operator (||)
 */
function isLogicalOrOperator(node: TSESTree.Node | null | undefined): node is TSESTree.LogicalExpression & { operator: '||' };

/**
 * Checks if a node is a type assertion (x as foo or <foo>x)
 */
function isTypeAssertion(node: TSESTree.Node | null | undefined): node is TSESTree.TSTypeAssertion | TSESTree.TSAsExpression;

/**
 * Checks if a node is a variable declarator
 */
function isVariableDeclarator(node: TSESTree.Node | null | undefined): node is TSESTree.VariableDeclarator;

/**
 * Checks if a node is any kind of function (declaration, expression, or arrow)
 */
function isFunction(node: TSESTree.Node | null | undefined): node is TSESTree.FunctionLike;

/**
 * Checks if a node is a function type
 */
function isFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.TSFunctionType | TSESTree.TSConstructorType;

/**
 * Checks if a node is a function or function type
 */
function isFunctionOrFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.FunctionLike | TSESTree.TSFunctionType | TSESTree.TSConstructorType;

/**
 * Checks if a node is a TypeScript function type
 */
function isTSFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.TSFunctionType;

/**
 * Checks if a node is a TypeScript constructor type
 */
function isTSConstructorType(node: TSESTree.Node | null | undefined): node is TSESTree.TSConstructorType;

/**
 * Checks if a node is a class or type element
 */
function isClassOrTypeElement(node: TSESTree.Node | null | undefined): node is TSESTree.ClassElement | TSESTree.TypeElement;

/**
 * Checks if a node is a constructor method
 */
function isConstructor(node: TSESTree.Node | null | undefined): node is TSESTree.MethodDefinition & { key: TSESTree.Identifier & { name: 'constructor' } };

/**
 * Checks if a node is a setter method
 */
function isSetter(node: TSESTree.Node | null | undefined): node is TSESTree.MethodDefinition & { kind: 'set' } | TSESTree.Property & { kind: 'set' };

/**
 * Checks if a node is an identifier
 */
function isIdentifier(node: TSESTree.Node | null | undefined): node is TSESTree.Identifier;

/**
 * Checks if a node is an await expression
 */
function isAwaitExpression(node: TSESTree.Node | null | undefined): node is TSESTree.AwaitExpression;

/**
 * Checks if a node is a loop statement
 */
function isLoop(node: TSESTree.Node | null | undefined): node is TSESTree.DoWhileStatement | TSESTree.ForStatement | TSESTree.ForInStatement | TSESTree.ForOfStatement | TSESTree.WhileStatement;

Token Predicates

Predicate functions for identifying specific types of tokens.

/**
 * Checks if a token is an optional chain punctuator (?.)
 */
function isOptionalChainPunctuator(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '?.' };

/**
 * Checks if a token is NOT an optional chain punctuator
 */
function isNotOptionalChainPunctuator(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '?.' }>;

/**
 * Checks if a token is a non-null assertion punctuator (!)
 */
function isNonNullAssertionPunctuator(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '!' };

/**
 * Checks if a token is NOT a non-null assertion punctuator
 */
function isNotNonNullAssertionPunctuator(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '!' }>;

/**
 * Checks if a token is an await keyword
 */
function isAwaitKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'await' };

/**
 * Checks if a token is a type keyword
 */
function isTypeKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'type' };

/**
 * Checks if a token is an import keyword
 */
function isImportKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'import' };

/**
 * Checks if a token is an arrow function token (=>)
 */
function isArrowToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '=>' };

/**
 * Checks if a token is NOT an arrow function token
 */
function isNotArrowToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '=>' }>;

/**
 * Checks if a token is a closing brace (})
 */
function isClosingBraceToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '}' };

/**
 * Checks if a token is NOT a closing brace
 */
function isNotClosingBraceToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '}' }>;

/**
 * Checks if a token is a closing bracket (])
 */
function isClosingBracketToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ']' };

/**
 * Checks if a token is NOT a closing bracket
 */
function isNotClosingBracketToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ']' }>;

/**
 * Checks if a token is a closing parenthesis ())
 */
function isClosingParenToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ')' };

/**
 * Checks if a token is NOT a closing parenthesis
 */
function isNotClosingParenToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ')' }>;

/**
 * Checks if a token is a colon (:)
 */
function isColonToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ':' };

/**
 * Checks if a token is NOT a colon
 */
function isNotColonToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ':' }>;

/**
 * Checks if a token is a comma (,)
 */
function isCommaToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ',' };

/**
 * Checks if a token is NOT a comma
 */
function isNotCommaToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ',' }>;

/**
 * Checks if a token is a comment token
 */
function isCommentToken(token: TSESTree.Token | null | undefined): token is TSESTree.Comment;

/**
 * Checks if a token is NOT a comment token
 */
function isNotCommentToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.Comment>;

/**
 * Checks if a token is an opening brace ({)
 */
function isOpeningBraceToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '{' };

/**
 * Checks if a token is NOT an opening brace
 */
function isNotOpeningBraceToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '{' }>;

/**
 * Checks if a token is an opening bracket ([)
 */
function isOpeningBracketToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '[' };

/**
 * Checks if a token is NOT an opening bracket
 */
function isNotOpeningBracketToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '[' }>;

/**
 * Checks if a token is an opening parenthesis (()
 */
function isOpeningParenToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '(' };

/**
 * Checks if a token is NOT an opening parenthesis
 */
function isNotOpeningParenToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '(' }>;

/**
 * Checks if a token is a semicolon (;)
 */
function isSemicolonToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ';' };

/**
 * Checks if a token is NOT a semicolon
 */
function isNotSemicolonToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: ';' }>;

Miscellaneous Utilities

Helper functions for common AST analysis tasks.

/**
 * Regular expression for matching line breaks
 */
const LINEBREAK_MATCHER: RegExp; // /\r\n|[\r\n\u2028\u2029]/

/**
 * Determines whether two adjacent AST nodes or tokens are on the same line
 * @param left - Left node or token
 * @param right - Right node or token
 * @returns True if both are on the same line
 */
function isTokenOnSameLine(
  left: TSESTree.Node | TSESTree.Token, 
  right: TSESTree.Node | TSESTree.Token
): boolean;

ESLint-specific AST Utilities

Advanced utilities for ESLint rule development.

/**
 * Gets the function head location for reporting purposes
 * @param node - Function-like node
 * @param sourceCode - ESLint source code object
 * @returns Location object suitable for error reporting
 */
function getFunctionHeadLocation(
  node: TSESTree.FunctionLike, 
  sourceCode: TSESLint.SourceCode
): TSESTree.SourceLocation;

/**
 * Gets the function name with its kind (e.g. "function foo", "method bar")
 * @param node - Function-like node
 * @param sourceCode - Optional source code object for getting text
 * @returns Descriptive function name string
 */
function getFunctionNameWithKind(
  node: TSESTree.FunctionLike, 
  sourceCode?: TSESLint.SourceCode
): string;

/**
 * Gets the property name from property-like nodes
 * @param node - Property-like AST node
 * @param initialScope - Optional initial scope for evaluation
 * @returns Property name string or null if not determinable
 */
function getPropertyName(
  node: TSESTree.PropertyLike, 
  initialScope?: TSESLintScope.Scope
): string | null;

/**
 * Gets the static value of an expression if it can be determined
 * @param node - Expression node to evaluate
 * @param initialScope - Optional initial scope for evaluation
 * @returns Object with value and whether it's static, or null
 */
function getStaticValue(
  node: TSESTree.Node, 
  initialScope?: TSESLintScope.Scope
): { value: unknown; static: boolean } | null;

/**
 * Gets string value if the expression evaluates to a constant string
 * @param node - Expression node to evaluate
 * @param initialScope - Optional initial scope for evaluation
 * @returns String value or null if not a constant string
 */
function getStringIfConstant(
  node: TSESTree.Node, 
  initialScope?: TSESLintScope.Scope
): string | null;

/**
 * Checks if a node has side effects when executed
 * @param node - Node to check for side effects
 * @param sourceCode - Source code object for analysis
 * @param options - Optional configuration for side effect analysis
 * @returns True if the node may have side effects
 */
function hasSideEffect(
  node: TSESTree.Node, 
  sourceCode: TSESLint.SourceCode, 
  options?: { considerGetters?: boolean; considerImplicitTypeConversion?: boolean }
): boolean;

/**
 * Checks if a node is wrapped in parentheses
 * @param node - Node to check
 * @param sourceCode - Source code object
 * @returns True if the node is parenthesized
 */
function isParenthesized(
  node: TSESTree.Node, 
  sourceCode: TSESLint.SourceCode
): boolean;

Pattern Matching

Advanced pattern matching utilities for complex AST analysis.

/**
 * Pattern matcher class for advanced string pattern matching with escape sequences
 */
class PatternMatcher {
  /**
   * Creates a new pattern matcher
   * @param pattern - Pattern string with escape sequences
   * @param options - Optional configuration
   */
  constructor(pattern: string, options?: { unicode?: boolean; sticky?: boolean });

  /**
   * Executes the pattern against input and returns all matches
   * @param input - Input string to match against
   * @returns Array of match results
   */
  execAll(input: string): RegExpExecArray[];

  /**
   * Tests if the pattern matches the input
   * @param input - Input string to test
   * @returns True if pattern matches
   */
  test(input: string): boolean;

  /**
   * Symbol.replace implementation for use with String.replace()
   */
  [Symbol.replace](input: string, replacement: string): string;
}

Reference Tracking

Utilities for tracking variable and import references across scopes.

/**
 * Reference tracker for following imports and variable usage
 */
class ReferenceTracker {
  /**
   * Creates a new reference tracker
   * @param globalScope - Global scope to start tracking from
   */
  constructor(globalScope: TSESLintScope.GlobalScope);

  /**
   * Iterates over global references
   * @param traceMap - Map of global references to trace
   * @returns Iterator of found references
   */
  iterateGlobalReferences<T>(
    traceMap: ReferenceTracker.TraceMap<T>
  ): IterableIterator<ReferenceTracker.FoundReference<T>>;

  /**
   * Iterates over CommonJS references
   * @param traceMap - Map of CJS references to trace
   * @returns Iterator of found references
   */
  iterateCjsReferences<T>(
    traceMap: ReferenceTracker.TraceMap<T>
  ): IterableIterator<ReferenceTracker.FoundReference<T>>;

  /**
   * Iterates over ESM references
   * @param traceMap - Map of ESM references to trace
   * @returns Iterator of found references
   */
  iterateEsmReferences<T>(
    traceMap: ReferenceTracker.TraceMap<T>
  ): IterableIterator<ReferenceTracker.FoundReference<T>>;
}

namespace ReferenceTracker {
  const READ: unique symbol;      // Read reference type
  const CALL: unique symbol;      // Call reference type
  const CONSTRUCT: unique symbol; // Constructor reference type
  const ESM: unique symbol;       // ESM import type

  interface TraceMap<T> {
    [key: string]: TraceMapElement<T>;
  }

  type TraceMapElement<T> = 
    | T 
    | { [READ]?: T }
    | { [CALL]?: T }
    | { [CONSTRUCT]?: T }
    | { [ESM]?: true }
    | TraceMap<T>;

  interface FoundReference<T> {
    node: TSESTree.Node;
    path: readonly string[];
    type: typeof READ | typeof CALL | typeof CONSTRUCT;
    info: T;
  }
}

Scope Analysis Helpers

Utilities for working with variable scopes and finding variables.

/**
 * Finds a variable in the given scope or parent scopes
 * @param initialScope - Scope to start searching from
 * @param nameOrNode - Variable name string or identifier node
 * @returns Variable object if found, null otherwise
 */
function findVariable(
  initialScope: TSESLintScope.Scope, 
  nameOrNode: TSESTree.Identifier | string
): TSESLintScope.Variable | null;

/**
 * Gets the innermost scope that contains the given node
 * @param initialScope - Scope to start searching from
 * @param node - AST node to find scope for
 * @returns Innermost scope containing the node
 */
function getInnermostScope(
  initialScope: TSESLintScope.Scope, 
  node: TSESTree.Node
): TSESLintScope.Scope;

Usage Examples

import { ASTUtils, TSESTree, TSESLint } from "@typescript-eslint/experimental-utils";

// Using type guards
function checkNode(node: TSESTree.Node): void {
  if (ASTUtils.isFunction(node)) {
    // node is now typed as TSESTree.FunctionLike
    console.log('Found function:', node.type);
  }
  
  if (ASTUtils.isNodeOfType(TSESTree.AST_NODE_TYPES.CallExpression)(node)) {
    // node is now typed as TSESTree.CallExpression
    console.log('Found call expression');
  }
}

// Using predicates in a rule
const rule: TSESLint.RuleModule<'error', []> = {
  meta: {
    type: 'problem',
    messages: { error: 'Message' },
    schema: []
  },
  create(context) {
    return {
      CallExpression(node) {
        if (ASTUtils.isOptionalCallExpression(node)) {
          context.report({ node, messageId: 'error' });
        }
      }
    };
  }
};

// Using pattern matching
const matcher = new ASTUtils.PatternMatcher('console\\.log\\((.*)\\)');
const matches = matcher.execAll(sourceCode);

// Using reference tracking
const tracker = new ASTUtils.ReferenceTracker(context.getScope());
const traceMap = {
  console: {
    log: { [ASTUtils.ReferenceTracker.CALL]: true }
  }
};

for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
  context.report({ node, messageId: 'error' });
}

Install with Tessl CLI

npx tessl i tessl/npm-typescript-eslint--experimental-utils

docs

ast-utils.md

eslint-utils.md

index.md

json-schema.md

scope-analysis.md

ts-eslint.md

ts-estree.md

tile.json