Skip to content

⬅️ Back to Table of Contents

πŸ“„ init-declarations

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 5
πŸ“¦ Imports 6
πŸ“‘ Type Aliases 2

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/init-declarations.ts

πŸ“€ Default Export

export default createRule<Options, MessageIds>({ ... })
Property Value
name 'init-declarations'
meta.type 'suggestion'
meta.docs.description 'Require or disallow initialization in variable declarations'
meta.docs.extendsBaseRule true
meta.docs.frozen true
meta.hasSuggestions baseRule.meta.hasSuggestions
meta.messages baseRule.meta.messages
meta.schema baseRule.meta.schema
defaultOptions ['always']

Entry point: create β€” documented under Functions.


πŸ“¦ Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
InferMessageIdsTypeFromRule ../util
InferOptionsTypeFromRule ../util
createRule ../util
getESLintCoreRule ../util/getESLintCoreRule

Functions

create(context: any, [mode]: any): { 'VariableDeclaration:exit'(node: TSESTree.VariableDeclara…

Parameters:

  • context any
  • [mode] any

Returns: { 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void; }

Calls:

  • context.report
  • getReportLoc
  • Reflect.get
  • baseRule.create
  • getBaseContextOverride
  • isAncestorNamespaceDeclared
  • complex_call_3187

Internal Comments:

// Make a custom context to adjust the loc of reports where the base
// rule's behavior is a bit too aggressive with TS-specific syntax (namely,
// type annotations).
// We only want to special case the report loc when reporting on
// variables declarations that are not initialized. Declarations that
// _are_ initialized get reported by the base rule due to a setting to
// prohibit initializing variables entirely, in which case underlining
// the whole node including the type annotation and initializer is
// appropriate.
// `return { ...context, report: reportOverride }` isn't safe because the
// `context` object has some getters that need to be preserved.
// (x2)
// `return new Proxy(context, ...)` doesn't work because `context` has
// non-configurable properties that throw when constructing a Proxy.
// So, we'll just use Proxy on a dummy object and use the `get` trap to
// proxy `context`'s properties.

Code
create(context, [mode]) {
    // Make a custom context to adjust the loc of reports where the base
    // rule's behavior is a bit too aggressive with TS-specific syntax (namely,
    // type annotations).
    function getBaseContextOverride(): typeof context {
      const reportOverride: typeof context.report = descriptor => {
        if ('node' in descriptor && descriptor.loc == null) {
          const { node, ...rest } = descriptor;
          // We only want to special case the report loc when reporting on
          // variables declarations that are not initialized. Declarations that
          // _are_ initialized get reported by the base rule due to a setting to
          // prohibit initializing variables entirely, in which case underlining
          // the whole node including the type annotation and initializer is
          // appropriate.
          if (
            node.type === AST_NODE_TYPES.VariableDeclarator &&
            node.init == null
          ) {
            context.report({
              ...rest,
              loc: getReportLoc(node),
            });
            return;
          }
        }

        context.report(descriptor);
      };

      // `return { ...context, report: reportOverride }` isn't safe because the
      // `context` object has some getters that need to be preserved.
      //
      // `return new Proxy(context, ...)` doesn't work because `context` has
      // non-configurable properties that throw when constructing a Proxy.
      //
      // So, we'll just use Proxy on a dummy object and use the `get` trap to
      // proxy `context`'s properties.
      return new Proxy({} as typeof context, {
        get: (target, prop, receiver): unknown =>
          prop === 'report'
            ? reportOverride
            : Reflect.get(context, prop, receiver),
      });
    }

    const rules = baseRule.create(getBaseContextOverride());

    return {
      'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void {
        if (mode === 'always') {
          if (node.declare) {
            return;
          }
          if (isAncestorNamespaceDeclared(node)) {
            return;
          }
        }

        rules['VariableDeclaration:exit'](node);
      },
    };

    function isAncestorNamespaceDeclared(
      node: TSESTree.VariableDeclaration,
    ): boolean {
      let ancestor: TSESTree.Node | undefined = node.parent;

      while (ancestor) {
        if (
          ancestor.type === AST_NODE_TYPES.TSModuleDeclaration &&
          ancestor.declare
        ) {
          return true;
        }

        ancestor = ancestor.parent;
      }

      return false;
    }
  }

getReportLoc(node: TSESTree.VariableDeclarator): TSESTree.SourceLocation

When reporting an uninitialized variable declarator, get the loc excluding the type annotation.

Raw JSDoc
/**
 * When reporting an uninitialized variable declarator, get the loc excluding
 * the type annotation.
 */

Calls:

  • structuredClone

Internal Comments:

// `if (id.type === AST_NODE_TYPES.Identifier)` is a condition for (x2)
// reporting in the base rule (as opposed to things like destructuring (x2)
// assignment), so the type assertion should always be valid. (x2)

Code
function getReportLoc(
  node: TSESTree.VariableDeclarator,
): TSESTree.SourceLocation {
  const start: TSESTree.Position = structuredClone(node.loc.start);
  const end: TSESTree.Position = {
    line: node.loc.start.line,
    // `if (id.type === AST_NODE_TYPES.Identifier)` is a condition for
    // reporting in the base rule (as opposed to things like destructuring
    // assignment), so the type assertion should always be valid.
    column:
      node.loc.start.column + (node.id as TSESTree.Identifier).name.length,
  };

  return {
    start,
    end,
  };
}

Internal helpers

Declared inside another function in this file.

getBaseContextOverride(): typeof context

Returns: typeof context

Calls:

  • context.report
  • getReportLoc
  • Reflect.get

Internal Comments:

// We only want to special case the report loc when reporting on
// variables declarations that are not initialized. Declarations that
// _are_ initialized get reported by the base rule due to a setting to
// prohibit initializing variables entirely, in which case underlining
// the whole node including the type annotation and initializer is
// appropriate.
// `return { ...context, report: reportOverride }` isn't safe because the
// `context` object has some getters that need to be preserved.
// (x2)
// `return new Proxy(context, ...)` doesn't work because `context` has
// non-configurable properties that throw when constructing a Proxy.
// So, we'll just use Proxy on a dummy object and use the `get` trap to
// proxy `context`'s properties.

Code
function getBaseContextOverride(): typeof context {
      const reportOverride: typeof context.report = descriptor => {
        if ('node' in descriptor && descriptor.loc == null) {
          const { node, ...rest } = descriptor;
          // We only want to special case the report loc when reporting on
          // variables declarations that are not initialized. Declarations that
          // _are_ initialized get reported by the base rule due to a setting to
          // prohibit initializing variables entirely, in which case underlining
          // the whole node including the type annotation and initializer is
          // appropriate.
          if (
            node.type === AST_NODE_TYPES.VariableDeclarator &&
            node.init == null
          ) {
            context.report({
              ...rest,
              loc: getReportLoc(node),
            });
            return;
          }
        }

        context.report(descriptor);
      };

      // `return { ...context, report: reportOverride }` isn't safe because the
      // `context` object has some getters that need to be preserved.
      //
      // `return new Proxy(context, ...)` doesn't work because `context` has
      // non-configurable properties that throw when constructing a Proxy.
      //
      // So, we'll just use Proxy on a dummy object and use the `get` trap to
      // proxy `context`'s properties.
      return new Proxy({} as typeof context, {
        get: (target, prop, receiver): unknown =>
          prop === 'report'
            ? reportOverride
            : Reflect.get(context, prop, receiver),
      });
    }

reportOverride(descriptor: any): void

Parameters:

  • descriptor any

Returns: void

Calls:

  • context.report
  • getReportLoc

Internal Comments:

// We only want to special case the report loc when reporting on
// variables declarations that are not initialized. Declarations that
// _are_ initialized get reported by the base rule due to a setting to
// prohibit initializing variables entirely, in which case underlining
// the whole node including the type annotation and initializer is
// appropriate.

Code
descriptor => {
        if ('node' in descriptor && descriptor.loc == null) {
          const { node, ...rest } = descriptor;
          // We only want to special case the report loc when reporting on
          // variables declarations that are not initialized. Declarations that
          // _are_ initialized get reported by the base rule due to a setting to
          // prohibit initializing variables entirely, in which case underlining
          // the whole node including the type annotation and initializer is
          // appropriate.
          if (
            node.type === AST_NODE_TYPES.VariableDeclarator &&
            node.init == null
          ) {
            context.report({
              ...rest,
              loc: getReportLoc(node),
            });
            return;
          }
        }

        context.report(descriptor);
      }

isAncestorNamespaceDeclared(node: TSESTree.VariableDeclaration): boolean

Parameters:

  • node TSESTree.VariableDeclaration

Returns: boolean

Code
function isAncestorNamespaceDeclared(
      node: TSESTree.VariableDeclaration,
    ): boolean {
      let ancestor: TSESTree.Node | undefined = node.parent;

      while (ancestor) {
        if (
          ancestor.type === AST_NODE_TYPES.TSModuleDeclaration &&
          ancestor.declare
        ) {
          return true;
        }

        ancestor = ancestor.parent;
      }

      return false;
    }

Type Aliases

Options

type Options = InferOptionsTypeFromRule<typeof baseRule>;

MessageIds

type MessageIds = InferMessageIdsTypeFromRule<typeof baseRule>;

Generated by Syntax Scribe