An Introduction to Writing HTML ESLint Rules in Angular

How to write a rule that will give you the core ideas behind writing HTML ESLint rules for Angular applications

Elad Zipper
Bits and Pieces

--

Image Source https://www.npmjs.com/package/eslint-plugin-html , Created By kuceb.

ESLint rules for HTML? Why should we care about it? It’s just HTML.
This is probably the answer you are going to hear from many developers.

We all know that HTML in Angular is a bit more than HTML, we have our angular components, directives, pipes, custom events, etc.

When you are working in a large company with many developers you may want to prevent developers from using deprecated directives, components, and pipes when developing new features.

In this article, I’m going to teach you how to write a rule that hopefully will give you the core ideas behind writing HTML ESLint rules for Angular applications so you can implement them for your projects and improve the quality of code.

Before we get our hands dirty I recommend you to look at my previous article about creating custom ESLint rules.
In this article, I assume that you have basic knowledge of writing ESLint Rules.

💡 As an aside, if you frequently need to reuse your Angular components over and over again for multiple projects, consider using a component-management hub like Bit. With Bit you can extract reusable components out of your codebase and use across multiple projects with a simple bit import your.username/yourComponent command.

Learn more:

Deprecated Components Rule:

Imagine you have a group of components that receives text as input and display it with a font size of 16px, 24px, 32px and etc.

For example:

After a while, you understand that creating those components was a mistake and it increases the application bundle size without any good reason, and instead of using those components, you should use simple CSS classes.

Let’s build a rule that will receive as input all the deprecated components selectors and will report if any of them has been used.

The first thing we want to do is to go to ASTExplorer and understand a bit of Angular’s HTML AST.

Make sure to switch to HTML Language and the parser to angular-eslint/template-parser.

In order to do that, I will provide a code example for our case.

The generated tree is too large for me to display in this article,
Nevertheless, the important thing is that we will see that our node is of type “Element$1”.

So If we will find a node of type “Element$1” with the name property of “app-title-one”, we have found our target and we can alert the developer.

Now let's see a rule that will be provided an array of deprecated components selectors and will alert whenever one of the selectors is found.

The following code might be overwhelming, but we will analyze the core ideas of the code.

Schema:
At line 16 we have the schema property, using the schema we can define the structure of the input that the user will provide to the ESLint rule.

At every level of the schema, we must define the types of our input.
For example, in our case, we define that we expect an Object with a property called ‘selectors’ that will be an Array of strings.
We can prevent the user to provide unexpected properties by adding additionalProperties: false to our schema.

Messages:
At line 27 we have our messages object, I assume that you are familiar with how we are working with messages in ESLint rules, I will only point out that we can provide dynamic data into the message by wrapping a variable with double curly brackets and later on provide that variable when reporting a match to the user, In our case, we will use it to report the exact component selector.

DefaultOptions:
At line 31 we have our default options, You can use them to define default values In case the user didn’t provide the required input.
I will only point out that this property is a must in order for the rule to work when using a schema.
In my case, I don't want to provide any default options, so I will provide our schema object without any selectors.

Now let's take a look at our visitor.

Remember we want to find an “Element$1” node with a name property that will match any of our deprecated component selectors.

In our case we will not use Element$1 node selector, We will use ESQuery string that will help us write our rule in a much faster and cleaner way
(For more details visit ESQuery GitHub).

ESQuery string will allow the use of a Regex that will match all our selectors.

At line 35 we are assigning to a variable a Regex that matches all our selectors using a helper function, After that, we can provide it to our ESQuery node selector (line 37) using template literals.

Because this rule will execute its logic only and only if we have a match, we can immediately report our match.

Unlike JavaScript rules, in HTML rules we are not reporting the node, but reporting the “loc” (line 41), which is the position/source location of the node.

We can get the node loc using TemplateParserServices, as I did in lines 38–39.

Now that we fully understand our rule we can add it to our eslintrc.json file.

And that is it!
I hope you had a great time reading this article and learned many new things!

Build Angular Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--