Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 9, 2022 08:29 am GMT

Build a custom Javascript linter in 5 minutes

Creating a custom linter can be a great way to enforce coding standards and detect code smells. In this tutorial, we'll use Sylver, a source code query engine to build a custom Javascript linter in just a few lines of code.

Sylver's main interface is a REPL console, in which we can load the source code of our project to query it using a SQL-like query language called SYLQ. Once we'll have authored SYLQ queries expressing our linting rules, we'll be able to save them into a ruleset that can be run like a traditional linter.

Installation

If sylver --version doesn't output a version number >= 0.1.9, go to https://sylver.dev to download a fresh copy of the software.

Starting the REPL

Starting the REPL is as simple as invoking the following command at the root of your project:

sylver query --files="src/**/*.js" --spec=https://github.com/sylver-dev/javascript.git#javascript.yaml

The REPL can be exited by pressing Ctrl+C or typing :quit at the prompt.

We can now execute SYLQ queries by typing the code of the query, followed by a ;. For instance: to retrieve all the method definitions (denoted by the node type MethodDefinition):

match MethodDefinition;

The results of the query will be formatted as follow:

[...]$0 [MethodDefinition src/store/createArticles.js:36:5-38:5]$1 [MethodDefinition src/store/createArticles.js:39:5-41:5]$2 [MethodDefinition src/store/createArticles.js:42:5-59:5]$3 [MethodDefinition src/store/createArticles.js:60:5-77:5]$4 [MethodDefinition src/store/createArticles.js:78:5-83:5]$5 [MethodDefinition src/store/createArticles.js:84:5-89:5][...]

The code of a given method definition can be displayed by typing :print followed by the node alias (for instance: :print $3). The parse tree can be displayed using the :print_ast command (for instance: :print_ast $3).

Rule1: use of the == operator

For our first rule, we'd like to detect uses of the unsafe == operator for checking equality. The first step is to get familiar with the tree structure of Javascript's binary expressions, so let's print a BinaryExpression node along with its AST:

> match BinaryExpression;[...]$43 [BinaryExpression src/pages/Article/Comments.js:7:31-7:77][...]> :print $43currentUser.username == comment.author.username> :print_ast $43BinaryExpression {.  left: MemberExpression {. .  object: Identifier { currentUser }. .  property: Identifier { username }. }.  operator: EqEq { == }.  right: MemberExpression {. .  object: MemberExpression {. . .  object: Identifier { comment }. . .  property: Identifier { author }. . }. .  property: Identifier { username }. }}

It appears that the nodes violating our rule are the BinaryExpression nodes for which the operator field contains an EqEq node. This can be easily expressed in SYLQ:

match BinaryExpression(operator: EqEq);

Rule2: functions with too many parameters

For our second linting rule, we'd like to identify functions that have more than 6 parameters.

Here is the relevant part of the parse tree of a Function node:

Function {.  async: AsyncModifier { async }.  name: Identifier { send }.  parameters: FormalParameters {. .  params: List {. . . FormalParameter {. . . .  value: Identifier { method }. . . }. . . FormalParameter {. . . .  value: Identifier { url }. . . }. . . FormalParameter {. . . .  value: Identifier { data }. . . }. . . FormalParameter {. . . .  value: Identifier { resKey }. . . }. . }. }.  body: StatementBlock {[...]

Function parameters are represented by FormalParameters nodes with a params field containing the actual function parameters. In our query, the condition regarding the length of the params list can be specified in a when clause, as follows:

match f@FormalParameters when f.params.length > 6;

Rule3: JSX 'img' elements without an 'alt' attribute

For our last rule, we'd like to identify <img> elements that miss the alt attribute. img elements are self-closing, so we'll start by looking at the parse tree of a JsxSelfClosingElement node:

> match JsxSelfClosingElement;[...]$73 [JsxSelfClosingElement src/pages/Article/Comments.js:21:11-21:55][...]> :print $73<img src={image} class="comment-author-img"/>> :print_ast $73JsxSelfClosingElement {.  name: Identifier { img }.  attribute: List {. . JsxAttribute {. . .  name: Identifier { src }. . .  value: JsxExpression {. . . . Identifier { image }. . . }. . }. . JsxAttribute {. . .  name: Identifier { class }. . .  value: String { "comment-author-img" }. . }. }}

In order to find the img elements that have no JsxAttribute with named alt in their attribute list, we can use a list quantifying expression, as illustrated in the following query:

match j@JsxSelfClosingElement(name: "img")       when no j.attribute match JsxAttribute(name: "alt");

Creating the ruleset

The following ruleset uses our linting rules:

id: customLinterlanguage: "https://github.com/sylver-dev/javascript.git#javascript.yaml"rules:    - id: unsafeEq      message: equality comparison with `==` operator      severity: warning      query: "match BinaryExpression(operator: EqEq)"    - id: tooManyParams      message: function has too many parameters      severity: info      note: According to our style guide, functions should have less than 6 parameters.      query: match f@FormalParameters when f.params.length > 6    - id: missingAlt      message: <img> tags should have an "alt" attribute      severity: error      query:        "match j@JsxSelfClosingElement(name: 'img')              when no j.attribute match JsxAttribute(name: 'alt')"

Assuming that it is stored in a file called custom_linter.yaml at the root of our project, we can run it with the following command:

sylver ruleset run --files="src/**/*.js" --rulesets=custom_linter.yaml

Getting updates

For more informations about new features and/or cool SYLQ one-liners, connect with Sylver on Twitter or Discord!


Original Link: https://dev.to/geoffreycopin/build-a-custom-javascript-linter-in-5-minutes-4a1j

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To