Giter VIP home page Giter VIP logo

dart_custom_lint's Introduction

custom_lint

Tools for building custom lint rules.

License


Chat on Discord

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.
  • Debugger support. Inspect your lints using the Dart debugger and place breakpoints.
  • Supports hot-reload/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:.
  • Built-in testing mechanism using // expect_lint. See Testing your plugins
  • 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: ">=3.0.0 <4.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 lib/<my_package_name>.dart file in your project with the following:

    import 'package:analyzer/error/listener.dart';
    import 'package:custom_lint_builder/custom_lint_builder.dart';
    
    // This is the entrypoint of our custom linter
    PluginBase createPlugin() => _ExampleLinter();
    
    /// A plugin class is used to list all the assists/lints defined by a plugin.
    class _ExampleLinter extends PluginBase {
      /// We list all the custom warnings/infos/errors
      @override
      List<LintRule> getLintRules(CustomLintConfigs configs) => [
            MyCustomLintCode(),
          ];
    }
    
    class MyCustomLintCode extends DartLintRule {
      MyCustomLintCode() : super(code: _code);
    
      /// Metadata about the warning that will show-up in the IDE.
      /// This is used for `// ignore: code` and enabling/disabling the lint
      static const _code = LintCode(
        name: 'my_custom_lint_code',
        problemMessage: 'This is the description of our custom lint',
      );
    
      @override
      void run(
        CustomLintResolver resolver,
        ErrorReporter reporter,
        CustomLintContext context,
      ) {
        // Our lint will highlight all variable declarations with our custom warning.
        context.registry.addVariableDeclaration((node) {
          // "node" exposes metadata about the variable declaration. We could
          // check "node" to show the lint only in some conditions.
    
          // This line tells custom_lint to render a warning at the location of "node".
          // And the warning shown will use our `code` variable defined above as description.
          reporter.reportErrorForNode(code, node);
        });
      }
    }

That's it for defining a custom lint package!

If you're looking for a more advanced example, see the example. This example implements:

  • a lint appearing on all variables of a specific type
  • a quick fix for that lint
  • an "assist" for providing refactoring options.

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: ">=3.0.0 <4.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

Enabling/disabling and configuring lints

By default, custom_lint enables all installed lints.
But chances are you may want to disable one specific lint, or alternatively, disable all lints besides a few.

This configuration is done in your analysis_options.yaml, but in a slightly different manner.

Configurations are placed within a custom_lint object, as followed:

analyzer:
  plugins:
    - custom_lint

custom_lint:
  rules:
    - my_lint_rule: false # disable this rule

As mentioned before, all lints are enabled by default.

custom_lint:
  # Disable all lints by default
  enable_all_lint_rules: false
  rules:
    - my_lint_rule # only enable my_lint_rule

If you want to change this, you can optionally disable all lints by default:

Last but not least, some lint rules may be configurable. When a lint is configurable, you can configure it in the same place with:

custom_lint:
  rules:
    - my_lint_rule:
      some_parameter: "some value"

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.

Using the Dart debugger and enabling hot-reload

By default, custom_lint does enable hot-reload or give you the necessary information to start the debugger. This is because most users don't need those, and only lint authors do.

If you wish to debug lints, you'll have to update your analysis_options.yaml as followed:

analyzer:
  plugins:
    - custom_lint

custom_lint:
  debug: true
  # Optional, will cause custom_lint to log its internal debug information
  verbose: true

Then, to debug plugins in custom_lint, you need to connect to plugins using "attach" mode in your IDE (cmd+shift+p + Debug: attach to Dart process in VSCode).

When using this command, you will need a VM service URI provided by custom_lint.

There are two possible ways to obtain one:

  • if you started your plugin using custom_lint --watch, it should be visible in the console output.
  • if your plugin is started by your IDE, you can open the custom_lint.log file that custom_lint created next to the pubspec.yaml of your analyzed projects.

In both cases, what you're looking for is logs similar to:

The Dart VM service is listening on http://127.0.0.1:60671/9DS43lRMY90=/
The Dart DevTools debugger and profiler is available at: http://127.0.0.1:60671/9DS43lRMY90=/devtools/#/?uri=ws%3A%2F%2F127.0.0.1%3A60671%2F9DS43lRMY90%3D%2Fws

What you'll want is the first URI. In this example, that is http://127.0.0.1:60671/9DS43lRMY90=/. You can then pass this to your IDE, which should now be able to attach to the plugin.

Testing your plugins

Testing lints

Custom_lint comes with an official testing mechanism for asserting that your plugins correctly work.

Testing lints is straightforward: Simply write a file that should contain lints from your plugin (such as the example folder). Then, using a syntax similar to // ignore, write a // expect_lint: code in the line before your lint:

// expect_lint: riverpod_final_provider
var provider = Provider(...);

When doing this, there are two possible cases:

  • The line after the expect_lint correctly contains the expected lint. In that case, the lint is ignored (similarly to if we used // ignore)
  • The next line does not contain the lint. In that case, the expect_lint comment will have an error.

This allows testing your plugins by simply running custom_lint on your test/example folder. Then, if any expected lint is missing, the command will fail. But if your plugin correctly emits the lint, the command will succeed.

Testing quick fixes and assists

Testing quick fixes and assists is also possible with regular tests by combining them with pkg:analyzer to manually execute the assists or fixes. An example can be found in the Riverpod repository.


Built and maintained by Invertase.

dart_custom_lint's People

Contributors

adsonpleal avatar andrzejchm avatar biplab-dutta avatar charlescyt avatar giuspepe avatar k9i-0 avatar kuhnroyal avatar kzrnm avatar laurentschall avatar luckey-elijah avatar mafreud avatar mhadaily avatar mrgnhnt96 avatar nohli avatar piotrrogulski avatar praxder avatar rrousselgit avatar salakar avatar snapsl avatar srtonz avatar timwhiting avatar webdevleo avatar yamarkz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dart_custom_lint's Issues

Run tests in the CI

Currently tests are disabled in the CI because there's an unknown issue causing them to fail.

Dart Analysis Server always crashes whenever I launch my custom lint project on vs code

Describe the bug
Dart Analysis Server always crashes whenever I launch my custom lint project on vs code. The crash doesn't take place when I launch my other flutter projects.

flutter doctor -v
[✓] Flutter (Channel stable, 3.3.10, on Fedora Linux 37 (Workstation Edition) 6.0.17-300.fc37.x86_64, locale en_US.UTF-8)
    • Flutter version 3.3.10 on channel stable at /home/biplab-khalti/snap/flutter/common/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 135454af32 (3 weeks ago), 2022-12-15 07:36:55 -0800
    • Engine revision 3316dd8728
    • Dart version 2.18.6
    • DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /home/biplab-khalti/Android/Sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /var/lib/snapd/snap/android-studio/125/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 10.0.0-4ubuntu1
    • cmake version 3.16.3
    • ninja version 1.10.0
    • pkg-config version 0.29.1

[✓] Android Studio (version 2021.3)
    • Android Studio at /var/lib/snapd/snap/android-studio/125/android-studio
    • Flutter plugin version 71.0.3
    • Dart plugin version 213.7433
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)

[✓] VS Code (version 1.74.2)
    • VS Code at /usr/share/code
    • Flutter extension version 3.56.0

[✓] Connected device (2 available)
    • Linux (desktop) • linux  • linux-x64      • Fedora Linux 37 (Workstation Edition) 6.0.17-300.fc37.x86_64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 108.0.5359.124

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

Screenshot from 2023-01-08 22-32-09

Support //ignore

  • // ignore: rule
  • // ignore_for_file: rule
  • // ignore_for_file: type=lintÏ

Run all fixes via command line

It would be nice to have the command line fix all the problems where a fix exists.
Like dart fix --apply.

Maybe something like this already exists and I couldn't find it.

Deduplicate pending analysis tasks for the same file (high cpu)

Describe the bug
We have a fairly large dart project with 1000+ files. When using the custom_lint we're seeing high cpu usage for 1-2 minutes whenever we make multiple edits to a file (10+ key strokes).
We added logging to our own custom lint and can see that the same files get analysed several times in a row, up to 10-20 times. This in combination with big invalidation graphs (lots of files depend on the file being edited) causes a lot of repetetive analysis work in the code.

I can see that there are TODO-notes in the code related to this so it might not be working as intended. Also, it would be great if the (presumably costly) scheduling of getResolvedUnitResult() was debounced / deferred / deduplicated to avoid this cost.

I can provide a more details of the flow if you DM me.

Documentation about using my custom lints package locally.

Describe what scenario you think is uncovered by the existing examples/articles
I'm trying to create custom lints for my Flutter project. For that, I want to have the Dart package containing the custom lints locally, i.e. in the same directory as my Flutter project. I would like to know how to do that.

Describe why existing examples/articles do not cover this case
I could not find any documentation about it.

Additional context
To start using dart_custom_lint I tried first having the custom lints package project and an example app in the same folder to see if I could use it later with my Flutter project.

Here is the directory custom-lints containing the two projects:
image

app_custom_lints is the custom lints package that's using dart_custom_lint.

The code inside app_custom_lints/app_custom_lints.dart is the one from the README.md:

import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

// This is the entrypoint of our custom linter
PluginBase createPlugin() => _ExampleLinter();

/// A plugin class is used to list all the assists/lints defined by a plugin.
class _ExampleLinter extends PluginBase {
  /// We list all the custom warnings/infos/errors
  @override
  List<LintRule> getLintRules(CustomLintConfigs configs) => [
        MyCustomLintCode(),
      ];
}

class MyCustomLintCode extends DartLintRule {
  MyCustomLintCode() : super(code: _code);

  /// Metadata about the warning that will show-up in the IDE.
  /// This is used for `// ignore: code` and enabling/disabling the lint
  static const _code = LintCode(
    name: 'my_custom_lint_code',
    problemMessage: 'This is the description of our custom lint',
  );

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) {
    // Our lint will highlight all variable declarations with our custom warning.
    context.registry.addVariableDeclaration((node) {
      // "node" exposes metadata about the variable declaration. We could
      // check "node" to show the lint only in some conditions.

      // This line tells custom_lint to render a waring at the location of "node".
      // And the warning shown will use our `code` variable defined above as description.
      reporter.reportErrorForNode(code, node);
    });
  }
}

The code inside app_custom_lints/pubspec.yaml is the one from the README.md:

name: app_custom_lints
environment:
  sdk: ">=2.18.6 <3.0.0"

dependencies:
  analyzer: 
  analyzer_plugin:
  custom_lint_builder:

The code inside example_app/main.dart is just:

void main() {
  
}

The code inside example_app/analysis_options.yaml is the one from the README.md:

analyzer:
  plugins:
    - custom_lint

Same with the code inside example_app/pubspec.yaml, but adding a relative path to the package dependency:

name: example_app
environment:
  sdk: ">=2.16.0 <3.0.0"
dev_dependencies:
  custom_lint:
  app_custom_lints:
    path: ../app_custom_lints

On both project dart pub get runs just fine, with exit code 0. The problem is that the analysis server crashes.
Here the log:

[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common\bin
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\emulator
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\emulator\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\cmdline-tools\latest\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\platform-tools
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\platform-tools\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Java\jdk-18.0.2.1\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3\condabin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3\condabin\bin
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\dotnet-core-uninstall\
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\dotnet-core-uninstall\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Docker\Docker\resources\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\PowerShell\7\
[5:17:48 PM] [General] [Info]         C:\Program Files\PowerShell\7\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Pub\Cache\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS
[5:17:48 PM] [General] [Info]         C:\WINDOWS\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\Wbem
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\Wbem\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\WindowsPowerShell\v1.0\
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\WindowsPowerShell\v1.0\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\OpenSSH\
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\OpenSSH\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\nodejs\
[5:17:48 PM] [General] [Info]         C:\Program Files\nodejs\bin
[5:17:48 PM] [General] [Info]         C:\ProgramData\chocolatey\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\Scripts\
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\Scripts\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Microsoft\WindowsApps
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Microsoft\WindowsApps\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Microsoft VS Code\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\oh-my-posh\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\.dotnet\tools
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\.dotnet\tools\bin
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\Atmel\Flip 3.4.7\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Roaming\npm
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Roaming\npm\bin
[5:17:48 PM] [General] [Info]     Found at:
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin
[5:17:48 PM] [General] [Info]     Candidate paths to be post-filtered:
[5:17:48 PM] [General] [Info]         C:\src\flutter
[5:17:48 PM] [General] [Info]     Found at C:\src\flutter
[5:17:48 PM] [General] [Info]     Returning SDK path C:\src\flutter for flutter.bat
[5:17:48 PM] [General] [Info] Searching for dart.exe
[5:17:48 PM] [General] [Info]     Looking for dart.exe in:
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\Razer Chroma SDK\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Razer Chroma SDK\bin
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\Razer\ChromaBroadcast\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Razer\ChromaBroadcast\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS
[5:17:48 PM] [General] [Info]         C:\WINDOWS\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\Wbem
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\Wbem\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\WindowsPowerShell\v1.0\
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\WindowsPowerShell\v1.0\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\OpenSSH\
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\OpenSSH\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR
[5:17:48 PM] [General] [Info]         C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\dotnet\
[5:17:48 PM] [General] [Info]         C:\Program Files\dotnet\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Git\cmd
[5:17:48 PM] [General] [Info]         C:\Program Files\Git\cmd\bin
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common\bin
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\emulator
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\emulator\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\cmdline-tools\latest\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\platform-tools
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Android\Sdk\platform-tools\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Java\jdk-18.0.2.1\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3\condabin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\miniconda3\condabin\bin
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\dotnet-core-uninstall\
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\dotnet-core-uninstall\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\Docker\Docker\resources\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\PowerShell\7\
[5:17:48 PM] [General] [Info]         C:\Program Files\PowerShell\7\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Pub\Cache\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32
[5:17:48 PM] [General] [Info]         C:\WINDOWS\system32\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS
[5:17:48 PM] [General] [Info]         C:\WINDOWS\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\Wbem
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\Wbem\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\WindowsPowerShell\v1.0\
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\WindowsPowerShell\v1.0\bin
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\OpenSSH\
[5:17:48 PM] [General] [Info]         C:\WINDOWS\System32\OpenSSH\bin
[5:17:48 PM] [General] [Info]         C:\Program Files\nodejs\
[5:17:48 PM] [General] [Info]         C:\Program Files\nodejs\bin
[5:17:48 PM] [General] [Info]         C:\ProgramData\chocolatey\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\Scripts\
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\Scripts\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Python\Python311\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Microsoft\WindowsApps
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Microsoft\WindowsApps\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\Microsoft VS Code\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Local\Programs\oh-my-posh\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\.dotnet\tools
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\.dotnet\tools\bin
[5:17:48 PM] [General] [Info]         C:\Program Files (x86)\Atmel\Flip 3.4.7\bin
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Roaming\npm
[5:17:48 PM] [General] [Info]         C:\Users\Marcos\AppData\Roaming\npm\bin
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin\cache\dart-sdk
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin\cache\dart-sdk\bin
[5:17:48 PM] [General] [Info]     Found at:
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin\cache\dart-sdk\bin
[5:17:48 PM] [General] [Info]     Candidate paths to be post-filtered:
[5:17:48 PM] [General] [Info]         C:\src\flutter\bin\cache\dart-sdk
[5:17:48 PM] [General] [Info]     Found at C:\src\flutter\bin\cache\dart-sdk
[5:17:48 PM] [General] [Info]     Returning SDK path C:\src\flutter\bin\cache\dart-sdk for dart.exe
[5:17:48 PM] [General] [Info] Experiment random number is 26 for experiment 'sdkDaps'. Experiment is enabled for <= 10
[5:17:48 PM] [General] [Info] Experiment 'sdkDaps' does not apply and will not be activated
[5:17:48 PM] [General] [Info] !! PLEASE REVIEW THIS LOG FOR SENSITIVE INFORMATION BEFORE SHARING !!

Dart Code extension: 3.50.0
Flutter extension: 3.50.0 (not activated)

App: Visual Studio Code
Version: 1.75.1
Platform: win

Workspace type: Dart
Analyzer type: LSP
Multi-root?: false

Dart SDK:
    Loc: C:\src\flutter\bin\cache\dart-sdk
    Ver: 2.18.6
Flutter SDK:
    Loc: C:\src\flutter
    Ver: 3.3.10

HTTP_PROXY: undefined
NO_PROXY: undefined
[5:17:48 PM] [Analyzer] [Info] Spawning C:\src\flutter\bin\cache\dart-sdk\bin\dart.exe with args ["language-server","--protocol=lsp","--client-id=VS-Code","--client-version=3.50.0"]
[5:17:48 PM] [Analyzer] [Info]     PID: 23616
[5:17:48 PM] [General] [Info] Returning cached results for project search
[5:17:48 PM] [General] [Info] Extension:Startup timing: 417ms
[5:17:48 PM] [General] [Info] Found 0 folders requiring "pub get":
[5:17:48 PM] [Analyzer] [Info] ==> Content-Length: 6285
[5:17:48 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":7620,"clientInfo":{"name":"Visual Studio Code","version":"1.75.1"},"locale":"en-us","rootPath":"d:\\_Meh\\_Projects\\custom-lints","rootUri":"file:///d%3A/_Meh/_Projects/custom-lints","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional","normalizesLineEndings":true,"changeAnnotationSupport":{"groupsOnL…
[5:17:48 PM] [General] [Info] Caching Pub package names from pub.dev...
[5:17:49 PM] [Analyzer] [Info] <== Content-Length: 398
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:49 PM] [Analyzer] [Info] <== {"id":0,"jsonrpc":"2.0","result":{"capabilities":{"executeCommandProvider":{"commands":["edit.sortMembers","edit.organizeImports","edit.fixAll","edit.sendWorkspaceEdit","refactor.perform"],"workDoneProgress":true},"workspace":{"workspaceFolders":{"changeNotifications":true,"supported":true}},"workspaceSymbolProvider":true},"serverInfo":{"name":"Dart SDK LSP Analysis Server","version":"2.18.6"}}}
[5:17:49 PM] [Analyzer] [Info] ==> Content-Length: 86
[5:17:49 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","method":"initialized","params":{},"clientRequestTime":1677428269392}
[5:17:49 PM] [General] [Info] Analyzer:Startup timing: 1083ms
[5:17:49 PM] [Analyzer] [Info] <== Content-Length: 170
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"id":1,"jsonrpc":"2.0","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///d:/_Meh/_Projects/custom-lints","section":"dart"},{"section":"dart"}]}}
[5:17:49 PM] [Analyzer] [Info] ==> Content-Length: 6727
[5:17:49 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":1,"result":[{"additionalAnalyzerFileExtensions":[],"analysisExcludedFolders":[],"analyzeAngularTemplates":true,"analyzerAdditionalArgs":[],"analyzerDiagnosticsPort":null,"analyzerPath":null,"analyzerSshHost":null,"analyzerVmServicePort":null,"notifyAnalyzerErrors":true,"onlyAnalyzeProjectsWithOpenFiles":false,"showTodos":false,"useLegacyAnalyzerProtocol":false,"updateDevTools":true,"devToolsBrowser":"default","devToolsPort":null,"devToolsReuseWindows":true,"devToolsThem…
[5:17:51 PM] [Analyzer] [Info] <== Content-Length: 165
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:52 PM] [Analyzer] [Info] <== {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[],"uri":"file:///d:/_Meh/_Projects/custom-lints/app_custom_lints/pubspec.yaml"}}Content-Length: 169
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[],"uri":"file:///d:/_Meh/_Projects/custom-lints/example_app/analysis_options.yaml"}}
[5:17:52 PM] [Analyzer] [Info] <== Content-Length: 160
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:52 PM] [Analyzer] [Info] <== {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[],"uri":"file:///d:/_Meh/_Projects/custom-lints/example_app/pubspec.yaml"}}Content-Length: 97
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:52 PM] [Analyzer] [Info] <== {"id":2,"jsonrpc":"2.0","method":"window/workDoneProgress/create","params":{"token":"ANALYZING"}}
[5:17:52 PM] [Analyzer] [Info] <== Content-Length: 4667
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 72
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":2,"result":null,"clientRequestTime":1677428272238}
[5:17:52 PM] [Analyzer] [Info] <== {"id":3,"jsonrpc":"2.0","method":"client/registerCapability","params":{"registrations":[{"id":"0","method":"textDocument/didOpen","registerOptions":{"documentSelector":[{"language":"dart","scheme":"file"},{"language":"yaml","pattern":"**/pubspec.yaml","scheme":"file"},{"language":"yaml","pattern":"**/analysis_options.yaml","scheme":"file"},{"language":"yaml","pattern":"**/lib/fix_data.yaml","scheme":"file"}]}},{"id":"1","method":"textDocument/didClose","registerOptions":{"documentSelector":[…
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 72
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":3,"result":null,"clientRequestTime":1677428272254}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 449
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/pubspec.yaml","languageId":"yaml","version":1,"text":"# The pubspec.yaml of an application using our lints\r\nname: example_app\r\nenvironment:\r\n  sdk: \">=2.16.0 <3.0.0\"\r\n\r\ndev_dependencies:\r\n  custom_lint:\r\n  app_custom_lints:\r\n    path: ../app_custom_lints\r\n"}},"clientRequestTime":1677428272254}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 248
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart","languageId":"dart","version":1,"text":"void main() {\r\n  \r\n}"}},"clientRequestTime":1677428272254}
[5:17:52 PM] [Analyzer] [Info] <== Content-Length: 118
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"jsonrpc":"2.0","method":"$/progress","params":{"token":"ANALYZING","value":{"kind":"begin","title":"Analyzing…"}}}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 196
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":1,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"}},"clientRequestTime":1677428272257}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 195
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":2,"method":"textDocument/documentColor","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"}},"clientRequestTime":1677428272260}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 311
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"},"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"context":{"diagnostics":[],"triggerKind":2}},"clientRequestTime":1677428272266}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 194
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":4,"method":"textDocument/foldingRange","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"}},"clientRequestTime":1677428272491}
[5:17:52 PM] [Analyzer] [Info] ==> Content-Length: 96
[5:17:52 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","method":"$/cancelRequest","params":{"id":3},"clientRequestTime":1677428272710}
[5:17:53 PM] [Analyzer] [Info] <== Content-Length: 157
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:53 PM] [Analyzer] [Info] ==> Content-Length: 223
[5:17:53 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":5,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"},"position":{"line":0,"character":8}},"clientRequestTime":1677428273077}
[5:17:53 PM] [Analyzer] [Info] <== {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[],"uri":"file:///d:/_Meh/_Projects/custom-lints/example_app/main.dart"}}
[5:17:53 PM] [Analyzer] [Info] <== Content-Length: 159
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:53 PM] [Analyzer] [Info] <== {"jsonrpc":"2.0","method":"dart/textDocument/publishClosingLabels","params":{"labels":[],"uri":"file:///d:/_Meh/_Projects/custom-lints/example_app/main.dart"}}
[5:17:53 PM] [Analyzer] [Info] <== Content-Length: 756
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"jsonrpc":"2.0","method":"dart/textDocument/publishOutline","params":{"outline":{"children":[{"codeRange":{"end":{"character":1,"line":2},"start":{"character":0,"line":0}},"element":{"kind":"FUNCTION","name":"main","parameters":"()","range":{"end":{"character":9,"line":0},"start":{"character":5,"line":0}},"returnType":"void"},"range":{"end":{"character":1,"line":2},"start":{"character":0,"line":0}}}],"codeRange"…
[5:17:53 PM] [Analyzer] [Info] <== {"id":1,"jsonrpc":"2.0","result":[{"deprecated":false,"detail":"()","kind":12,"name":"main","range":{"end":{"character":1,"line":2},"start":{"character":0,"line":0}},"selectionRange":{"end":{"character":9,"line":0},"start":{"character":5,"line":0}}}]}Content-Length: 36
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"id":2,"jsonrpc":"2.0","result":[]}Content-Length: 1129
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"id":3,"jsonrpc":"2.0","result":[{"command":{"ar…
[5:17:53 PM] [Analyzer] [Info] ==> Content-Length: 223
[5:17:53 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":6,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"},"position":{"line":0,"character":7}},"clientRequestTime":1677428273973}
[5:17:54 PM] [Analyzer] [Info] <== Content-Length: 178
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:54 PM] [Analyzer] [Info] <== {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[],"uri":"file:///d:/_Meh/_Projects/custom-lints/app_custom_lints/lib/app_custom_lints.dart"}}
[5:17:54 PM] [Analyzer] [Info] <== Content-Length: 189
Content-Type: application/vscode-jsonrpc; charset=utf-8
[5:17:54 PM] [Analyzer] [Info] <== {"id":6,"jsonrpc":"2.0","result":{"contents":{"kind":"markdown","value":"```dart\nvoid main()\n```\n*main.dart*"},"range":{"end":{"character":9,"line":0},"start":{"character":5,"line":0}}}}
[5:17:54 PM] [Analyzer] [Info] <== Content-Length: 93
Content-Type: application/vscode-jsonrpc; charset=utf-8

{"jsonrpc":"2.0","method":"$/progress","params":{"token":"ANALYZING","value":{"kind":"end"}}}
[5:17:54 PM] [General] [Info] Analyzer:FirstAnalysis timing: 2367ms
[5:17:55 PM] [Analyzer] [Error] ../../runtime/vm/message_snapshot.cc: 576: error: expected: !lib.IsNull()
version=2.
[5:17:55 PM] [Analyzer] [Error] 18.6 (stable) (Tue Dec 13 21:15:14 2022 +0000) on "windows_x64"
pid=11912, thread=22096, isolate_group=main(0000020BEA30DCC0), isolate=main(0000020BEA2F29D0)
isolate_instructions=7ff6d5d466d0, vm_instructions=7ff6d5d466e0
[5:17:55 PM] [Analyzer] [Error]   pc 0x00007ff6d5f50202 fp 0x0000009636bfeb20 Dart_IsPrecompiledRuntime+0x21ef62
[5:17:55 PM] [Analyzer] [Error] 
-- End of DumpStackTrace
[5:17:55 PM] [Analyzer] [Info] ==> Content-Length: 223
[5:17:55 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":7,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///d%3A/_Meh/_Projects/custom-lints/example_app/main.dart"},"position":{"line":0,"character":8}},"clientRequestTime":1677428275066}
[5:17:55 PM] [Analyzer] [Info] Spawning C:\src\flutter\bin\cache\dart-sdk\bin\dart.exe with args ["language-server","--protocol=lsp","--client-id=VS-Code","--client-version=3.50.0"]
[5:17:55 PM] [Analyzer] [Info]     PID: 32920
[5:17:55 PM] [Analyzer] [Info] ==> Content-Length: 6285
[5:17:55 PM] [Analyzer] [Info] ==> {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":7620,"clientInfo":{"name":"Visual Studio Code","version":"1.75.1"},"locale":"en-us","rootPath":"d:\\_Meh\\_Projects\\custom-lints","rootUri":"file:///d%3A/_Meh/_Projects/custom-lints","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional","normalizesLineEndings":true,"changeAnnotationSupport":{"groupsOnL…

And VSCode shows:
image

Even after I reset the analysis server.

I'm using:

  • Windows 11 Pro 22H2
  • Visual Studio Code v1.75.1
  • VSCode Dart extension v3.50.0

Thanks!

No quick fixes on the last character of the error

Describe the bug
Quick fixes menu is missing my rule fix, if the menu is opened with the cursor placed on the last character of the error span (offset + length).

To Reproduce
Create the following rule and open the quick fix menu on the last character of the reported error.

import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

class TestRule extends DartLintRule {
  TestRule() : super(code: TestCode());

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) =>
      context.registry.addClassDeclaration((node) {
        reporter.reportErrorForNode(TestCode(), node);
      });

  @override
  List<Fix> getFixes() => [
        TestFix(),
      ];
}

class TestCode extends LintCode {
  TestCode()
      : super(
          name: 'test_rule',
          problemMessage: 'This is a test rule.',
        );
}

class TestFix extends DartFix {
  @override
  void run(
    CustomLintResolver resolver,
    ChangeReporter reporter,
    CustomLintContext context,
    AnalysisError analysisError,
    List<AnalysisError> others,
  ) =>
      reporter.createChangeBuilder(
        message: 'Test Fix',
        priority: 0,
      );
}

Expected behavior
The menu contains TestFix entry, when the cursor is placed directly before, inside or directly after the reported error.

Actual behavior
With the cursor placed directly before or inside of the report:
image
With the cursor placed directly after the report:
image

Leftover client processes

Describe the bug
custom_lint client processes are not being shut down.
This is on version 0.2.0.

Bildschirm­foto 2023-01-31 um 12 10 34

To Reproduce
Every time the analysis server restarts, there are 2 new left over processes:
1x dart:custom_lint_client.dart
1x dart:dds.dart.snapshot

In the screenshot I was able to reproduce this by just pressing Restart Analysis Server in IntelliJ.

Expected behavior
The processes should be shut down when the client is shut down.

Bad state: Two ContextRoots Error with Sub Packages

Describe the bug
I am trying to use riverpod_lint, but I get this error when I run dart run custom_lint. This happens when I am using melos with a packages directory. I have reproduced it without using melos.

The request analysis.setContextRoots failed with the following error:
RequestErrorCode.PLUGIN_ERROR
Bad state: Two ContextRoots depend on _fe_analyzer_shared but use different version,
therefore custom_lint does not know which one to pick.
- file:///Users/boolean/.pub-cache/hosted/pub.dev/_fe_analyzer_shared-53.0.0/
- file:///Users/boolean/.pub-cache/hosted/pub.dev/_fe_analyzer_shared-52.0.0/

at:
#0      _writePackageConfigForTempProject (package:custom_lint/src/v2/server_to_client_channel.dart:96:9)
#1      _SocketCustomLintServerToClientChannel.init (package:custom_lint/src/v2/server_to_client_channel.dart:255:5)
#2      CustomLintServer._maybeSpawnCustomLintPlugin (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:289:25)
<asynchronous suspension>
#3      CustomLintServer._handleAnalysisSetContextRoots.<anonymous closure> (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:264:9)
<asynchronous suspension>
#4      PendingOperation.run (package:custom_lint/src/async_operation.dart:14:14)
<asynchronous suspension>
#5      CustomLintServer._handleRequest (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:124:22)
<asynchronous suspension>

To Reproduce

I have reproduced it in a separate flutter project without melos. A dart subpackage models is a dependency of the app. The command works if I delete the packages folder (and remove the models dependency).

  1. Clone repo
  2. flutter pub get
  3. cd packages/models
  4. dart pub get
  5. cd ../..
  6. dart run custom_lint (see above output)

Expected behavior
dart run custom_lint should output that ProviderScope should be used

Integrating with Android Studio

Describe what scenario you think is uncovered by the existing examples/articles
It integrates well with VSCode and I can see lint info in the IDE itself. But when I opened the project in Android Studio, the custom lint messages won't appear.

Describe why existing examples/articles do not cover this case
I couldn't find any documentation that says how to make it work on Android Studio.

Additional context
I use VSCode but many of my colleagues use Android Studio, so support for it will be really helpful

Consider simplifying package usage

Issue:
The current PluginBase class requires overriding the getLints method and returning a Stream<Lint> without providing guidance or structure on how all the custom lints are to be provided. Users of this package must design their own way to go from a ResolvedUnitResult to yielding Lints.

To be more clear, when creating a single custom lint, the current implementation works fine (like your final providers lint in the example folder). The issue happens when trying to define multiple lints. How do we make lints easy to add/remove? How do we avoid getLints from becoming a giant method full of different lints? How do we decouple lints but also let them share an AstVisitor to speed up processing?

Essentially:

  1. Lints aren't easily sharable because everyone will implement them differently
  2. It's hard to get started writing custom lints because you don't just write the lint, you have to connect it with the PluginBase too
  3. Related to point 2, there's more code to test as well, as users (who like to test their code, at least) must test their PluginBase too.

Solution:
Expect users to supply lint rules instead of a PluginBase.

I anticipate showing code will be the best way to explain this.

This code would be added to the custom_lint package (it's just an example, doesn't need to be done this way).

import 'dart:async';

import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/source/line_info.dart';

//ignore: implementation_imports
import 'package:analyzer/src/lint/linter_visitor.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:example_lints/src/rules/example_rule.dart';

final List<ExampleLintRule> rules = [
  ExampleRule(),
];

// In this example, I extend PluginBase, but if you use my idea, the PluginBase can be modified
// itself instead.
//
// This class implements AnalysisErrorListener from the analyzer package so that it's onError
// method will be called when each rule reports a lint.
class ExamplePluginBase extends PluginBase implements AnalysisErrorListener {
  late StreamController<Lint> _streamController;

  @override
  Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) {
    _streamController = StreamController<Lint>();

    // For the stream to work, it must work specifically in this order:
    // 1. Be created
    // 2. Be listened to (by being returned from this method)
    // 3. Have lints added
    // 4. Be closed
    //
    // If any of these steps are out of order, the stream will not work
    // correctly and lints will never be reported.
    //
    // Thus, the method which does to processing is done in an unawaited future
    // so that step 2 can happen before 3 or 4.
    unawaited(process(resolvedUnitResult));

    return _streamController.stream;
  }

  Future<void> process(ResolvedUnitResult resolvedUnitResult) async {
    // To speed up analysis, a single visitor is created, which will find each
    // AST node and send it to any registration from the registry.
    final registry = NodeLintRegistry(false);
    final visitor = LinterVisitor(registry);

    // When an ExampleLintRule finds a lint error, this reporter will send it
    // to the onError method below.
    final reporter = ErrorReporter(
      this,
      resolvedUnitResult.libraryElement.source,
      isNonNullableByDefault: true,
    );

    for (final rule in rules) {
      rule.reporter = reporter;
      rule.registerNodeVisitors(registry, resolvedUnitResult);
    }

    // Visit the AST tree.
    resolvedUnitResult.unit.visitChildren(visitor);

    // We have to be sure to close the stream, or the stream will be listened to indefinitely!
    _streamController.close();
  }

  // Any time a rule reports an error, we convert it to a Lint and send to the stream.
  @override
  void onError(AnalysisError error) {
    LineInfo lineInfo = LineInfo.fromContent(error.source.contents.data);

    final startLocation = lineInfo.getLocation(error.offset);
    final endLocation = lineInfo.getLocation(error.offset + error.length);

    _streamController.add(Lint(
      code: error.errorCode.name,
      message: error.message,
      location: LintLocation(
        offset: error.offset,
        length: error.length,
        startLine: startLocation.lineNumber,
        startColumn: startLocation.columnNumber,
        endLine: endLocation.lineNumber,
        endColumn: endLocation.columnNumber,
        filePath: error.source.uri.path,
      ),
    ));
  }
}

// Here we make our own version of a LintRule from the analyzer package.
abstract class ExampleLintRule extends LintRule {
  final LintSeverity severity;
  // I'm not sure if we need the group, or if we can just always make it Group.style.
  final Group lintGroup;
  final String message;
  final String code;
  final String? url;

  ExampleLintRule({
    required this.severity,
    required this.lintGroup,
    required this.message,
    required this.code,
    this.url,
  }) : super(
          name: code,
          group: lintGroup,
          description: message,
          details: 'No details',
        );

  // The original `registerNodeProcessors` method of the LintRule class expects to be given
  // a LinterContext, which we can't provide, so we make this method instead.
  void registerNodeVisitors(
      NodeLintRegistry registry, ResolvedUnitResult resolvedUnitResult);
}

Then for a user to define a lint rule, it's just a matter of defining an ExampleLintRule.

Here's the rewritten version of the final provider rule in the example folder.

bool _isProvider(DartType type) {
  final element = type.element! as ClassElement;
  final source = element.librarySource.uri;

  final isProviderBase = source.scheme == 'package' &&
      source.pathSegments.first == 'riverpod' &&
      element.name == 'ProviderBase';

  return isProviderBase || element.allSupertypes.any(_isProvider);
}

class FinalProviders extends ExampleLintRule {
  FinalProviders()
      : super(
          code: 'riverpod_final_provider',
          severity: LintSeverity.warning,
          message: r'Providers should always be declared as final',
        );

  @override
  void registerNodeVisitors(
      NodeLintRegistry registry, ResolvedUnitResult resolvedUnitResult) {
    var visitor = _Visitor(this);
    registry.addVariableDeclaration(this, visitor);
  }
}

class _Visitor extends SimpleAstVisitor<void> {
  final LintRule rule;

  _Visitor(this.rule);

  @override
  void visitVariableDeclaration(VariableDeclaration node) {
    final element = node.declaredElement2;
    if (element != null && !element.isFinal && _isProvider(element.type)) {
      rule.reportLint(node);
    }
  }
}

The benefits of this are:

  1. Rules are sharable as they share a common interface
  2. They are easier to write because instead of using resolvedUnitResult.libraryElement.topLevelElements.where(...).where(...), we visit variable declarations and use an if statement
  3. It reuses existing code from the analyzer package
  4. Relating to point 3, these rules are also written extremely similarly to the rules from the dart linter itself, making them potentially swappable in the future, or at least makes it easier to create a rule based of a dart lint.
  5. It speeds up the processing of lint rules (if you have multiple) because we use a NodeLintRegistry so that PluginBase can create a single AstVisitor instead of each rule visiting the tree itself (they use a Visitor, but, it doesn't actually do any visiting...)

My code is a proof of concept and doesn't have to be the route you go, of course. You may use any, none, or all of it.

Conclusion:
The interaction with the custom_lint package can be greatly simplified by allowing users to define rules instead of a PluginBase.

In fact, with this approach, you could modify the startPlugin method to require a list of rules instead of a PluginBase. The startPlugin method would create the PluginBase itself and give it the rules (if a PluginBase is even required anymore).

final rules = [
  FinalProviders(),
  AnotherExampleLintRule(),
  //ARuleThatIsEasilyTemporarilyDisabledByCommentingItOut(),
  // This could allow for people to share their lints by publishing packages with lint rules! Like:
  ARuleFromSomebodyElsesPackage(),
];

void main(List<String> args, SendPort sendPort) {
  startPlugin(sendPort, rules);
}

Also, this could possibly solve #50, or at least get closer.

Depending on the implementation, this doesn't have to be a breaking change.

Support for Quick Assists

Hello,

At the moment dart_custom_lint is capable of supporting custom quick fixes, and that's great.
Do you think we can do the same thing to support quick assists too?

Enforcing dart documentation

I wanted to ask if it is possible to create a linter rule that enforces dart documentation ? Like it checks if the class, its methods and attributes are properly documented and follow dart doc guidelines.
Does any rule like this already exist ? If no, then can you please hint me in the right direction so that I can create one ?

Dependency on riverpod 2.0.0-dev.9

custom_lint 0.0.9+1 depends on riverpod 2.0.0-dev.9 meaning we cannot using while using stable riverpod 1.0.3.
Is there something that can be done about it besides switching to dev version of Riverpod?

Optimize analysis speed for large projects

Running the custom lint analysis slows down disproportionately for large projects. This is a huge impediment for using custom_lint on large projects.

I have made some measurements on a very small project and a large project with one custom linter which yields a lint for each file and one custom linter which yields nothing at all. There was no significant difference between the two custom linters. As a baseline, I used dart analyze.
The measurements were conducted on a MacBook Pro (M1 Max, 32 GB RAM).

baseline (dart analyze) flutter pub run custom_lint
small project 3 seconds 17 seconds
large project 11 seconds 753 seconds

The small project was created with flutter create small_project and thus only has 2 dart files with 145 lines of code. The large project has 3285 dart files with 282901 lines of code.

It would be great if the performance of custom_lint could be improved to come close to the performance of dart analyze. The current performance issues make custom_lint practically unusable on large projects, even though large projects are the ones that would benefit the most from using custom_lint. I'd be glad to help out too if you provide me with some guidance 😊

Output of flutter doctor -v
[✓] Flutter (Channel stable, 3.0.4, on macOS 12.2.1 21D62 darwin-arm, locale en-DE)
    • Flutter version 3.0.4 at /Users/giuseppecianci/fvm/versions/stable
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 85684f9300 (12 days ago), 2022-06-30 13:22:47 -0700
    • Engine revision 6ba2af10bb
    • Dart version 2.17.5
    • DevTools version 2.12.2

[!] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/giuseppecianci/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 13.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.69.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.44.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 12.2.1 21D62 darwin-arm
    • Chrome (web)    • chrome • web-javascript • Google Chrome 103.0.5060.114

[✓] HTTP Host Availability
    • All required HTTP hosts are available

Add quick fix "Add // expect_lint"

Similar to the built-in "ignore for this line", we could have an "expect lint for this line"

This would both make it simpler to use the feature and help its discoverability

Incorrect documentation for how to use hot restart/reload

Docs say:

First, create a tools/custom_lint_debug.dart file next to tools/custom_lint.dart with the following content:

import 'dart:io';
import 'package:custom_lint/basic_runner.dart';

void main() {
  await customLint(workingDirectory: Directory.current.parent);
}

We never created a tools/custom_lint.dart file but a bin/custom_lint.dart file, so where the former came from?

Once I created a tools/custom_lint_debug.dart file (without having a tools/custom_lint.dart file), after running it (or should I not run it?), I get the following error:

Bad state: No pubspec.yaml found at /Users/me/flutter/packages/flutter/.

2nd issue. The code is also missing an async.

void main () async { ...} // added async

Asynchronous lints

Is your feature request related to a problem? Please describe.
It would be nice to allow for asynchronous lint rules and/or post run callbacks. Some of the methods from the analyzer return a future (in my case AnalysisSession.getResolvedLibraryByElement) and currently the best (and only) way to handle these is to use waitFor from dart:cli which is deprecated and not something a published package should rely on.

Describe the solution you'd like
Update most linter/callback APIs to take FutureOr<void> instead of void as the return types of functions.

Describe alternatives you've considered
waitFor could be used, but it isn't great as mentioned above. We could also of course use analyzer_plugin directly and forego this package but this isn't such a complex task that we need this.

Additional context
I am willing to put forward a PR for this as I will be trying to implement it for my own use in my own fork anyway.

Running in CI pipeline fails because plugin is loading

My custom linter works fine in the IDE and when run on the terminal with flutter pub run custom_lint.
But when I try to run flutter analyze in a CI pipeline to analyze my code for the default lints, I get this output and the command fails:

Analyzing my_app...                                        

warning • The plugin is currently starting • pubspec.yaml:121:2 • custom_lint_plugin_loading

1 issue found. (ran in 101.0s)

I've tried adding another CI step before the flutter analyze step which executes the custom linter first. The flutter pub run custom_lint CI step works fine, but even after that step finished I still get the above error when running flutter analyze in subsequent CI step.

Is there a way to wait until the plugin has started? Or is there some workaround so I can use custom_lint in a CI pipeline?

[Feature request] Project path

I'm currently working on a custom lint which works with my library for strings localization and I have a file containing all the available keys so the user will be notified on the debug console if he's using an invalid keyword.

It would be nice to have something to fetch the project directory so it would be possible to read local files on the plugin initialization like:

PluginBase createPlugin() => _CustomPlugin();

class _CustomPlugin extends PluginBase {
  _CustomPlugin() {
    final file = File('$projectDir/filename');
  }
}

Error when "subprojects" exist

I have a root project with a couple "subprojects"/packages in packages/xyz.

Somehow custom_lint traverses these folders and is looking for .dart_tool/package_config.json inside, which may not exist.

Bad state: No /Users/me/workspace/my-app/packages/xyz/.dart_tool/package_config.json found. Make sure to run `pub get` first.

Accessing `nameLintLocation` of import statements returns `null`

Goal

A custom lint rule that checks the import statements of a given file.

Code Snipped

Stream<Lint> getLints(ResolvedUnitResult unit) async* {
    final imports = unit.libraryElement.imports;
    final import = imports.first;
    ...
    yield Lint(
        severity: LintSeverity.error,
        code: 'code',
        message: 'message',
        correction: 'correction',
        location: import.nameLintLocation,
    );
}

Expected

To access the import.nameLintLocation property to yield a lint at a given location of the import statement.

Result

import.nameLintLocation returns null

Fuse all plugins into one

It'd be ideal if all plugins were fused into one, so that each implementation of custom_lint could share resources with one another. On analysis_options.yaml changes, we would fuse all plugins into one by doing something like the following (sudo code):

import 'package:my_plugin/my_plugin.dart' as plugin1;
import 'package:another/another.dart' as plugin2;

void main() {
  plugin1.main();
  plugin2.main();
}

Currently waiting for PRs to close to avoid any merge conflicts downstream, including: #26

Improve error message when there are conflicting package versions

It's be great if the error message about conflicting dependency versions in 2+ contextroots could include:

  • the package names causing the problem
  • suggest to run "pub upgrade" in both packages
  • suggest checking that the pubspecs correctly allow the version everywhere

After Applying Quick Fix throws InconsistentAnalysisException

Sometimes after applying a custom DartFix the analyzer session crashes with
InconsistentAnalysisException: Requested result might be inconsistent with previously returned results
custom_lint.log

It does not happen all the time (haven't found a reliable way to reproduce)
But when it happens the custom list stays even though it's fixed, and it let's me apply the fix multiple times.

Custom lints not showing lint warnings in IDEs at all

So, I was working on some lints and everything was fine until yesterday. I created my lint, had it working and then I went saved my work, and went to bed. The next day when I tried opening the same project, the lints are not getting displayed at all. I had other lint projects too and none of them are working. I have all the dependencies and dev_dependencies properly configured.

Update CLI to output severity

It would be helpful for CI/CD if the custom_lint CLI output the severity of the lint. For example, perhaps I want to fail PR's that trigger a lint of 'error' severity, but don't want to fail it for 'warning' or 'info' lints.

Support git dependency for plugins

I created a lint_package and tried to use this package within my application:

1. Project structure

lint_package structure
pubspec.yaml

dependencies:
  analyzer: ^4.2.0
  analyzer_plugin: ^0.10.0
  custom_lint_builder: ^0.0.9+1

In my custom_lint file (bin/custom_lint.dart) I have several imports:

import 'dart:isolate';

import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

application structure
pubspec.yaml

dependencies:
  custom_lint:
  lint_package:
     git:
        url: [...]
        ref: [...]

analysis_options.yaml

analyzer:
  plugins:
    - custom_lint

2. Problem

When running flutter pub get or dart run custom_lint within my application I get the following error:

IsolateSpawnException: Unable to spawn isolate: Error: Error when reading '**/.pub_cache/**/lint_package/.dart_tool/package_config.json': No such file or directory
Error: Couldn't resolve the package 'analyzer' in 'package:analyzer/dart/analysis/results.dart'.
Error: Couldn't resolve the package 'analyzer' in 'package:analyzer/dart/ast/ast.dart'.
Error: Couldn't resolve the package 'analyzer' in 'package:analyzer/dart/element/type.dart'.
Error: Couldn't resolve the package 'analyzer' in 'package:analyzer/source/source_range.dart'.
Error: Couldn't resolve the package 'analyzer_plugin' in 'package:analyzer_plugin/protocol/protocol_generated.dart'.
Error: Couldn't resolve the package 'analyzer_plugin' in 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'.
Error: Couldn't resolve the package 'custom_lint_builder' in 'package:custom_lint_builder/custom_lint_builder.dart'.

The .dart_tool directory is not included in my lint_package repository.

If I manually execute flutter pub get in my local copy of this package (.pub-cache/**/lint_package) everything works as expected.

When installing along with `flutter_hooks_lint_plugin`, when trying to add `custom_lint` to analyzer plugins, `Multiple plugins can't be enabled` error occurs

Describe the bug
Multiple plugins apparently can't be added to analysis_options.yaml if we're using both flutter_hooks_lint_plugin and custom_lint.

To Reproduce

<Please add a small sample to that can be executed to reproduce the problem. As a general rule, 100 lines is the maximum>

Add flutter_hooks and flutter_hooks_lint_plugin as well as riverpod_lint and custom_lint to pubspec.yaml, and when you try to add custom_lint to analysis_options.yaml, there is a warning stating:

Multiple plugins can't be enabled.
Remove all plugins following the first, 'flutter_hooks_lint_plugin'. dart(multiple_plugins)

Expected behavior
Both should work together.

Issues in the finding Flutter widgets

Hello, I am using Custom_lint Package. To write some project specific lints. Like I want my team to use a project specific CustomScaffold rather flutter given Scaffold.

But since this is build on top on Dart Analyzer, which has no way of identifying Flutter Widgets, how can we detect Flutter Widgets with this ?

Tried both Element Tree as well as AST, but since in the documentation there was no mention of Flutter widget, it didn't help much. So it would be amazing if you guys could find some time to see how can we detect Flutter widgets with this.

Utilize `analysis_options` exclude

It would be useful to have the paths excluded in analysis_options.yaml also excluded in the custom lints.

I saw that the analyzer options are already available at ContextRoot.optionsFile so theoretically the exclude paths could be parsed and used, not sure if there is a better way to achieve that.

A slightly lesser but possible solution to excluding would be #4.

No UI Feedback in Android Studio

Describe the bug
With the latest update to dart_custom_lint (0.0.13), the linter works from the command line but doesn't work in Android Studio.

To Reproduce
Use dart_custom_lint version 0.0.13, create a custom lint, write code that violates the custom lint rule, and then notice that the violation is not reported in the Android Studio IDE.

Expected behavior
Violations of custom lint rules are displayed when running dart_custom_lint from both the command line and the Android Studio IDE.

[Documentation] Failed to start plugin error when "custom_lint.dart" file doesn't exist

Error is received in the pubspec.yaml file (of the application depending on a custom lint) when setting up first lint:

Failed to start plugin dart(custom_lint_plugin_error)

Steps to Reproduce:

  1. Create a new dart package, e.g. dart create my_lints.
  2. Create a custom lint and place it in bin/my_lints.dart (where file name = anything besides 'custom_lint.dart')
  3. Create a test dart application my_example_app and depend on custom_lint and my_lints
  4. "Failed to start plugin" error appears in my_example_app pubspec.yaml file

I'm not sure if the invertase team is at the documentation stage of this project yet, but for what its worth I found the setup and development extremely intuitive (especially with the walkthrough video), besides the lack of documentation / emphasis on this one requirement. Since the error received is also so vague, it took a bit of time for me to track down the root cause of the problem. A simple note in the readme may go a long way to help other early-adopters of this package.

Thanks you all for a great package!

Exclude from analysis?

Is there a way to exclude certain files/patterns from analysis globally? (besides to ignoring them in each lint). In the analysis_options.yaml file you can exclude files/patterns from the static Dart analyzer, but custom_lint doesn't seem to be respecting those.

LintCode url doesn't work

Describe the bug
After upgrading to 0.2.x, it doesn't seem like url specified in LintCode isn't being reported for a lint. It doesn't show up for my custom lint and looking in the source code, as far as I can see, it's never used (seeing error.dart#120)

To Reproduce
create a lint with:

class MyCustomLintCode extends DartLintRule {
  MyCustomLintCode() : super(code: _code);

  /// Metadata about the warning that will show-up in the IDE.
  /// This is used for `// ignore: code` and enabling/disabling the lint
  static const _code = LintCode(
    name: 'my_custom_lint_code',
    problemMessage: 'This is the description of our custom lint',
    url: 'https://www.google.com'
  );

  @override
  void run(
    CustomLintResolver resolver,
    ErrorReporter reporter,
    CustomLintContext context,
  ) {
    // Our lint will highlight all variable declarations with our custom warning.
    context.registry.addVariableDeclaration((node) {
      // "node" exposes metadata about the variable declaration. We could
      // check "node" to show the lint only in some conditions.

      // This line tells custom_lint to render a waring at the location of "node".
      // And the warning shown will use our `code` variable defined above as description.
      reporter.reportErrorForNode(code, node);
    });
  }
}

Expected behavior
A url to go with the lint message. It used to work prior to 0.2. I'm using IntelliJ IDEA 2022.2.2.
Actual behavior: only name and problemMessage shows up.

Let me know if I can provide any additional info!

Analyser error on a non-UTF8 file

Describe the bug
The analyser error's on a non-UTF8 file.
I tried to use adapt the globs in filesToAnalyze but it crashes before it evaluates that.
analysis_config.yaml also doesn't seem to have a way to exclude anything but .dart files.

RequestErrorCode.PLUGIN_ERROR
A request throw the exception:FileSystemException(path=/local-path-to/file.png; message=Failed to decode data using encoding 'utf-8')
#0      _PhysicalFile.readAsStringSync (package:analyzer/file_system/physical_file_system.dart:158:7)
#1      _OverlayFile.readAsStringSync (package:analyzer/file_system/overlay_file_system.dart:196:18)
#2      FileSource.contentsFromFile (package:analyzer/src/source/source_resource.dart:64:51)
#3      FileSource.contents (package:analyzer/src/source/source_resource.dart:51:12)
#4      _ClientAnalyzerPlugin._createResolverForFile (package:custom_lint_builder/src/client.dart:781:50)
#5      _ClientAnalyzerPlugin.analyzeFile (package:custom_lint_builder/src/client.dart:656:22)
#6      ServerPlugin.analyzeFiles (package:analyzer_plugin/plugin/plugin.dart:119:13)
<asynchronous suspension>
#7      ServerPlugin.afterNewContextCollection.<anonymous closure> (package:analyzer_plugin/plugin/plugin.dart:86:7)
<asynchronous suspension>
#8      ServerPlugin._forAnalysisContexts (package:analyzer_plugin/plugin/plugin.dart:518:9)
<asynchronous suspension>
#9      ServerPlugin.afterNewContextCollection (package:analyzer_plugin/plugin/plugin.dart:84:5)
<asynchronous suspension>
#10     _ClientAnalyzerPlugin._runOperation (package:custom_lint_builder/src/client.dart:797:14)
<asynchronous suspension>
#11     ServerPlugin.handleAnalysisSetContextRoots (package:analyzer_plugin/plugin/plugin.dart:273:5)
<asynchronous suspension>
#12     _ClientAnalyzerPlugin._runOperation (package:custom_lint_builder/src/client.dart:797:14)
<asynchronous suspension>
#13     ServerPlugin._getResponse (package:analyzer_plugin/plugin/plugin.dart:544:18)
<asynchronous suspension>
#14     ServerPlugin._onRequest (package:analyzer_plugin/plugin/plugin.dart:611:18)
<asynchronous suspension>

at:
#0      _SocketCustomLintServerToClientChannel.sendCustomLintRequest.<anonymous closure> (package:custom_lint/src/v2/server_to_client_channel.dart:385:11)
#1      _$_CustomLintResponseAnalyzerPluginResponse.map (package:custom_lint/src/v2/protocol.freezed.dart:924:34)
#2      _SocketCustomLintServerToClientChannel.sendCustomLintRequest (package:custom_lint/src/v2/server_to_client_channel.dart:379:14)
<asynchronous suspension>
#3      _SocketCustomLintServerToClientChannel.sendAnalyzerPluginRequest (package:custom_lint/src/v2/server_to_client_channel.dart:351:22)
<asynchronous suspension>
#4      Future.wait.<anonymous closure> (dart:async/future.dart:522:21)
<asynchronous suspension>
#5      _SocketCustomLintServerToClientChannel.init (package:custom_lint/src/v2/server_to_client_channel.dart:304:5)
<asynchronous suspension>
#6      CustomLintServer._maybeSpawnCustomLintPlugin (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:289:5)
<asynchronous suspension>
#7      CustomLintServer._handleAnalysisSetContextRoots.<anonymous closure> (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:264:9)
<asynchronous suspension>
#8      PendingOperation.run (package:custom_lint/src/async_operation.dart:14:14)
<asynchronous suspension>
#9      CustomLintServer._handleRequest (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:124:22)
<asynchronous suspension>

The request edit.getAssists failed with the following error:
RequestErrorCode.PLUGIN_ERROR
A request throw the exception:Bad state: Unable to find the context to /Users/peter/.pub-cache/hosted/pub.dev/custom_lint_builder-0.2.0/lib/src/client.dart
#0      AnalysisContextCollectionImpl.contextFor (package:analyzer/src/dart/analysis/analysis_context_collection.dart:143:5)
#1      _ClientAnalyzerPlugin.handleEditGetAssists (package:custom_lint_builder/src/client.dart:354:47)
<asynchronous suspension>
#2      ServerPlugin._getResponse (package:analyzer_plugin/plugin/plugin.dart:564:18)
<asynchronous suspension>
#3      ServerPlugin._onRequest (package:analyzer_plugin/plugin/plugin.dart:611:18)
<asynchronous suspension>

at:
#0      _SocketCustomLintServerToClientChannel.sendCustomLintRequest.<anonymous closure> (package:custom_lint/src/v2/server_to_client_channel.dart:385:11)
#1      _$_CustomLintResponseAnalyzerPluginResponse.map (package:custom_lint/src/v2/protocol.freezed.dart:924:34)
#2      _SocketCustomLintServerToClientChannel.sendCustomLintRequest (package:custom_lint/src/v2/server_to_client_channel.dart:379:14)
<asynchronous suspension>
#3      _SocketCustomLintServerToClientChannel.sendAnalyzerPluginRequest (package:custom_lint/src/v2/server_to_client_channel.dart:351:22)
<asynchronous suspension>
#4      CustomLintServer._handleRequest.<anonymous closure>.<anonymous closure> (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:140:17)
<asynchronous suspension>
#5      PendingOperation.run (package:custom_lint/src/async_operation.dart:14:14)
<asynchronous suspension>
#6      CustomLintServer._handleRequest (package:custom_lint/src/v2/custom_lint_analyzer_plugin.dart:124:22)
<asynchronous suspension>

To Reproduce

  • Have a .png file somewhere in a subfolder.
  • Run the plugin

Expected behavior
File gets ignored

Running custom_lint on a single file

Thanks for this awesome plugin. I recently integrated in my org's project and the custom lint is working like charm. Uses quite some memory but that's a different issue.
I wanted to ask is there any way to lint a single file ? Like from command line ?

Describe what scenario you think is uncovered by the existing examples/articles

Currently, following the documentation, I am able to run flutter pub run custom_lint in the project root and it scans all the files of the project. I couldn't find any documentation which states how to lint a single file from command line.

Additional context
We are working on a team project in an org and want to add Documentation compliance for new files. As all the existing files can't be documented at once, we want that any new PR should include complete documentation for the changed files.
If it was possible to run custom_lint on a single file, then this task could easily be integrated to GitHub workflow of our project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.