{"id":13550094,"url":"https://github.com/invertase/dart_custom_lint","last_synced_at":"2025-04-14T08:58:30.297Z","repository":{"id":41187302,"uuid":"470539658","full_name":"invertase/dart_custom_lint","owner":"invertase","description":"💡 Easily write powerful Dart \u0026 Flutter lint rules for your projects or for users of your packages.","archived":false,"fork":false,"pushed_at":"2025-02-27T12:53:37.000Z","size":2390,"stargazers_count":296,"open_issues_count":33,"forks_count":76,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-07T02:12:31.650Z","etag":null,"topics":["analyzer","dart","hacktoberfest","lint"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/custom_lint","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/invertase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-16T10:46:15.000Z","updated_at":"2025-03-27T18:37:51.000Z","dependencies_parsed_at":"2024-01-09T13:52:30.849Z","dependency_job_id":"6cd8c571-4293-472d-acd3-c188e77fc431","html_url":"https://github.com/invertase/dart_custom_lint","commit_stats":{"total_commits":341,"total_committers":31,"mean_commits":11.0,"dds":"0.15249266862170086","last_synced_commit":"bc5ba8f82abb5cad59a3492a5b51f475e7638ada"},"previous_names":[],"tags_count":159,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invertase%2Fdart_custom_lint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invertase%2Fdart_custom_lint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invertase%2Fdart_custom_lint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/invertase%2Fdart_custom_lint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/invertase","download_url":"https://codeload.github.com/invertase/dart_custom_lint/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852128,"owners_count":21171840,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analyzer","dart","hacktoberfest","lint"],"created_at":"2024-08-01T12:01:28.884Z","updated_at":"2025-04-14T08:58:30.274Z","avatar_url":"https://github.com/invertase.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1\u003ecustom_lint\u003c/h1\u003e\n  \u003cspan\u003eTools for building custom lint rules.\u003c/span\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/invertase/dart_custom_lint/blob/main/LICENSE\"\u003eLicense\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n \u003ca href=\"https://invertase.link/discord\"\u003e\n   \u003cimg src=\"https://img.shields.io/discord/295953187817521152.svg?style=flat-square\u0026colorA=7289da\u0026label=Chat%20on%20Discord\" alt=\"Chat on Discord\"\u003e\n \u003c/a\u003e\n\n---\n\n## Index\n\n- [Index](#index)\n- [Tutorial](#tutorial)\n- [About](#about)\n- [Usage](#usage)\n  - [Creating a custom lint package](#creating-a-custom-lint-package)\n  - [Using our custom lint package in an application](#using-our-custom-lint-package-in-an-application)\n  - [Enabling/disabling and configuring lints](#enablingdisabling-and-configuring-lints)\n  - [Obtaining the list of lints in the CI](#obtaining-the-list-of-lints-in-the-ci)\n  - [Using the Dart debugger and enabling hot-reload](#using-the-dart-debugger-and-enabling-hot-reload)\n  - [Testing your plugins](#testing-your-plugins)\n    - [Testing lints](#testing-lints)\n    - [Testing quick fixes and assists](#testing-quick-fixes-and-assists)\n\n## Tutorial\n\nYou can read the latest [blog post](https://invertase.link/b18R) or watch the [advanced use case with custom_lint video](https://invertase.link/RNoz).\n\n## About\n\nLint rules are a powerful way to improve the maintainability of a project.\nThe more, the merrier!\nBut while Dart offers a wide variety of lint rules by default, it cannot\nreasonably include every possible lint. For example, Dart does not\ninclude lints related to third-party packages.\n\nCustom_lint fixes that by allowing package authors to write custom lint rules.\n\nCustom_lint is similar to [analyzer_plugin], but goes deeper by trying to\nprovide a better developer experience.\n\nThat includes:\n\n- A command-line to obtain the list of lints in your CI\n  without having to write a command line yourself.\n- A simplified project setup:\n  No need to deal with the `analyzer` server or error handling. Custom_lint\n  takes care of that for you, so that you can focus on writing lints.\n- Debugger support.\n  Inspect your lints using the Dart debugger and place breakpoints.\n- Supports hot-reload/hot-restart:\n  Updating the source code of a linter plugin will dynamically restart it,\n  without having to restart your IDE/analyzer server.\n- Built-in support for `// ignore:` and `// ignore_for_file:`.\n- Built-in testing mechanism using `// expect_lint`. See [Testing your plugins](#testing-your-plugins)\n- Support for `print(...)` and exceptions:\n  If your plugin somehow throws or print debug messages, custom_lint\n  will generate a log file with the messages/errors.\n\n## Usage\n\nUsing custom_lint is split in two parts:\n\n- how to define a custom_lint package\n- how users can install our package in their application to see our newly defined lints\n\n### Creating a custom lint package\n\nTo create a custom lint, you will need two things:\n\n- updating your `pubspec.yaml` to include `custom_lint_builder` as a dependency:\n\n  ```yaml\n  # pubspec.yaml\n  name: my_custom_lint_package\n  environment:\n    sdk: \"\u003e=3.0.0 \u003c4.0.0\"\n\n  dependencies:\n    # we will use analyzer for inspecting Dart files\n    analyzer:\n    analyzer_plugin:\n    # custom_lint_builder will give us tools for writing lints\n    custom_lint_builder:\n  ```\n\n- create a `lib/\u003cmy_package_name\u003e.dart` file in your project with the following:\n\n  ```dart\n  import 'package:analyzer/error/listener.dart';\n  import 'package:custom_lint_builder/custom_lint_builder.dart';\n  \n  // This is the entrypoint of our custom linter\n  PluginBase createPlugin() =\u003e _ExampleLinter();\n\n  /// A plugin class is used to list all the assists/lints defined by a plugin.\n  class _ExampleLinter extends PluginBase {\n    /// We list all the custom warnings/infos/errors\n    @override\n    List\u003cLintRule\u003e getLintRules(CustomLintConfigs configs) =\u003e [\n          MyCustomLintCode(),\n        ];\n  }\n\n  class MyCustomLintCode extends DartLintRule {\n    MyCustomLintCode() : super(code: _code);\n\n    /// Metadata about the warning that will show-up in the IDE.\n    /// This is used for `// ignore: code` and enabling/disabling the lint\n    static const _code = LintCode(\n      name: 'my_custom_lint_code',\n      problemMessage: 'This is the description of our custom lint',\n    );\n\n    @override\n    void run(\n      CustomLintResolver resolver,\n      ErrorReporter reporter,\n      CustomLintContext context,\n    ) {\n      // Our lint will highlight all variable declarations with our custom warning.\n      context.registry.addVariableDeclaration((node) {\n        // \"node\" exposes metadata about the variable declaration. We could\n        // check \"node\" to show the lint only in some conditions.\n\n        // This line tells custom_lint to render a warning at the location of \"node\".\n        // And the warning shown will use our `code` variable defined above as description.\n        reporter.atNode(node, code);\n      });\n    }\n  }\n  ```\n\nThat's it for defining a custom lint package!\n\nIf you're looking for a more advanced example, see the [example](https://github.com/invertase/dart_custom_lint/tree/main/packages/custom_lint/example).\nThis example implements:\n\n- a lint appearing on all variables of a specific type\n- a quick fix for that lint\n- an \"assist\" for providing refactoring options.\n\nLet's now use it in an application.\n\n### Using our custom lint package in an application\n\nFor users to run custom_lint packages, there are a few steps:\n\n- The application must contain an `analysis_options.yaml` with the following:\n\n  ```yaml\n  analyzer:\n    plugins:\n      - custom_lint\n  ```\n\n- The application also needs to add `custom_lint` and our package(s) as dev\n  dependency in their application:\n\n  ```yaml\n  # The pubspec.yaml of an application using our lints\n  name: example_app\n  environment:\n    sdk: \"\u003e=3.0.0 \u003c4.0.0\"\n\n  dev_dependencies:\n    custom_lint:\n    my_custom_lint_package:\n  ```\n\nThat's all!\nAfter running `pub get` (and possibly restarting their IDE), users should now\nsee our custom lints in their Dart files:\n\n![screenshot of our custom lints in the IDE](https://raw.githubusercontent.com/invertase/dart_custom_lint/main/resources/lint_showcase.png)\n\n### Enabling/disabling and configuring lints\n\nBy default, custom_lint enables all installed lints.  \nBut chances are you may want to disable one specific lint,\nor alternatively, disable all lints besides a few.\n\nThis configuration is done in your `analysis_options.yaml`,\nbut in a slightly different manner.\n\nConfigurations are placed within a `custom_lint` object, as\nfollowed:\n\n```yaml\nanalyzer:\n  plugins:\n    - custom_lint\n\ncustom_lint:\n  rules:\n    - my_lint_rule: false # disable this rule\n```\n\nAs mentioned before, all lints are enabled by default.\n\n```yaml\ncustom_lint:\n  # Disable all lints by default\n  enable_all_lint_rules: false\n  rules:\n    - my_lint_rule # only enable my_lint_rule\n```\n\nIf you want to change this, you can optionally disable\nall lints by default:\n\nLast but not least, some lint rules may be configurable.\nWhen a lint is configurable, you can configure it in the same place with:\n\n```yaml\ncustom_lint:\n  rules:\n    - my_lint_rule:\n      some_parameter: \"some value\"\n```\n\n### Obtaining the list of lints in the CI\n\nUnfortunately, running `dart analyze` does not pick up our newly defined lints.\nWe need a separate command for this.\n\nTo do that, users of our custom lint package can run the following inside their terminal:\n\n```sh\n$ dart run custom_lint\n  lib/main.dart:0:0 • This is the description of our custom lint • my_custom_lint_code\n```\n\nIf you are working on a Flutter project, run `flutter pub run custom_lint` instead.\n\n### Using the Dart debugger and enabling hot-reload\n\nBy default, custom_lint does enable hot-reload or give you the necessary\ninformation to start the debugger. This is because most users don't need those,\nand only lint authors do.\n\nIf you wish to debug lints, you'll have to update your `analysis_options.yaml` as followed:\n\n```yaml\nanalyzer:\n  plugins:\n    - custom_lint\n\ncustom_lint:\n  debug: true\n  # Optional, will cause custom_lint to log its internal debug information\n  verbose: true\n```\n\nThen, to debug plugins in custom_lint, you need to connect to plugins using \"attach\"\nmode in your IDE (`cmd+shift+p` + `Debug: attach to Dart process` in VSCode).\n\nWhen using this command, you will need a VM service URI provided by custom_lint.\n\nThere are two possible ways to obtain one:\n\n- if you started your plugin using `custom_lint --watch`, it should be visible\n  in the console output.\n- if your plugin is started by your IDE, you can open the `custom_lint.log` file\n  that custom_lint created next to the `pubspec.yaml` of your analyzed projects.\n\nIn both cases, what you're looking for is logs similar to:\n\n```\nThe Dart VM service is listening on http://127.0.0.1:60671/9DS43lRMY90=/\nThe 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\n```\n\nWhat you'll want is the first URI. In this example, that is `http://127.0.0.1:60671/9DS43lRMY90=/`.\nYou can then pass this to your IDE, which should now be able to attach to the\nplugin.\n\n### Testing your plugins\n\n#### Testing lints\n\nCustom_lint comes with an official testing mechanism for asserting that your\nplugins correctly work.\n\nTesting lints is straightforward: Simply write a file that should contain\nlints from your plugin (such as the example folder). Then, using a syntax\nsimilar to `// ignore`, write a `// expect_lint: code` in the line before\nyour lint:\n\n```dart\n// expect_lint: riverpod_final_provider\nvar provider = Provider(...);\n```\n\nWhen doing this, there are two possible cases:\n\n- The line after the `expect_lint` correctly contains the expected lint.\n  In that case, the lint is ignored (similarly to if we used `// ignore`)\n- The next line does **not** contain the lint.\n  In that case, the `expect_lint` comment will have an error.\n\nThis allows testing your plugins by simply running `custom_lint` on your test/example folder.\nThen, if any expected lint is missing, the command will fail. But if your plugin correctly\nemits the lint, the command will succeed.\n\n#### Testing quick fixes and assists\n\nTesting quick fixes and assists is also possible with regular tests by combining them with\n`pkg:analyzer` to manually execute the assists or fixes. An example can be found in the\n[Riverpod repository](https://github.com/rrousselGit/riverpod/tree/master/packages/riverpod_lint_flutter_test/test/assists).\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://invertase.io/?utm_source=readme\u0026utm_medium=footer\u0026utm_campaign=dart_custom_lint\"\u003e\n    \u003cimg width=\"75px\" src=\"https://static.invertase.io/assets/invertase/invertase-rounded-avatar.png\"\u003e\n  \u003c/a\u003e\n  \u003cp align=\"center\"\u003e\n    Built and maintained by \u003ca href=\"https://invertase.io/?utm_source=readme\u0026utm_medium=footer\u0026utm_campaign=dart_custom_lint\"\u003eInvertase\u003c/a\u003e.\n  \u003c/p\u003e\n\u003c/p\u003e\n\n[analyzer_plugin]: https://pub.dev/packages/analyzer_plugin\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finvertase%2Fdart_custom_lint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finvertase%2Fdart_custom_lint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finvertase%2Fdart_custom_lint/lists"}