June Lee
June Lee

Reputation: 417

eslint rules that prevent using 'some keyword' AST parser

I want to make a custom eslint rule using the AST parser.

In the useEffect cleanup function, I want to prevent using some keywords.

import React, { useEffect } from 'react';


export const SomeReactFun = () => {
  useEffect(() => {
     return () => {
          // `Hello` is some keyword I want to prevent in using cleanup function.
          Hello.alert();
     }
  }, []);
}

this is my custom parse function in AST parser.

export default function (context) {
  const filename = context.getFilename();
  if (filename.includes(".test.ts")) return {};

  return {
    Identifier: (node) => {
      if (node.name !== "useEffect" || node.parent.type !== "CallExpression")
        return {};

      const arrayExpressionBody = node.parent.arguments[0];
      if (arrayExpressionBody.type !== "ArrowFunctionExpression") return {};

      const arrowFunctionBody = arrayExpressionBody.body;
      if (arrowFunctionBody.type !== "BlockStatement") return {};

      const returnStatement = arrowFunctionBody.body.find((functionNode) => {
        if (functionNode.type === "ReturnStatement") return true;
        return false;
      });
      if (!returnStatement || returnStatement.type !== "ReturnStatement")
        return {};

      const returnStateArgument = returnStatement.argument;
      if (returnStateArgument.type !== "ArrowFunctionExpression") return {};

      const blockStatementInReturnState = returnStateArgument.body;
      if (blockStatementInReturnState.type !== "BlockStatement") return {};

      const isHelloUsedInClenaup = blockStatementInReturnState.body.find(
        (nodeBody) => {
          if (nodeBody.type !== "ExpressionStatement") return false;

          console.log(nodeBody.expression);

          if (
            nodeBody.expression.type === "CallExpression" &&
            nodeBody.expression.callee.object.name === "Hello"
          ) {
            return false;
          }

          if (
            nodeBody.expression.type === "Identifier" &&
            nodeBody.expression.name === "Hello"
          )
            return false;
        }
      );

      if (!isHelloUsedInClenaup) return {};

      context.report({
        node: isHelloUsedInClenaup,
        message: "ERROR, do not use `Hello` in cleanup function",
        data: { explanation: `${node.loc}` }
      });
    }
  };
}

But this code can't prevent like this

import React, { useEffect } from 'react';


export const SomeReactFun = () => {
  useEffect(() => {
     return () => {
          Hello.alert(); // works!
          Hello.someObject.a.alert(); // not works :)
     }
  }, []);
}

How can I prevent using the Hello keyword in useEffect cleanup function completely?

Upvotes: 2

Views: 502

Answers (1)

Brad Zacher
Brad Zacher

Reputation: 3243

There's some good docs on writing lint rules on TypeScript-ESLint's website which can help walk you through custom lint rules

https://typescript-eslint.io/docs/development/custom-rules

You can also use our playground to interrogate the AST and learn its structure so that you can write appropriate selectors

https://typescript-eslint.io/play#showAST=es

Upvotes: 1

Related Questions