Skip to main content

Hello World

Overview

This tutorial will give you an in-depth introduction to creating a basic rule.

At the conclusion of the tutorial, we will have the following code showing a lint message.

example/main.dart
const question = 'Is there anybody there?';

Learning Objectives

  • Explore the basics of the LintRule class
  • Create analyzer logic for our particular use case
  • Requirements for declaring the rule so that it can be discovered by Sidecar
  • Validating a LintRule within our IDE

Defining a Rule

Creating a new Rule Package

Our first step is to create a package for our lints to reside in, and add the necessary dependencies to our pubspec.yaml file.

# create our package and open the directory
dart create hello_world_rules && cd hello_world_rules

# add sidecar dependency
dart pub add sidecar

# add official package:analyzer
dart pub add analyzer

NOTE: version conflicts will arise if using a Dart SDK version thats not v2.17.0

Though a rule package can contain one or more rules, for this example we'll create a single Lint Rule.

import 'package:sidecar/sidecar.dart';

class HelloWorld extends LintRule {

LintCode get code =>
const LintCode('hello_world', package: 'hello_world_rules');

}

The summary of all Sidecar Rule requirements are:

  • every rule must have a unique rule ID (in snake_case)
  • the class name of the Rule must match the rule ID (in PascalCase)
  • the code.package parameter must match the name given to our rule package

Defining the Logic for our use case

For our paricular rule, we want to create a lint that simply outputs 'Hello world!' any time we create code that has a string containing 'Is there anybody there?'. Our requirements are therefore:

  • Analyze all Strings
  • If the String value is equal to the text 'Is there anybody there?' then report a lint with the message 'Hello world!'

In order to analyze all Strings in a particular file, we must override the visitSimpleStringLiteral method. In later tutorials, we will cover how to determine which visit method(s) to use for a given use case.

lib/hello_world.dart
import 'package:analyzer/dart/ast/ast.dart';
import 'package:sidecar/sidecar.dart';

class HelloWorld extends LintRule {

void visitSimpleStringLiteral(SimpleStringLiteral node) {
// TODO: implement visitSimpleStringLiteral
super.visitSimpleStringLiteral(node);
}
}

The takeaway here is that the logic we write within this method will be executed for every String literal that appears in our codebase, and the information of this code will be delivered via the node parameter of all visit methods.

For our use case, we want to check if the particular String contains the code 'Is there anybody there?'. We do so easily by writing the following logic:

import 'package:analyzer/dart/ast/ast.dart';
import 'package:sidecar/sidecar.dart';

class HelloWorld extends LintRule {

void visitSimpleStringLiteral(SimpleStringLiteral node) {
final stringValue = node.value;
if (stringValue == 'Is there anybody there?') {
reportAstNode(node, message: 'Hello world!');
}
}
}

The last thing we must do for our newly created Rule class is add our rule's visitSimpleStringLiteral method to Sidecar's NodeRegistry; without this step, our visitor method will never be executed.

import 'package:analyzer/dart/ast/ast.dart';
import 'package:sidecar/sidecar.dart';

class HelloWorld extends LintRule {

LintCode get code =>
const LintCode('hello_world', package: 'hello_world_rules');


void initializeVisitor(NodeRegistry registry) {
registry.addSimpleStringLiteral(this);
}


void visitSimpleStringLiteral(SimpleStringLiteral node) {
final stringValue = node.value;
if (stringValue == 'Is there anybody there?') {
reportAstNode(node, message: 'Hello world!');
}
super.visitSimpleStringLiteral(node);
}
}

We've now fully defined our HelloWorld rule class!

Making our Rule Visible to Sidecar

There are two other requirements that make our newly created rule visible to sidecar:

Validating our LintRule in an IDE

The best way to visually test if our lint is working is by creating an example package:

# create new project within the root hello_world_rules directory
dart create example && cd example

# add our new rules package from path
dart pub add hello_world_rules --path ../

We can now add our rule to our sidecar.yaml file:

And finally, we can enable sidecar in our analysis_options.yaml file:

analyzer:
plugins:
- sidecar

With our example app set up, all that's left to do is add our 'Is there anybody there?' string into a dart file, and you should see a lint appear over the string.

example/main.dart
const question = 'Is there anybody there?';

Congrats! You've created your first lint rule. 🎉

Conclusion

This is a simple example of what it takes to create a custom lint rule using Sidecar. On one hand, creating the logic to analyze code can be relatively straightforward, only taking a few lines of code to write:

  void visitSimpleStringLiteral(SimpleStringLiteral node) {
final stringValue = node.value;
if (stringValue == 'Is there anybody there?') {
reportAstNode(node, message: 'Hello world!');
}
}

On the otherhand, there are many individual requirements to abide by, and forgetting any of them results in no lint appearing at all.

The rule creation checklist makes it easy to ensure you've covered all the bases. Additionally, it's highly recommended to use package:sidecar_lints to help ensure all of your rules are properly defined for Sidecar.