custom_lint

Tools for building custom lint rules.

License

Tutorial

You can read the latest blog post or watch the advanced use case with custom_lint video

About

Lint rules are a powerful way to improve the maintainability of a project. The more, the merrier! But while Dart offers a wide variety of lint rules by default, it cannot reasonably include every possible lint. For example, Dart does not include lints related to third-party packages.

Custom_lint fixes that by allowing package authors to write custom lint rules.

Custom_lint is similar to analyzer_plugin, but goes deeper by trying to provide a better developer experience.

That includes:

  • A command-line to obtain the list of lints in your CI without having to write a command line yourself.
  • A simplified project setup. No need to deal with the analyzer server or error handling. Custom_lint takes care of that for you, so that you can focus on writing lints.
  • Support for hot-restart. Updating the source code of a linter plugin will dynamically restart it, without having to restart your IDE/analyzer server
  • Built-in support for // ignore: and // ignore_for_file:.
  • Support for print(...) and exceptions. If your plugin somehow throws or print debug messages, custom_lint will generate a log file with the messages/errors.

Usage

Using custom_lint is split in two parts:

  • how to define a custom_lint package
  • how users can install our package in their application to see our newly defined lints

Creating a custom lint package

To create a custom lint, you will need two things:

  • updating your pubspec.yaml to include custom_lint_builder as a dependency:

    # pubspec.yaml
    name: my_custom_lint_package
    environment:
      sdk: '>=2.16.0 <3.0.0'
    
    dependencies:
      # we will use analyzer for inspecting Dart files
      analyzer:
      # custom_lint_builder will give us tools for writing lints
      custom_lint_builder:
  • create a bin/custom_lint.dart file in your project with the following:

    // This is the entrypoint of our custom linter
    void main(List<String> args, SendPort sendPort) {
      startPlugin(sendPort, _ExampleLinter());
    }
    
    // This class is the one that will analyze Dart files and return lints
    class _ExampleLinter extends PluginBase {
      @override
      Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
        // A basic lint that shows at the top of the file.
        yield Lint(
          code: 'my_custom_lint_code',
          message: 'This is the description of our custom lint',
          // Where your lint will appear within the Dart file.
          // The following code will make appear at the top of the file (offset 0),
          // and be 10 characters long.
          location: resolvedUnitResult.lintLocationFromOffset(0, length: 10),
        );
      }
    }

That’s it for defining a custom lint package!

Let’s use it in an application now.

Using our custom lint package in an application

For users to run custom_lint packages, there are a few steps:

  • The application must contain an analysis_options.yaml with the following:

    analyzer:
      plugins:
        - custom_lint
  • The application also needs to add custom_lint and our package(s) as dev dependency in their application:

    # The pubspec.yaml of an application using our lints
    name: example_app
    environment:
      sdk: '>=2.16.0 <3.0.0'
    
    dev_dependencies:
      custom_lint:
      my_custom_lint_package:

That’s all! After running pub get (and possibly restarting their IDE), users should now see our custom lints in their Dart files:

screenshot of our custom lints in the IDE

Obtaining the list of lints in the CI

Unfortunately, running dart analyze does not pick up our newly defined lints. We need a separate command for this.

To do that, users of our custom lint package can run inside the application the following:

$ dart run custom_lint
  lib/main.dart:0:0 • This is the description of our custom lint • my_custom_lint_code

If you are working on a Flutter project, run flutter pub run custom_lint instead.


Built and maintained by Invertase.

GitHub

View Github