Skip to content

⬅️ Back to Table of Contents

πŸ“„ no-implied-eval

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 6
πŸ“¦ Imports 6
πŸ“Š Variables & Constants 3

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/no-implied-eval.ts

πŸ“€ Default Export

export default createRule({ ... })
Property Value
name 'no-implied-eval'
meta.type 'suggestion'
meta.docs.description 'Disallow the use of eval()-like functions'
meta.docs.extendsBaseRule true
meta.docs.recommended 'recommended'
meta.docs.requiresTypeChecking true
meta.messages.noFunctionConstructor 'Implied eval. Do not use the Function constructor to create functions.'
meta.messages.noImpliedEvalError 'Implied eval. Consider passing a function.'
meta.schema []
defaultOptions []

Entry point: create β€” documented under Functions.


πŸ“¦ Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
createRule ../util
getParserServices ../util
isBuiltinSymbolLike ../util
isReferenceToGlobalFunction ../util

Variables & Constants

Name Type Kind Value Exported
FUNCTION_CONSTRUCTOR "Function" const 'Function' βœ—
GLOBAL_CANDIDATES Set<string> const new Set(['global', 'globalThis', 'window']) βœ—
EVAL_LIKE_FUNCTIONS Set<string> const new Set([ 'execScript', 'setImmediate', 'setInterval', 'setTimeout', ]) βœ—

Functions

create(context: any): { CallExpression: (node: TSESTree.CallExpression | TSESTree…

Parameters:

  • context any

Returns: { CallExpression: (node: TSESTree.CallExpression | TSESTree.NewExpression) => void; NewExpression: (node: TSESTree.CallExpression | TSESTree.NewExpression) => void; }

Calls:

  • getParserServices (from ../util)
  • services.program.getTypeChecker
  • GLOBAL_CANDIDATES.has
  • services.getTypeAtLocation
  • type.getSymbol
  • tsutils.isSymbolFlagSet
  • isBuiltinSymbolLike (from ../util)
  • checker.getSignaturesOfType
  • isBind
  • isFunctionType
  • getCalleeName
  • context.report
  • EVAL_LIKE_FUNCTIONS.has
  • isFunction
  • isReferenceToGlobalFunction (from ../util)
Code
create(context) {
    const services = getParserServices(context);
    const checker = services.program.getTypeChecker();

    function getCalleeName(node: TSESTree.Expression): string | null {
      if (node.type === AST_NODE_TYPES.Identifier) {
        return node.name;
      }

      if (
        node.type === AST_NODE_TYPES.MemberExpression &&
        node.object.type === AST_NODE_TYPES.Identifier &&
        GLOBAL_CANDIDATES.has(node.object.name)
      ) {
        if (node.property.type === AST_NODE_TYPES.Identifier) {
          return node.property.name;
        }

        if (
          node.property.type === AST_NODE_TYPES.Literal &&
          typeof node.property.value === 'string'
        ) {
          return node.property.value;
        }
      }

      return null;
    }

    function isFunctionType(node: TSESTree.Node): boolean {
      const type = services.getTypeAtLocation(node);
      const symbol = type.getSymbol();

      if (
        symbol &&
        tsutils.isSymbolFlagSet(
          symbol,
          ts.SymbolFlags.Function | ts.SymbolFlags.Method,
        )
      ) {
        return true;
      }

      if (isBuiltinSymbolLike(services.program, type, FUNCTION_CONSTRUCTOR)) {
        return true;
      }

      const signatures = checker.getSignaturesOfType(
        type,
        ts.SignatureKind.Call,
      );

      return signatures.length > 0;
    }

    function isBind(node: TSESTree.Node): boolean {
      return node.type === AST_NODE_TYPES.MemberExpression
        ? isBind(node.property)
        : node.type === AST_NODE_TYPES.Identifier && node.name === 'bind';
    }

    function isFunction(node: TSESTree.Node): boolean {
      switch (node.type) {
        case AST_NODE_TYPES.ArrowFunctionExpression:
        case AST_NODE_TYPES.FunctionDeclaration:
        case AST_NODE_TYPES.FunctionExpression:
          return true;

        case AST_NODE_TYPES.Literal:
        case AST_NODE_TYPES.TemplateLiteral:
          return false;

        case AST_NODE_TYPES.CallExpression:
          return isBind(node.callee) || isFunctionType(node);

        default:
          return isFunctionType(node);
      }
    }

    function checkImpliedEval(
      node: TSESTree.CallExpression | TSESTree.NewExpression,
    ): void {
      const calleeName = getCalleeName(node.callee);
      if (calleeName == null) {
        return;
      }

      if (calleeName === FUNCTION_CONSTRUCTOR) {
        const type = services.getTypeAtLocation(node.callee);
        const symbol = type.getSymbol();
        if (symbol) {
          if (
            isBuiltinSymbolLike(services.program, type, 'FunctionConstructor')
          ) {
            context.report({ node, messageId: 'noFunctionConstructor' });
            return;
          }
        } else {
          context.report({ node, messageId: 'noFunctionConstructor' });
          return;
        }
      }

      if (node.arguments.length === 0) {
        return;
      }

      const [handler] = node.arguments;
      if (
        EVAL_LIKE_FUNCTIONS.has(calleeName) &&
        !isFunction(handler) &&
        isReferenceToGlobalFunction(calleeName, node, context.sourceCode)
      ) {
        context.report({ node: handler, messageId: 'noImpliedEvalError' });
      }
    }

    return {
      CallExpression: checkImpliedEval,
      NewExpression: checkImpliedEval,
    };
  }

Internal helpers

Declared inside another function in this file.

getCalleeName(node: TSESTree.Expression): string | null

Parameters:

  • node TSESTree.Expression

Returns: string | null

Calls:

  • GLOBAL_CANDIDATES.has
Code
function getCalleeName(node: TSESTree.Expression): string | null {
      if (node.type === AST_NODE_TYPES.Identifier) {
        return node.name;
      }

      if (
        node.type === AST_NODE_TYPES.MemberExpression &&
        node.object.type === AST_NODE_TYPES.Identifier &&
        GLOBAL_CANDIDATES.has(node.object.name)
      ) {
        if (node.property.type === AST_NODE_TYPES.Identifier) {
          return node.property.name;
        }

        if (
          node.property.type === AST_NODE_TYPES.Literal &&
          typeof node.property.value === 'string'
        ) {
          return node.property.value;
        }
      }

      return null;
    }

isFunctionType(node: TSESTree.Node): boolean

Parameters:

  • node TSESTree.Node

Returns: boolean

Calls:

  • services.getTypeAtLocation
  • type.getSymbol
  • tsutils.isSymbolFlagSet
  • isBuiltinSymbolLike (from ../util)
  • checker.getSignaturesOfType
Code
function isFunctionType(node: TSESTree.Node): boolean {
      const type = services.getTypeAtLocation(node);
      const symbol = type.getSymbol();

      if (
        symbol &&
        tsutils.isSymbolFlagSet(
          symbol,
          ts.SymbolFlags.Function | ts.SymbolFlags.Method,
        )
      ) {
        return true;
      }

      if (isBuiltinSymbolLike(services.program, type, FUNCTION_CONSTRUCTOR)) {
        return true;
      }

      const signatures = checker.getSignaturesOfType(
        type,
        ts.SignatureKind.Call,
      );

      return signatures.length > 0;
    }

isBind(node: TSESTree.Node): boolean

Parameters:

  • node TSESTree.Node

Returns: boolean

Calls:

  • isBind
Code
function isBind(node: TSESTree.Node): boolean {
      return node.type === AST_NODE_TYPES.MemberExpression
        ? isBind(node.property)
        : node.type === AST_NODE_TYPES.Identifier && node.name === 'bind';
    }

isFunction(node: TSESTree.Node): boolean

Parameters:

  • node TSESTree.Node

Returns: boolean

Calls:

  • isBind
  • isFunctionType
Code
function isFunction(node: TSESTree.Node): boolean {
      switch (node.type) {
        case AST_NODE_TYPES.ArrowFunctionExpression:
        case AST_NODE_TYPES.FunctionDeclaration:
        case AST_NODE_TYPES.FunctionExpression:
          return true;

        case AST_NODE_TYPES.Literal:
        case AST_NODE_TYPES.TemplateLiteral:
          return false;

        case AST_NODE_TYPES.CallExpression:
          return isBind(node.callee) || isFunctionType(node);

        default:
          return isFunctionType(node);
      }
    }

checkImpliedEval(node: TSESTree.CallExpression | TSESTree.NewE…): void

Parameters:

  • node TSESTree.CallExpression | TSESTree.NewExpression

Returns: void

Calls:

  • getCalleeName
  • services.getTypeAtLocation
  • type.getSymbol
  • isBuiltinSymbolLike (from ../util)
  • context.report
  • EVAL_LIKE_FUNCTIONS.has
  • isFunction
  • isReferenceToGlobalFunction (from ../util)
Code
function checkImpliedEval(
      node: TSESTree.CallExpression | TSESTree.NewExpression,
    ): void {
      const calleeName = getCalleeName(node.callee);
      if (calleeName == null) {
        return;
      }

      if (calleeName === FUNCTION_CONSTRUCTOR) {
        const type = services.getTypeAtLocation(node.callee);
        const symbol = type.getSymbol();
        if (symbol) {
          if (
            isBuiltinSymbolLike(services.program, type, 'FunctionConstructor')
          ) {
            context.report({ node, messageId: 'noFunctionConstructor' });
            return;
          }
        } else {
          context.report({ node, messageId: 'noFunctionConstructor' });
          return;
        }
      }

      if (node.arguments.length === 0) {
        return;
      }

      const [handler] = node.arguments;
      if (
        EVAL_LIKE_FUNCTIONS.has(calleeName) &&
        !isFunction(handler) &&
        isReferenceToGlobalFunction(calleeName, node, context.sourceCode)
      ) {
        context.report({ node: handler, messageId: 'noImpliedEvalError' });
      }
    }

Generated by Syntax Scribe