[Flutter翻译]宣布Dart定制的Lint包

550 阅读5分钟

本文由 简悦SimpRead 转码,原文地址 invertase.io

我很高兴地宣布我们的'custom_lint'包,这是一个用于建立自定义lint规则的强大工具,......。

image.png

Lint规则是提高项目可维护性的一种强大方式。越多越好! 但是,虽然Dart默认提供了各种各样的lint规则,但它不能合理地包括所有可能的lint。例如,Dart不包括与第三方软件包有关的提示,也不包括与你的项目和团队有关的提示。

我很高兴地宣布Custom Lint包,这是一个强大的工具,用于构建自定义的lint规则,让包的作者以及Flutter和Dart的开发者能够超越。

如果你已经尝试过定义自定义林特,也许,你已经看到了analyzer_plugin。与这个插件打交道并不像你希望的那样愉快,而且还带有一些限制。

custom_lint包是类似的,然而,它更深入,努力提供一个更好的开发者体验。

该包提供了很多功能,包括但不限于。

  • 一个命令行来获取你的CI中的lints列表,而不需要自己写一个命令行。
  • 一个简化的项目设置。不需要处理 "分析器 "服务器或错误处理。custom_lint为你解决这些问题,这样你就可以专注于编写lints。
  • 支持热重启。更新linter插件的源代码将动态地重启它,而不需要重启你的IDE/分析器服务器。
  • 内置支持// ignore:// ignore_for_file:
  • 支持print(...)和异常。如果你的插件以某种方式抛出或打印调试信息,custom_lint将生成一个包含这些信息/错误的日志文件。

你可以打开Github上的custom_lint资源库,你会发现源代码。基本上,这个仓库有两个主要的包,custom_lint,和custom_lint_builder。一般来说,custom_lint包被用在你要利用定义的自定义lints的应用程序中,而custom_lint_builder则被用在你要定义自己的自定义lints规则的包中。

为了更好的理解,让我们看看你如何使用它们。

一般来说,当你使用custom_lint时,你需要将你的任务定义为两个部分。

  • 如何定义一个自定义_lint包
  • 用户如何在他们的应用程序中安装我们的包以看到我们新定义的lints

让我们深入了解一下。

创建一个自定义的lint包#

创建自定义lint规则的第一步是创建一个包,要做到这一点,你需要遵循两个简单的步骤。

  1. 更新你的pubspec.yaml,将custom_lint_builder作为一个依赖项。
# pubspec.yaml
name: my_custom_lint_package
environment:
  sdk: ">=2.16.0 <3.0.0"

dependencies:
  # we will use an analyzer for inspecting Dart files
  analyzer:
  # custom_lint_builder will give us tools for writing lints
  custom_lint_builder:
  1. 在你的项目中创建一个bin/custom_lint.dart文件,内容如下。
void main(List<String> args, SendPort sendPort) {
  startPlugin(sendPort, _ExampleLinter());
}

class _ExampleLinter extends PluginBase {
  @override
  Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
    yield Lint(
      code: 'my_custom_lint_code',
      message: 'This is the description of our custom lint',
      location: resolvedUnitResult.lintLocationFromOffset(0, length: 10),
    );
  }
}

让我们分析一下第2步的代码,了解它的作用。

你的自定义linter的入口点从main函数开始,它将有两个参数,List<String> argsSendPort sendPort

你将需要通过传递sendPort和你将定义的自定义linter类来调用startPlugin函数。

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

然后,你需要创建一个自定义类,该类扩展PluginBase,并编写你自己的Lint 这是一个分析Dart文件并返回lints的类。

class _ExampleLinter extends PluginBase {
  @override
  Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
    // A basic lint that shows at the top of the file.
    yield Lint(
      code: 'my_custom_lint_code',
      message: 'This is the description of our custom lint',
      location: resolvedUnitResult.lintLocationFromOffset(
        0,
        length: 10,
      ),
    );
  }
}

让我们看一下Lint类。有三个必须填写的参数:code, message, 和location,你的lint将出现在Dart文件中。上面的例子将使它出现在文件的顶部(偏移量为0),长度为10个字符。

让我给你一个真实世界的例子。

第一个文件夹结构

|__ my_awesome_lints
|_____ bin
|________ custom_lint.dart
|_____ analysis_options.yaml
|_____ pubspec.yaml
import 'dart:isolate';

import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

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);
}

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

class _RiverpodLint extends PluginBase {
  @override
  Stream<Lint> getLints(ResolvedUnitResult resolvedUnitResult) async* {
    final library = resolvedUnitResult.libraryElement;
    print('This is a print');
    final providers = library.topLevelElements
        .whereType<VariableElement>()
        .where((e) => !e.isFinal)
        .where((e) => _isProvider(e.type))
        .toList();
    for (final provider in providers) {
      if (provider.name == 'fail') throw StateError('Nani?');
      yield Lint(
        code: 'riverpod_final_provider',
        message: 'Providers should always be declared as final',
        location: provider.nameLintLocation!,
      );
    }
  }
}

正如你在上面的例子中看到的,我现在已经定义了riverpod_final_provider规则,以确保提供者被定义为final关键字。

现在让我们在一个应用程序中使用它,就是我上面提到的第二步。

在一个应用程序中使用我们的自定义lint包 #

现在你已经定义了你的包,你可以在你的应用程序中使用它,只需两个步骤。

  1. 应用程序必须包含一个analysis_options.yaml,内容如下。
analyzer:
  plugins:
    - custom_lint
  1. 应用程序还需要在他们的应用程序中添加custom_lint和我们的软件包作为开发依赖。
# The pubspec.yaml of an application using your lints
name: example_app
environment:
  sdk: ">=2.16.0 <3.0.0"

dev_dependencies:
  custom_lint:
  my_awesome_lints:

这就是全部! 在运行pub get后(可能还要重启他们的IDE),用户现在应该在他们的Dart文件中看到我们的自定义lints。

获得CI中的lints列表 #

不幸的是,运行 "dart analyze "并不能发现我们新定义的lints。我们需要一个单独的命令来处理这个问题。

要做到这一点,我们的custom_lint包的用户可以在应用程序中运行以下命令。

$ dart run custom_lint

  lib/main.dart:0:0 - 这是对你的自定义lint的描述 - my_awesome_lints

作为一个开发者,你花了很多时间在调试上。custom_lint带有一个整洁的功能,可以让你轻松点击日志,跳转到你定义的自定义lints。这可以节省时间,并且很容易找到事情出错的原因和地点。

invertase.io/customlint-…

custom_lint包也会生成一个custom_lint.log文件,在那里你可以找到所有的输出,包括你所打印的内容或任何错误。

invertase.io/customlint-…

高级用例 #

如果你想了解更多,看看你能用custom_lint包做什么,你可以看下面的视频,我已经实现了两个自定义的lint规则,还有修正和快速修复。

添加lints,尤其是与包的要求完全匹配的自定义lints,或进一步满足项目和团队的需求,将促进整个项目的代码一致性,并有助于提高代码质量。

Dart custom_lint package在这里可以帮助你定义自定义规则,增强开发者的体验,并提供一个定义此类规则的愉快旅程。

一如既往,Invertase提供的工具使开发者富有成效,并旨在将其开源,希望其他人能够利用它来获得利益。

请不要犹豫,通过打开版本库上的问题或通过社交媒体分享给我们反馈。

请继续关注更多关于自定义衬垫的例子和教程,以及我们将在未来分享的关于我们正在开发的其他工具的令人兴奋的消息。请在TwitterLinkedinYoutube上关注我们,并订阅我们的月度新闻简报,以便始终保持最新的信息。


www.deepl.com 翻译