Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to forbid a specific named function with ESlint

The Situation

In our current project we've had some recurring problems with people using 'asMutable' from seamless-immutable where it isn't actually necessary. This has resulted in 'search project for string "asMutable"' becoming part of every pull request. To speed this up we would like to add a rule warning that to our eslint. But I haven't figured out how.

The Question

What seems like the best solution to me right now, though I'm open to suggestions, is a rule that allows me to specify a function name to forbid. Does ESlint, or a plugin therefore, have that sort of functionality?

Additional Notes

I've looked a little into writing our own, but I was intimidated by AST and the startup difficulty to writing my first rule. I may take the plunge if I can't find a better answer, yes we're getting this enough in PRs to warrant it. This seems like something someone much smarter than me has already solved though, so I'd rather follow in their footsteps then build my own.

like image 859
Suni Avatar asked Dec 05 '16 15:12

Suni


People also ask

How do I disable a specific ESLint rule?

If you want to disable an ESLint rule in a file or on a specific line, you can add a comment. On a single line: const message = 'foo'; console. log(message); // eslint-disable-line no-console // eslint-disable-next-line no-console console.

How do you exclude a ESLint?

Use "--no-ignore" to override. This message occurs because ESLint is unsure if you wanted to actually lint the file or not. As the message indicates, you can use --no-ignore to omit using the ignore rules.

How do you set rules in ESLint?

ESLint comes with a large number of built-in rules and you can add more rules through plugins. You can modify which rules your project uses either using configuration comments or configuration files. To change a rule setting, you must set the rule ID equal to one of these values: "off" or 0 - turn the rule off.

Where can I find ESLint rules?

The current eslint:recommended rules can be found at github.com/eslint/eslint/blob/master/conf/eslint-recommended.js.


1 Answers

I had the same problem not so long ago so I can help you with writing your own.

So, first, let's explain some basic structures:

  1. ESLint has plugins, and each plugin has rules.
  2. ESLint uses AST which is a syntax tree to find specific parts in the code. This helps ESLint find what each rule is looking for.

So, let's start by creating a plugin with a rule in it:


1. Use The ESLint Generator for Yeoman

This makes things a lot easier. Check it out here.

After you install yeoman and the yeoman eslint generator:

  • go into the folder you want to create your project in
  • run yo eslint:plugin to create a new ESLint plugin
  • after creating the plugin, run yo eslint:rule in the same folder

I used suni as the plugin name, and check-as-mutable as the rule name. Now we have all the initial files we need to write the rule.


2. Know what you need to look for using AST Explorer

AST Explorer Can help us find what type of thing we're looking for. This is important so we can tell ESLint what in the code we want our function to run on.

When you paste code into AST Explorer, it shows you what ESLint is seeing. We want to target all MemberExpressions:

something.asMutable();

Inside that, we want the Identifier node to check the function name


3. Write the plugin itself

Open lib/rules/check-as-mutable.js and check it out. All the data you provided for Yeoman was used to fill some fields here.

Inside the rule, you have a create attribute. Here, we write our code. This function should return an object, with what we want our rules to run on as attributes. So, in this case, it will look like so:

create: function(context) {

    return {
      MemberExpression: function(node)...

    };
}

While writing the rule, you should check which fields you need using the AST Explorer.

here is the implementation:

create: function(context) {
  var UNWANTED_FUNCTION_NAME = 'asMutable';
  return {
    MemberExpression: function reportUnwantedName(node) {
      var functionName = node.property.name;

      if (functionName === UNWANTED_FUNCTION_NAME) {
        context.report({
          node: node,
          message: [
            'Please don\'t use ',
            UNWANTED_FUNCTION_NAME,
            '. We don\'t like it!'].join('')
        });
      }
    }
  };
}

After that, you need to install the plugin in your project. To do that, upload it to GitHub, and install it using npm:

npm install --save-dev <user_name>/<repository_name>

And include the rule in your .eslintrc file as well:

{
    'plugins': ['suni'],
    'rules': {
      'suni/check-as-mutable': 1
    }
}

Notice that I gave it the value 1. This makes this rule show as a Warning and not as an Error

enter image description here

Notice that the warning highlights the Immutable itself, since that is the node we pass to context.report. You can tweak that to highlight the id node instead.

Here's the plugin I created for this answer

Good luck!

like image 95
Thatkookooguy Avatar answered Sep 23 '22 17:09

Thatkookooguy