In development teams we strive for a code base that is consistent and reflects our best practices. While coding, we tend to focus on the core logic, and would like to allow tools to take care of everything else. One of those tools is the linter, that helps us maintain coding standards and ensure we don’t miss any of them by mistake.
We often take for granted the linter set of rules, and don’t think of it as a tool that can help us maintain a new standard or best practice we might want to introduce into our code.
Writing you own custom lint rules is a powerful method that is often overlooked, and many teams could easily make better use of it for their own purposes.Oh, and you can also make a contribution to the community along the way.
© Eran Shabi
How TSLint works
A lint rule scans the Abstract Syntax Tree (AST) of a file, and searches for problematic patterns. Don’t let a fancy term like AST intimidate you, it only means a tree-like representation of the code.For example, here is the AST tree visualisation of const myVar = 7;:
AST illustration by AST visualizer
TSLint transforms the code into AST, and goes over each and every expression in the file. We can hook into this process, and take care of each expression that we care about in our rule.
To see an AST in action, use astexplorer.net
A case study
At our team, we found that enforcing all public method’s signatures to be well typed, improves the code readability and makes integrations easier.
We will walk through the implementation of this new rule, no-untyped-public-signature (this is a simplified version, the full implementation can be found here).
Step 1: implement the rule’s logic
The custom rule’s logic will be implemented in a class that inherits from TSLint’s RuleWalker.
The RuleWalker class has a method for every node type. In our case, we want to check method declaration nodes, so we will override the visitMethodDeclaration method and write our logic inside:
https://medium.com/media/30fd8c3ed08ea55a7d063bd692595ef4/hrefThe RuleWalker class actually implements the visitor design pattern,for more methods which visit other node types, take a look at the source code.
We will inspect each method’s node and check that if they are public, they don’t have any untyped parameter.
https://medium.com/media/a8efec98f01c754729beaf7e44720b6f/hrefThis is the core of our rule — a code that recognises an error and reports it. All other stuff is boilerplate. TSLint will know how to display the error at the correct position relative to the source file.Step 2: Boilerplate
For the rule to be used in TSLint, we have to abide by some conventions: We will place our code in a file named noUntypedPublicSignatureRule.ts. By convention the file name must consist of the rule’s name in camel case, followed by the Rule keyword. This module must export a class named Rule that inherits from Lint.Rules.AbstractRule. We will instantiate our Walk class and invoke it using the inherited applyWithWalker method:
At our team we found that developing a rule is much faster using TDD and file strings instead of manually running your rule on real files and checking the results. For quicker development cycle, we wrote a small function that receives the code to lint and a rule name, and returns the linter’s result.
The TDD development cycle. The full project is available on GitHub
Here is a boilerplate with a working example, so you can start write your rule right away.
Now that you know how to create your own TSLint rule, all you need is an idea. We recommend choosing something bothersome from you daily coding you wish to automate.
A good place to start is to use the TSLint custom rules boilerplate.