Flutter注解处理插件cli_annotations的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter注解处理插件cli_annotations的使用

简介

cli_annotations 是一个用于构建命令行接口(CLI)应用程序的Dart包,它允许开发者通过简单的注解和Dart类、函数来快速创建CLI应用。此工具简化了CLI应用的开发过程,提供了类型安全的参数解析、帮助文本自动生成以及良好的错误处理机制。

快速开始

安装

在你的 pubspec.yaml 文件中添加 cli_annotations 作为依赖,并将 cli_genbuild_runner 作为开发依赖。

name: dart_git
description: An implementation of the git CLI in Dart.

environment:
  sdk: ^3.0.0

dependencies:
  cli_annotations: ^0.1.0-dev.4

dev_dependencies:
  build_runner: ^2.4.8
  cli_gen: ^0.1.0-dev.4

# define an executable name (optional)
executables:
  dart_git: main

你可以选择定义一个可执行文件名并使用 pub global activate 激活它。

运行Build Runner

安装依赖后,启动 build_runner 来开始代码生成:

$ dart run build_runner watch -d

定义Command Runner

通过给类添加 @cliRunner 注解并继承生成的超类(通常带有 $ 前缀),可以创建一个 CommandRunner

@cliRunner
class GitRunner extends _$GitRunner {
  // ...
}

生成的代码包含了一个名为 CommandRunner.run() 的方法,这是CLI应用的入口点,需要从 main 函数调用。

定义命令

CommandRunner 类内部,通过创建方法并添加 @cliCommand 注解来定义命令。

@cliRunner
class GitRunner extends _$GitRunner {
  @cliCommand
  Future<void> merge({
    required String branch,
    MergeStrategy strategy = MergeStrategy.ort,
    bool? commit,
  }) async {
    print('Merging branch $branch');
    if (commit == true) {
      print('Committing merge');
    }
    await Future.delayed(const Duration(seconds: 1));
  }
}

你可以根据需要定义多个命令。

定义子命令

当应用程序变大时,可以通过创建新的 Subcommand 类来组织命令。

@cliSubcommand
class StashSubcommand extends _$StashSubcommand {
  @cliCommand
  Future<void> push() async { /* ... */ }

  @cliCommand
  Future<void> pop() async { /* ... */ }
}

@cliRunner
class GitRunner extends _$GitRunner {
  @cliMount
  StashSubcommand get stash => StashSubcommand();
}

运行应用

最后,在 main 函数中调用 CommandRunner.run() 方法以运行应用程序。

void main(List<String> arguments) async {
  final runner = GitRunner();
  await runner.run(arguments);
}

激活可执行文件(如果在 pubspec.yaml 中定义了可执行文件):

$ dart pub global activate . --source=path

然后运行应用程序:

$ dart_git merge --help

你将看到如下输出:

$ dart_git merge --help
Join two or more development histories together.

Usage: git-runner merge [arguments]
--branch (mandatory)
--commit
--options

Run "git-runner help" to see global options.

特性

类型安全的参数解析

cli-gen 自动将传入的字符串参数解析为正确的类型,并告知用户是否输入了无效值。

  • 支持的类型:String, int, double, bool, num, Uri, BigInt, DateTime。
  • 集合类型:List, Set, Iterable 可与上述类型结合使用。

帮助文本推断 (--help)

CLI 应用程序通常提供 --help 选项,显示可用命令及其参数的描述。cli-gen 可以自动生成这些信息,基于方法和参数名称、文档注释、默认值等。

参数帮助文本

@cliCommand
Future<void> myCustomCommand({
  required String requiredParam,
  int? optionalParam,
  String defaultPath = '~/',
  /// A parameter that uses a doc comment
  String someDocumentedParameter,
}) async {
  // ...
}

这将生成如下的帮助文本:

$ my-custom-command --help
Save your local modifications to a new stash.

Usage: git stash my-custom-command [arguments]
-h, --help                         Print this usage information.
    --required-param (mandatory)
    --optionalParam
    --default-path                 (defaults to "~/")
    --some-documented-parameter    A parameter that uses a doc comment

Run "git help" to see global options.

命令描述

你还可以通过在类和方法上添加文档注释来自动生成命令和整个应用的描述。

/// A dart implementation of the git CLI.
@cliRunner
class GitRunner extends _$GitRunner {

  /// Merge two or more development histories together.
  @cliCommand
  Future<void> commit() async {
    // ...
  }
}

这将生成如下的帮助文本:

$ git-runner --help
A dart implementation of the git CLI.

Usage: git-runner [arguments]
-h, --help    Print this usage information.

Available commands:
  commit    Merge two or more development histories together.

Run "git help" to see global options.

枚举和允许的值

枚举类型可以自动解析为字符串,并且可以在帮助文本中列出允许的值。

enum Values { a, b, c }

// 使用上述 Values 枚举作为参数:
--values (allowed: a, b, c)

位置参数

cli_gen 支持尾随的位置参数。

@cliCommand
Future<void> push(
  String remote,      // 位置参数
  String? branch, {   // 位置参数
  bool force = false, // 命名参数
}) async {
  /* ... */
}

名称格式化

cli-gen 将Dart的类、方法和参数名称转换为kebab-case格式,这是CLI命令和标志的惯例。

例如,stashChanges 将被转换为 stash-changesoutputFile 将被转换为 --output-file

要覆盖默认行为,只需在相应的注解中提供 name 参数。

示例代码

以下是一个完整的示例,展示了如何使用 cli_annotations 创建一个CLI应用。

import 'package:cli_annotations/cli_annotations.dart';

part 'example.g.dart';

// 1. 创建一个入口点,调用 `YourRunner().run(arguments)`。
Future<void> main(List<String> args) => GitRunner().run(args);

// 2. 创建一个扩展生成的 `_$` 类的类,并使用 `@cliRunner` 注解。

/// 一个用于版本控制的命令行界面。
@cliRunner
class GitRunner extends _$GitRunner {
  @cliMount
  Command get stash => StashSubcommand();

  /// 合并两个或多个开发历史。
  @cliCommand
  Future<void> merge({
    /// 要合并到当前分支的分支名称。
    required String branch,

    /// 传递特定于合并策略的选项。
    MergeStrategy strategy = MergeStrategy.ort,

    /// 执行合并并提交结果。
    bool? commit,
  }) async {
    print('Merging branch $branch');
    if (commit == true) {
      print('Committing merge');
    }
    await Future.delayed(const Duration(seconds: 1));
  }
}

enum MergeStrategy { ort, recursive, resolve, octopus, ours, subtree }

// 3. 你也可以通过使用 `@cliSubcommand` 注解的方法创建子命令。

/// 用于管理保存更改堆栈的命令。
///
/// 使用此命令可以临时保存和恢复工作目录中的更改,从而在不提交到Git历史记录的情况下切换上下文并管理正在进行的工作。
@cliSubcommand
class StashSubcommand extends _$StashSubcommand {
  /// 保存本地修改到新的stash。
  @cliCommand
  Future<void> myCustomCommand({
    // 必需参数将显示为 `mandatory`
    required String name,

    // 可选和/或可空参数不是 `mandatory`
    int? age,

    // 默认值也会显示在帮助文本中
    String defaultPath = '~/',

    /// 使用文档注释(即三个斜杠)显示参数的描述
    String? someDocumentedParameter,

    // 你可以使用 `@Option` 覆盖任何生成的值
    @Option(
      help: '一个自定义参数的帮助消息',
      defaultsTo: 42,
    )
    int? customParameter,
  }) async {
    // print('Stashing changes with message: $message');
    // await Future.delayed(const Duration(seconds: 1));
  }

  /// 应用指定的 [stashRef] 到工作目录。
  @cliCommand
  Future<void> apply({
    String stashRef = '0',
  }) async {
    print('Applying stash $stashRef');
    await Future.delayed(const Duration(seconds: 1));
  }
}

这个示例展示了如何使用 cli_annotations 创建一个简单的CLI应用,包括主命令、子命令和参数解析等功能。希望这能帮助你更好地理解和使用 cli_annotations 插件。


更多关于Flutter注解处理插件cli_annotations的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter注解处理插件cli_annotations的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,注解处理插件(Annotation Processing Plugins)可以帮助开发者在编译时生成代码,从而减少手动编码的工作量。cli_annotations 是一个假设的注解处理插件名称,尽管这不是一个广泛认知的官方插件,但我可以提供一个通用的注解处理插件使用的示例,并解释如何在Flutter项目中集成和使用类似的注解处理插件。

步骤 1: 创建注解定义

首先,你需要定义一个注解。这通常在一个单独的Dart包中完成,该包只包含注解定义。

// 在一个名为 `annotations` 的 Dart 包中
library annotations;

import 'package:meta/meta.dart';

// 定义一个简单的注解
class MyAnnotation {
  final String value;

  const MyAnnotation({@required this.value});
}

步骤 2: 创建注解处理器

接下来,你需要创建一个注解处理器。这通常是一个Dart VM应用程序,使用 build_runnersource_gen 等包来生成代码。

// 在一个名为 `generator` 的 Dart 包中
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:annotations/annotations.dart'; // 引入自定义注解

class MyAnnotationGenerator extends GeneratorForAnnotation<MyAnnotation> {
  @override
  FutureOr<String> generateForAnnotatedElement(
      Element element, ConstantReader annotation, BuildStep buildStep) {
    // 这里是生成代码的逻辑
    // 例如,我们可以生成一个简单的类
    var className = element.name + 'Generated';
    return '''
class $className {
  static String get message => '${annotation.read('value')}';
}
''';
  }
}

// build.yaml 配置
targets:
  $default:
    builders:
      my_annotation_builder:
        import: 'package:generator/builder.dart'
        builder_factories: ['myAnnotationBuilder']
        auto_apply: root_package
        build_extensions: { ".dart": [".g.dart"] }

步骤 3: 使用注解和生成器

在你的Flutter应用中,你可以使用刚才定义的注解,并使用 build_runner 来生成代码。

// 在你的 Flutter 应用中
import 'package:flutter/material.dart';
import 'package:annotations/annotations.dart'; // 引入自定义注解

// 使用注解
@MyAnnotation(value: "Hello, World!")
class MyClass {}

void main() {
  // 确保在运行前运行 build_runner
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Annotation Processing Example'),
        ),
        body: Center(
          child: Text(MyClassGenerated.message), // 使用生成的代码
        ),
      ),
    );
  }
}

// 注意:MyClassGenerated 是由注解处理器生成的类
// 你需要在运行应用之前运行 `flutter pub run build_runner build`

运行生成器

在命令行中,导航到你的Flutter应用目录,并运行以下命令来生成代码:

flutter pub run build_runner build

这将会扫描你的代码中的注解,并运行注解处理器生成相应的代码文件(例如 .g.dart 文件)。

注意事项

  1. 包依赖:确保你的 pubspec.yaml 文件中包含了所有必要的依赖,如 build_runnersource_gen
  2. 生成文件:生成的文件通常放在 lib/generated 目录下,但你可以通过 build.yaml 文件配置它们的位置。
  3. 热重载:在Flutter开发中,生成的文件通常不会自动热重载。你可能需要手动重启应用来看到变化。

以上就是一个使用注解处理插件的通用示例。尽管 cli_annotations 不是一个实际存在的插件名称,但这个过程可以应用于任何自定义的注解处理插件。

回到顶部