Skip to content

⬅️ Back to Table of Contents

πŸ“„ no-array-delete

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 3
πŸ“¦ Imports 7
πŸ“‘ Type Aliases 1

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/eslint-plugin/src/rules/no-array-delete.ts

πŸ“€ Default Export

export default createRule<[], MessageId>({ ... })
Property Value
name 'no-array-delete'
meta.type 'problem'
meta.docs.description 'Disallow using the delete operator on array values'
meta.docs.recommended 'recommended'
meta.docs.requiresTypeChecking true
meta.hasSuggestions true
meta.messages.noArrayDelete 'Using the delete operator with an array expression is unsafe.'
meta.messages.useSplice 'Use array.splice() instead.'
meta.schema []
defaultOptions []

Entry point: create β€” documented under Functions.


πŸ“¦ Imports

Name Source
TSESLint @typescript-eslint/utils
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
AST_TOKEN_TYPES @typescript-eslint/utils
createRule ../util
getConstrainedTypeAtLocation ../util
getParserServices ../util

Functions

create(context: any): { 'UnaryExpression[operator="delete"]'(node: TSESTree.Unary…

Parameters:

  • context any

Returns: { 'UnaryExpression[operator="delete"]'(node: TSESTree.UnaryExpression): void; }

Calls:

  • getParserServices (from ../util)
  • services.program.getTypeChecker
  • checker.isArrayType
  • checker.isTupleType
  • type.isUnion
  • type.types.every
  • type.isIntersection
  • type.types.some
  • predicate
  • getConstrainedTypeAtLocation (from ../util)
  • isUnderlyingTypeArray
  • context.report
  • nodeMap.get(object).getText
  • nodeMap.get(property).getText
  • context.sourceCode.getCommentsInside
  • ' '.repeat
  • comments .map(comment => { return comment.type === AST_TOKEN_TYPES.Line ?//${comment.value}:/${comment.value}/; }) .join
  • fixer.replaceText
Code
create(context) {
    const services = getParserServices(context);
    const checker = services.program.getTypeChecker();

    function isUnderlyingTypeArray(type: ts.Type): boolean {
      const predicate = (t: ts.Type): boolean =>
        checker.isArrayType(t) || checker.isTupleType(t);

      if (type.isUnion()) {
        return type.types.every(predicate);
      }

      if (type.isIntersection()) {
        return type.types.some(predicate);
      }

      return predicate(type);
    }

    return {
      'UnaryExpression[operator="delete"]'(
        node: TSESTree.UnaryExpression,
      ): void {
        const { argument } = node;

        if (argument.type !== AST_NODE_TYPES.MemberExpression) {
          return;
        }

        const type = getConstrainedTypeAtLocation(services, argument.object);

        if (!isUnderlyingTypeArray(type)) {
          return;
        }

        context.report({
          node,
          messageId: 'noArrayDelete',
          suggest: [
            {
              messageId: 'useSplice',
              fix(fixer): TSESLint.RuleFix | null {
                const { object, property } = argument;

                const shouldHaveParentheses =
                  property.type === AST_NODE_TYPES.SequenceExpression;

                const nodeMap = services.esTreeNodeToTSNodeMap;
                const target = nodeMap.get(object).getText();
                const rawKey = nodeMap.get(property).getText();
                const key = shouldHaveParentheses ? `(${rawKey})` : rawKey;

                let suggestion = `${target}.splice(${key}, 1)`;

                const comments = context.sourceCode.getCommentsInside(node);

                if (comments.length > 0) {
                  const indentationCount = node.loc.start.column;
                  const indentation = ' '.repeat(indentationCount);

                  const commentsText = comments
                    .map(comment => {
                      return comment.type === AST_TOKEN_TYPES.Line
                        ? `//${comment.value}`
                        : `/*${comment.value}*/`;
                    })
                    .join(`\n${indentation}`);

                  suggestion = `${commentsText}\n${indentation}${suggestion}`;
                }

                return fixer.replaceText(node, suggestion);
              },
            },
          ],
        });
      },
    };
  }

Internal helpers

Declared inside another function in this file.

isUnderlyingTypeArray(type: ts.Type): boolean

Parameters:

  • type ts.Type

Returns: boolean

Calls:

  • checker.isArrayType
  • checker.isTupleType
  • type.isUnion
  • type.types.every
  • type.isIntersection
  • type.types.some
  • predicate
Code
function isUnderlyingTypeArray(type: ts.Type): boolean {
      const predicate = (t: ts.Type): boolean =>
        checker.isArrayType(t) || checker.isTupleType(t);

      if (type.isUnion()) {
        return type.types.every(predicate);
      }

      if (type.isIntersection()) {
        return type.types.some(predicate);
      }

      return predicate(type);
    }

predicate(t: ts.Type): boolean

Parameters:

  • t ts.Type

Returns: boolean

Code
(t: ts.Type): boolean =>
        checker.isArrayType(t) || checker.isTupleType(t)

Type Aliases

MessageId

type MessageId = 'noArrayDelete' | 'useSplice';

Generated by Syntax Scribe