p-hatan/ mirror

pub repository

mirror.p-hatan.com

custom_lint

0.0.10+1

Lint rules are a powerful way to improve the maintainability of a project. Custom Lint allows package authors and developers to easily write custom lint rules.

Download archive

Readme

Index

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:
      analyzer_plugin:
      # 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 now use it in an application.

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 the following inside their terminal:

$ 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.


FAQs

Q. How do I get all the classes present in my source code?

There are two ways of doing that. You can either use the Element Tree or the Abstract Syntax Tree (AST) to find all the classes. Here's an example with each approach.

  • Element Tree Approach

    class _CustomLint extends PluginBase {
      @override
      Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
        final library = resolvedUnitResult.libraryElement;
        final classes = library.topLevelElements.whereType<ClassElement>();
        ....
        ....
      }
    }
    

    The variable classes is of type List<ClassElement> and will contain all the ClassElements.

  • AST Approach

    class ClassDeclarationVisitor extends GeneralizingAstVisitor<void> {
      ClassDeclarationVisitor({
        required this.onClassDeclarationVisit,
      });
    
      void Function(ClassDeclaration node) onClassDeclarationVisit;
    
      @override
      void visitClassDeclaration(ClassDeclaration node) {
        onClassDeclarationVisit(node);
        super.visitClassDeclaration(node);
      }
    }
    
    class _CustomLint extends PluginBase {
      @override
      Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
        final classDeclarations = <ClassDeclaration>[];
        resolvedUnitResult.unit.visitChildren(
          ClassDeclarationVisitor(
            onClassDeclarationVisit: classDeclarations.add,
          ),
        );
        ....
        ....
      }
    }
    

    This way, the variable classDeclarations will contain list of ClassDeclaration.


Q. How do I get all the global variables present in my source code?

Same as above. Just replace ClassElement with VariableElement in the Element Tree Approach or replace ClassDeclaration with VariableDeclaration in the AST approach.


Q. How do I get the path to my currently opened dart file?

You can use the instance of ResolvedUnitResult to call the path getter.

class _CustomLints extends PluginBase {
  @override
  Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
    final path = resolvedUnitResult.path; // Gives the path of the currently opened Dart file
    ...
    ...
  }
}

Q. I want to insert code at the end of the file. How can I get the required offset?

To find the offset for the end of the file (or simply put, find the end line of a Dart file), you can use the instance of ResolvedUnitResult to call the end getter.

class _CustomLints extends PluginBase {
  @override
  Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
    final endLineOffset = resolvedUnitResult.unit.end; // Gives the offset for the last line in a Dart file
  }
}

Changelog

0.0.10+1

Update docs

0.0.10

  • Upgrade Riverpod to 2.0.0
  • Fix deprecation errors with analyzer

0.0.9+1

Update description and readme

0.0.9

  • Lint fixes can now be used when placing the cursor on the last character of a lint
  • improve pub score

0.0.8

Allow lints to emit fixes

0.0.7

Fix a bug where the custom_lint command line may not list all lints

0.0.6

feat!: getLints now is expected to return a Stream<Lint> instead of Iterable<Lint>

fix: a bug where the lints shown by the IDE could get out of sync with the actual content of the file

0.0.5

Fixed error reporting if a custom_lint plugin throws but the exception comes from a package instead of the plugin itself.

0.0.4

  • Fixed a bug where the command line could show IDE-only meant for debugging

0.0.3

PluginBase.getLints now receive a ResolvedUnitResult instead of a LibraryElement.

0.0.2

  • Compilation errors are now visible within the pubspec.yaml of applications that are using the plugin.

  • Plugins that are currently loading are now highlighted inside the pubspec.yaml of applications that are using the plugin.

  • If a plugin throws when trying to analyze a Dart file, the IDE will now show the exception at the top of the analyzed file.

  • Compilation errors, exceptions and prints are now accessible within a log file (custom_lint.log) inside applications using the plugin.

0.0.1

Initial release

Installing

export PUB_HOSTED_URL=https://pub.mirror.p-hatan.com
flutter pub add custom_lint
pubspec.yaml
name: custom_lint
version: 0.0.10+1
description: Lint rules are a powerful way to improve the maintainability of a project. Custom Lint allows package authors and developers to easily write custom lint rules.
repository: https://github.com/invertase/dart_custom_lint
issue_tracker: https://github.com/invertase/dart_custom_lint/issues

environment:
  sdk: '>=2.17.1 <3.0.0'

dependencies:
  analyzer: ^4.6.0
  analyzer_plugin: ^0.10.0
  async: ^2.8.2
  cli_util: ^0.3.5
  collection: ^1.15.0
  meta: ^1.7.0
  package_config: ^2.0.2
  path: ^1.8.0
  pub_semver: ^2.1.1
  pubspec_parse: ^1.2.0
  recase: ^4.0.0
  riverpod: ^2.0.0
  uuid: ^3.0.6
  yaml: ^3.1.0

dev_dependencies:
  test: ^1.20.2

executables:
  custom_lint: custom_lint

Version history

VersionPublishedArchiveSHA-256
0.0.12022-04-11T10:37:28.967785ZDownload9cdc374121ac30bedb80f68a07fd76ebf1d55083f8d314bd22df4eae67ae137a
0.0.22022-04-14T10:43:53.407881ZDownloade952987a3982038ec72f4783288bb0adeb139fbf5b122a470aa5d1a9dd0fa094
0.0.32022-05-16T14:03:26.737735ZDownload7b684ff0459998e5eee39dcea3c0d14070120de9e2a1c2918d0fbfddda1e0a4a
0.0.42022-06-07T12:02:42.865ZDownloadd9dec5988450ec2698bc9b3bd0d5f8d313a3540527d024310f700687cb10f894
0.0.52022-06-07T17:54:59.892367ZDownload269f8d70c027b4c4fec4325c52f2e3ed50e0d202643e713e8038cffd21104c9c
0.0.62022-06-13T17:49:47.738781ZDownload09c32f0ba53ed11e12ca09453cd9377de506455cd229cbd0b47e7299433a6f41
0.0.72022-06-14T13:40:12.407094ZDownload2ad9dd3530461521da080bf78ad011a29bffd3c1e779c91aa70fee3c62ba648c
0.0.82022-06-14T20:14:04.097837ZDownloadbaa4661f21a6fe0e6f88da9d2c6e7f827bf94d5bef41f57ac38de968477ad350
0.0.92022-07-05T09:09:15.791242ZDownloada14dff85bda445a78462d907960921d91fbfa58994cb43fc0098aaf4e378a8aa
0.0.9+12022-07-06T11:32:41.111224ZDownload4c4cc2ac5556dee746b3e81edb847335dd77fafe5e9b6808595560be5783f4f3
0.0.102022-10-03T10:20:43.324883ZDownloadd58a9c288971d04374b9d1cbd7b8c8d7aa07900873f1224a260e7ded9a737894
0.0.10+12022-10-04T08:48:04.719084ZDownload2c49e6a1f4994a0d2494e0ec3d122ff2158e2414cf2f02e8502ee68566595761
0.0.112022-10-07T14:19:21.186791ZDownload2f97dc4806abd2c185665e3c91f5af93cd61718e340bcc29b0a9662306cc024e
0.0.122022-10-07T15:49:36.461277ZDownload4db715848640a185d66bee2d9477bdfb0b2cf18b6e6647bc11dd35984e427436
0.0.132022-11-23T13:55:58.573145ZDownload0f19aaf6ab634fe6da225174424262fecafc318551282fb38209c78657868b7f
0.0.142022-11-23T16:16:21.151678ZDownload6eab9aae8f204dbac3a785c81a32980c84c00f42a72300a275b7c661d1a6efd6
0.0.152022-12-06T15:22:09.076923ZDownload2264aea4889331d19ea6eb8cf27e4ee62c5a3eb6f572c81d1d057709b30bf52a
0.0.162022-12-09T13:09:00.522339ZDownloadfa0b50885e41a66180a9b5a2dca7c2152ad0c8ea10dee16d0c123adc573a21df
0.1.02023-01-06T07:51:15.830037ZDownload244cb887d5f6e9cf0b739774dac37d6b2462c677dce6ec8b2eb952aceef2a18f
0.1.12023-01-09T15:10:42.545626ZDownloadee61018ed2c4bafa94458aca259d58335bfe6110f7ba244ad15a853b0513898b
0.1.2-dev2023-01-10T09:53:09.414769ZDownloadc0dcebfb2250226c563f4400d0762d8d22e357299af53e9b61944976f15c431a
0.2.02023-01-20T14:34:45.994014ZDownloadc14f87590e96e4686b8fdaaf5c088983a8fcabf9ccc7274eb1c5516427521a38
0.2.22023-01-31T18:57:11.443431ZDownloadced9a173ce0b30fc498160060c23ff8fed5aabfbfb7c7ceaed782f3129c73084
0.2.52023-02-10T17:28:54.634220ZDownload29b7e51b5e75fcd5ffce8fc12af87b71cbde7a59d080467b187630231aeb42c0
0.2.112023-02-27T18:20:21.294990ZDownload8df4335b86ff9695770dfec9599d1b2d87d997b2db59827f11381ecd62ab572e
0.2.122023-02-28T20:00:14.953769ZDownload324e7026902f34e180d8d27e08a89dbbe3dd8a54e0c3852a0df0db0f4046120b
0.3.02023-03-09T07:23:14.092498ZDownload32d120ce01a93ff145ab20ce807d68e0eac71a44fc8802d8688ab64e5bf151ad
0.3.22023-03-09T15:11:02.081592ZDownload32648ef4f1dda618d98a22bc958fa79d479895891061e63338bec510b67e821a
0.3.32023-04-06T14:57:02.113259ZDownload80ccf10b30d4f1d0b40bd6d276a86d72266569c0a7542f1b839daf2fd05c16a5
0.3.42023-04-19T11:54:53.963574ZDownloade87176016465263daf10c209df1f50a52e9e46e7612fab7462da1e6d984638f6
0.4.02023-05-12T08:57:17.240922ZDownload3ce36c04d30c60cde295588c6185b3f9800e6c18f6670a7ffdb3d5eab39bb942
0.5.02023-06-21T10:56:46.333593ZDownloadb09a939c3bb062fdf072aa4c8eb5447231338854c4fefb23e4c9f7cef41cb3ff
0.5.12023-08-03T16:24:21.399646ZDownload99e3cd20010b93c466f07573583660c73f034da2d95cc98e90426c1c16e40640
0.5.22023-08-16T10:08:13.621027ZDownloadae3cf0f83a155bdfc50315d4a11c7b358ea1e201a57ab0bb2b397f1a9a2a9b80
0.5.32023-08-29T07:59:55.546944ZDownload837821e4619c167fd5a547b03bb2fc6be7e65b800ec75528848429705c31ceba
0.5.42023-10-20T12:53:17.389489ZDownload32ca92485d52095d1296c99c8ab922d112a99f190dac1568aa369fe701038a33
0.5.52023-10-26T10:08:40.185087ZDownload68671c7b9cad03029c0270119169e32e801f8d87cec00367f233f4408d8913bd
0.5.62023-10-30T15:04:08.436356ZDownloadf9a828b696930cf8307f9a3617b2b65c9b370e484dc845d69100cadb77506778
0.5.72023-11-20T11:05:58.655952ZDownload198ec6b8e084d22f508a76556c9afcfb71706ad3f42b083fe0ee923351a96d90
0.5.82024-01-09T12:49:06.027628ZDownloaddfb893ff17c83cf08676c6b64df11d3e53d80590978d7c1fb242afff3ba6dedb
0.5.112024-01-27T17:55:58.060707ZDownload22bd87a362f433ba6aae127a7bac2838645270737f3721b180916d7c5946cb5d
0.6.02024-02-04T15:03:30.056643ZDownloadf89ff83efdba7c8996e86bb3bad0b759d58f9b19ae4d0e277a386ddd8b481217
0.6.22024-02-19T09:53:05.774612ZDownload445242371d91d2e24bd7b82e3583a2c05610094ba2d0575262484ad889c8f981
0.6.32024-03-16T14:52:51.836974ZDownload7dbb45d90ec8c73f99b08414cb629d8b35e3f84a28c971bfaffe4bfd99266e1a
0.6.42024-03-16T15:43:13.380036ZDownload7c0aec12df22f9082146c354692056677f1e70bc43471644d1fdb36c6fdda799
0.6.52024-08-15T16:41:02.336624ZDownload4939d89e580c36215e48a7de8fd92f22c79dcc3eb11fda84f3402b3b45aec663
0.6.62024-09-08T08:11:47.421420ZDownloadcbea60b2e574a2958170bfb7a76b2d85e07e175911a7931a8e8eef42cc36673e
0.6.72024-09-08T11:13:51.381079ZDownload6e1ec47427ca968f22bce734d00028ae7084361999b41673291138945c5baca0
0.6.82024-10-08T17:08:16.595136ZDownload832fcdc676171205201c9cffafd6b5add19393962f6598af8472b48b413026e6
0.6.92024-10-09T10:40:45.163373ZDownload18f7982b99c84c10d27280852c7e6efb3cc320b6acd85a922999e9a6bf8c7bea
0.6.102024-10-10T15:52:28.533958ZDownload4500e88854e7581ee43586abeaf4443cb22375d6d289241a87b1aadf678d5545
0.7.02024-10-27T19:02:52.933666ZDownload3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9
0.7.12025-01-08T17:54:53.884005ZDownload6d509673c4dd0baa90e60dc8366bc2acc6690f16a7d44bfae31294d82c5d2a62
0.7.22025-01-29T21:11:30.265803ZDownload7e6a73e1722ad90b48f77918994c17a5b177b0869804ea3c4ce9c9199de019f6
0.7.32025-02-08T16:26:44.034352ZDownload021897cce2b6c783b2521543e362e7fe1a2eaab17bf80514d8de37f99942ed9e
0.7.42025-02-27T12:00:16.852656ZDownload3a9fcbcba1d141d8084a17e57a787993d8d409b294e6d781069a7d627963ebe0
0.7.52025-02-27T12:53:28.344757ZDownload409c485fd14f544af1da965d5a0d160ee57cd58b63eeaa7280a4f28cf5bda7f1
0.7.62025-07-18T21:04:09.693416ZDownload9656925637516c5cf0f5da018b33df94025af2088fe09c8ae2ca54c53f2d9a84
0.7.72025-07-25T13:37:27.482785ZDownload9f0f0c832ed35e57de68bb4884eb86dedd061e826b593b6cea3d8c4600490f71
0.8.02025-07-25T13:40:22.353524ZDownload78085fbe842de7c5bef92de811ca81536968dbcbbcdac5c316711add2d15e796
0.8.12025-09-09T14:08:31.029924ZDownload751ee9440920f808266c3ec2553420dea56d3c7837dd2d62af76b11be3fcece5

Dependencies

analyzer "^4.6.0"

analyzer_plugin "^0.10.0"

async "^2.8.2"

cli_util "^0.3.5"

collection "^1.15.0"

meta "^1.7.0"

package_config "^2.0.2"

path "^1.8.0"

pub_semver "^2.1.1"

pubspec_parse "^1.2.0"

recase "^4.0.0"

riverpod "^2.0.0"

uuid "^3.0.6"

yaml "^3.1.0"