diff --git a/README.md b/README.md index b6116dd..03a84f2 100644 --- a/README.md +++ b/README.md @@ -84,16 +84,15 @@ environment: sdk: ^3.0.0 dependencies: - cli_annotations: ^0.1.0-dev.1 + cli_annotations: ^0.1.0-dev.4 dev_dependencies: - build_runner: ^2.4.8 - cli_gen: ^0.1.0-dev.1 + build_runner: ^2.4.8 + cli_gen: ^0.1.0-dev.4 # define an executable name (optional) executables: - dart_git: - path: main # file name of `main()` in bin/ directory + dart_git: main ``` You can optionally define an executable name and activate it using [pub global activate](https://dart.dev/tools/pub/cmd/pub-global#activating-a-package-on-your-local-machine). @@ -121,7 +120,7 @@ class GitRunner extends _$GitRunner { ### Define a Command -Create a `Command` by simply creating a method on the class; any type can be used as a parameter. +Inside the `CommandRunner` class, create a `Command` by creating a method and annotating it with `@cliCommand`. See the [Features](#features) section for more information on the supported types and features. ```dart @cliRunner @@ -137,14 +136,35 @@ class GitRunner extends _$GitRunner { } ``` +You can create as many commands inside the `CommandRunner` class as you'd like: + +```dart +@cliRunner +class GitRunner extends _$GitRunner { + @cliCommand + Future merge({ + required String branch, + MergeStrategy strategy = MergeStrategy.ort, + bool? commit, + }) async { /* ... */ } + + @cliCommand + Future stashPush() async { /* ... */ } + + @cliCommand + Future stashPop() async { /* ... */ } + + // ... +} +``` + ### Define a Subcommand As your application grows, you may want to separate your commands into their own groups. -You can create a `Subcommand` by annotating a class with `@cliSubcommand` and extending the generated superclass. +To do so, create a `Subcommand` class by annotating the class with `@cliSubcommand` and extending the generated superclass. ```dart -// Create your subcommand @cliSubcommand class StashSubcommand extends _$StashSubcommand { @cliCommand @@ -154,11 +174,15 @@ class StashSubcommand extends _$StashSubcommand { Future pop() async { /* ... */ } } -// Then mount it to your `CommandRunner` or a parent `Subcommand` +``` + +Subcommands can then be connected to the main `CommandRunner` class, or to another `Subcommand` class, by using the `@cliMount` annotation. + +```dart @cliRunner class GitRunner extends _$GitRunner { - @mount - Command get stash => StashSubcommand(); + @cliMount + StashSubcommand get stash => StashSubcommand(); } ``` diff --git a/docs/pub_example/pubspec.lock b/docs/pub_example/pubspec.lock index 2b4eff5..835557a 100644 --- a/docs/pub_example/pubspec.lock +++ b/docs/pub_example/pubspec.lock @@ -119,14 +119,14 @@ packages: path: "../../src/cli_annotations" relative: true source: path - version: "0.1.0-dev.3" + version: "0.1.0-dev.4" cli_gen: dependency: "direct dev" description: path: "../../src/cli_gen" relative: true source: path - version: "0.1.0-dev.3" + version: "0.1.0-dev.4" code_builder: dependency: transitive description: diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index 5891153..a8a7bd2 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -7,4 +7,4 @@ analyzer: linter: rules: prefer_relative_imports: true - prefer_if_null_operators: false + # prefer_if_null_operators: false diff --git a/example/lib/runner.dart b/example/lib/runner.dart index b14700a..4affde2 100644 --- a/example/lib/runner.dart +++ b/example/lib/runner.dart @@ -31,7 +31,6 @@ class GitRunner extends _$GitRunner { int? fooWithDefault, /// Perform the merge and commit the result. - bool? commit, }) async { print('Merging branch $branch'); diff --git a/example/lib/runner.g.dart b/example/lib/runner.g.dart index a0947ff..d5d205e 100644 --- a/example/lib/runner.g.dart +++ b/example/lib/runner.g.dart @@ -6,6 +6,13 @@ part of 'runner.dart'; // CliRunnerGenerator // ************************************************************************** +/// A command-line interface for version control. +/// +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. class _$GitRunner extends CommandRunner { _$GitRunner() : super( @@ -58,7 +65,7 @@ class MergeCommand extends Command { ..addFlag('commit'); } - final Function({ + final Future Function({ required String branch, MergeStrategy strategy, int fooWithDefault, diff --git a/example/lib/stash.g.dart b/example/lib/stash.g.dart index 1eff532..dc31c56 100644 --- a/example/lib/stash.g.dart +++ b/example/lib/stash.g.dart @@ -34,7 +34,7 @@ class PushCommand extends Command { ); } - final Function({ + final Future Function({ bool includeUntracked, String message, }) userMethod; @@ -49,9 +49,7 @@ class PushCommand extends Command { Future run() { final results = argResults!; return userMethod( - includeUntracked: results['include-untracked'] != null - ? results['include-untracked'] - : false, + includeUntracked: (results['include-untracked'] as bool?) ?? false, message: results['message'], ); } @@ -67,7 +65,7 @@ class ApplyCommand extends Command { ); } - final Function({String stashRef}) userMethod; + final Future Function({String stashRef}) userMethod; @override String get name => 'apply'; @@ -79,7 +77,6 @@ class ApplyCommand extends Command { @override Future run() { final results = argResults!; - return userMethod( - stashRef: results['stash-ref'] != null ? results['stash-ref'] : '0'); + return userMethod(stashRef: (results['stash-ref'] as String?) ?? '0'); } } diff --git a/example/pubspec.lock b/example/pubspec.lock index a636e35..42caefb 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -119,14 +119,14 @@ packages: path: "../src/cli_annotations" relative: true source: path - version: "0.1.0-dev.2" + version: "0.1.0-dev.4" cli_gen: dependency: "direct dev" description: path: "../src/cli_gen" relative: true source: path - version: "0.1.0-dev.2" + version: "0.1.0-dev.4" code_builder: dependency: transitive description: diff --git a/melos.yaml b/melos.yaml index 2f9f075..c59bae9 100644 --- a/melos.yaml +++ b/melos.yaml @@ -7,6 +7,7 @@ packages: - src/cli_annotations - src/cli_gen - src/cli_gen/test/** + - test/goldens scripts: analyze: @@ -23,7 +24,7 @@ scripts: exec: dart test packageFilters: - published: true + dirExists: test build: run: dart run build_runner build -d diff --git a/pubspec.yaml b/pubspec.yaml index 10d194a..9190733 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,13 +7,13 @@ environment: dependencies: analyzer: ^6.4.1 args: ^2.4.2 - cli_annotations: ^0.1.0-dev.2 + cli_annotations: ^0.1.0-dev.4 freezed_annotation: ^2.4.1 json_annotation: ^4.8.1 dev_dependencies: build_runner: ^2.4.8 - cli_gen: ^0.1.0-dev.2 + cli_gen: ^0.1.0-dev.4 freezed: ^2.4.7 json_serializable: ^6.7.1 lints: ^3.0.0 diff --git a/src/cli_annotations/CHANGELOG.md b/src/cli_annotations/CHANGELOG.md index ad880c9..ce565fb 100644 --- a/src/cli_annotations/CHANGELOG.md +++ b/src/cli_annotations/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.0-dev.5 + +- feat: Warning on `cliCommand` use on a class, rather than a method/function + ## 0.1.0-dev.4 - feat: Support for adding a generic type to `Command` and `CommandRunner` diff --git a/src/cli_annotations/lib/src/commands.dart b/src/cli_annotations/lib/src/commands.dart index e3d33f2..42f00c8 100644 --- a/src/cli_annotations/lib/src/commands.dart +++ b/src/cli_annotations/lib/src/commands.dart @@ -26,7 +26,7 @@ import 'package:meta/meta_meta.dart'; /// } /// ``` /// {@endtemplate} -@Target({TargetKind.method, TargetKind.function, TargetKind.classType}) +@Target({TargetKind.method, TargetKind.function}) class CliCommand { final String? name; diff --git a/src/cli_gen/lib/src/analysis/parameters/default_value_code_builder.dart b/src/cli_gen/lib/src/analysis/parameters/default_value_code_builder.dart index eab8bb2..2e36d8c 100644 --- a/src/cli_gen/lib/src/analysis/parameters/default_value_code_builder.dart +++ b/src/cli_gen/lib/src/analysis/parameters/default_value_code_builder.dart @@ -131,7 +131,7 @@ class DefaultValueCodeBuilder { } throw InvalidGenerationSourceError( - 'Invalid type for constant value: $thisType', + 'Unknown type for constant value: $thisType', ); } diff --git a/src/cli_gen/lib/src/code/command/command_builder.dart b/src/cli_gen/lib/src/code/command/command_builder.dart index f606f65..8a3803c 100644 --- a/src/cli_gen/lib/src/code/command/command_builder.dart +++ b/src/cli_gen/lib/src/code/command/command_builder.dart @@ -36,10 +36,12 @@ class CommandBuilder { }), ); - const argParserBuilder = ArgParserInstanceExp(); - builder.body = argParserBuilder - .buildArgParserCascadeFromRef(model.parameters) - .statement; + if (model.parameters.isNotEmpty) { + const argParserBuilder = ArgParserInstanceExp(); + builder.body = argParserBuilder + .buildArgParserCascadeFromRef(model.parameters) + .statement; + } }), ); @@ -52,6 +54,7 @@ class CommandBuilder { builder.modifier = FieldModifier.final$; builder.type = FunctionType((builder) { + builder.returnType = model.returnType; final requiredPositionalParams = model.parameters.where((e) => !e.isNamed && e.isRequired); builder.requiredParameters.addAll( @@ -127,10 +130,11 @@ class CommandBuilder { builder.statements.addAll([ // -- declare a `results` variable -- - declareFinal('results') - .assign(refer('argResults')) - .nullChecked - .statement, + if (model.parameters.isNotEmpty) + declareFinal('results') + .assign(refer('argResults')) + .nullChecked + .statement, // -- call the user method -- userMethodCallBuilder.buildInlineCallStatement(model), diff --git a/src/cli_gen/lib/src/code/command/runner_builder.dart b/src/cli_gen/lib/src/code/command/runner_builder.dart index b064425..9335d4c 100644 --- a/src/cli_gen/lib/src/code/command/runner_builder.dart +++ b/src/cli_gen/lib/src/code/command/runner_builder.dart @@ -48,6 +48,11 @@ class RunnerBuilder { builder.symbol = 'T'; })); + builder.docs.addAll([ + if (model.docComments != null) '/// ${model.docComments}\n///', + _classDocComments, + ]); + builder.constructors.add( Constructor((builder) { // -- super initializer -- @@ -60,9 +65,12 @@ class RunnerBuilder { ); // -- the constructor body -- - // adds nested commands and `@mount` subcommands to the CommandRunner - final bodyBuilder = SubcommandConstructorBodyBuilder(); - builder.body = bodyBuilder.buildSubcommandConstructorBody(model); + if (model.commandMethods.isNotEmpty || + model.mountedSubcommands.isNotEmpty) { + // adds nested commands and `@mount` subcommands to the CommandRunner + final bodyBuilder = SubcommandConstructorBodyBuilder(); + builder.body = bodyBuilder.buildSubcommandConstructorBody(model); + } }), ); @@ -70,11 +78,15 @@ class RunnerBuilder { final runReturnType = TypeReference((builder) { builder.symbol = Identifiers.dart.future.symbol; builder.url = Identifiers.dart.future.url; - final nestedType = (model.bound ?? Identifiers.dart.dynamic); + final nestedType = + (model.bound ?? Identifiers.dart.dynamic).toTypeRef(); + // `void?` and `dynamic?` are not valid, but any other type should be + // nullable (according to `args``CommandRunner.run` return type) + final isNullable = + nestedType.symbol != 'void' && nestedType.symbol != 'dynamic'; + builder.types.add( - nestedType.toTypeRef( - isNullable: nestedType.symbol == 'void' ? null : true, - ), + nestedType.toTypeRef(isNullable: isNullable), ); }); @@ -115,3 +127,10 @@ class RunnerBuilder { }); } } + +const _classDocComments = ''' +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values.'''; diff --git a/src/cli_gen/lib/src/code/command/subcommand_builder.dart b/src/cli_gen/lib/src/code/command/subcommand_builder.dart index f4fd945..d9ef419 100644 --- a/src/cli_gen/lib/src/code/command/subcommand_builder.dart +++ b/src/cli_gen/lib/src/code/command/subcommand_builder.dart @@ -19,9 +19,9 @@ class SubcommandBuilder { const commandBuilder = CommandBuilder(); final subcommandClass = buildSubcommandClass(model); - final subcommands = model.commandMethods.map((e) { - return commandBuilder.buildCommandClass(e); - }); + final subcommands = model.commandMethods.map( + commandBuilder.buildCommandClass, + ); return [subcommandClass, ...subcommands]; } @@ -48,12 +48,15 @@ class SubcommandBuilder { // -- class constructor -- builder.constructors.add( Constructor((constructor) { - constructor.body = Block((block) { - final constructorBodyBuilder = SubcommandConstructorBodyBuilder(); - block.statements.add( - constructorBodyBuilder.buildSubcommandConstructorBody(model), - ); - }); + if (model.commandMethods.isNotEmpty || + model.mountedSubcommands.isNotEmpty) { + constructor.body = Block((block) { + final constructorBodyBuilder = SubcommandConstructorBodyBuilder(); + block.statements.add( + constructorBodyBuilder.buildSubcommandConstructorBody(model), + ); + }); + } }), ); diff --git a/src/cli_gen/lib/src/code/command/subcommand_constructor_body_builder.dart b/src/cli_gen/lib/src/code/command/subcommand_constructor_body_builder.dart index 3ed8c97..f84f2cb 100644 --- a/src/cli_gen/lib/src/code/command/subcommand_constructor_body_builder.dart +++ b/src/cli_gen/lib/src/code/command/subcommand_constructor_body_builder.dart @@ -8,8 +8,9 @@ class SubcommandConstructorBodyBuilder { const SubcommandConstructorBodyBuilder(); Block buildSubcommandConstructorBody( - SubcommandModel model, - ) { + SubcommandModel model, { + bool isRunner = true, + }) { final addCommandRef = switch (model) { RunnerModel() => Identifiers.args.addCommand, SubcommandModel() => Identifiers.args.addSubcommand, @@ -39,7 +40,7 @@ class SubcommandConstructorBodyBuilder { // -- add `@mount` subcommands via `addCommand()` -- block.statements.addAll( model.mountedSubcommands.map( - (e) => Identifiers.args.addCommand.call([ + (e) => addCommandRef.call([ refer('upcastedType').property(e.symbol!), ]).statement, ), diff --git a/src/cli_gen/lib/src/code/command/user_method_call_builder.dart b/src/cli_gen/lib/src/code/command/user_method_call_builder.dart index e712022..04e73c9 100644 --- a/src/cli_gen/lib/src/code/command/user_method_call_builder.dart +++ b/src/cli_gen/lib/src/code/command/user_method_call_builder.dart @@ -65,7 +65,8 @@ class UserMethodCallBuilder { // b) whether the parameter is iterable and needs to call `.map` on the result Expression parserExpression; final isIterable = param.optionType == OptionType.multi; - if (isIterable && param.parser != null) { + final hasParser = param.parser != null; + if (isIterable && hasParser) { parserExpression = refer('List') .toTypeRef(typeArguments: [refer('String')]) .property('from') @@ -88,18 +89,36 @@ class UserMethodCallBuilder { switch ((isNullable, hasDefault)) { case (true, _): - return resultKeyValue.notEqualTo(literalNull).conditional( - parserExpression, - literalNull, - ); + if (hasParser || isIterable) { + return resultKeyValue.notEqualTo(literalNull).conditional( + parserExpression, + literalNull, + ); + } else { + return parserExpression + .asA( + param.type.toTypeRef(isNullable: true), + ) + .ifNullThen(literalNull); + } case (false, true): // in this case, we need to copy the defaultValueCode into the elseThen // expression of the conditional, because otherwise we're passing a null // value into a non-nullable parameter. - return resultKeyValue.notEqualTo(literalNull).conditional( - parserExpression, - param.defaultValueAsCode!, - ); + if (hasParser || isIterable) { + return resultKeyValue.notEqualTo(literalNull).conditional( + parserExpression, + param.defaultValueAsCode!, + ); + } else { + return parserExpression + .asA( + param.type.toTypeRef(isNullable: true), + ) + .ifNullThen( + param.defaultValueAsCode!, + ); + } case (false, false): return parserExpression; } diff --git a/src/cli_gen/pubspec.lock b/src/cli_gen/pubspec.lock index 5e761d5..fc5effa 100644 --- a/src/cli_gen/pubspec.lock +++ b/src/cli_gen/pubspec.lock @@ -49,6 +49,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + url: "https://pub.dev" + source: hosted + version: "2.4.8" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + url: "https://pub.dev" + source: hosted + version: "7.3.0" built_collection: dependency: transitive description: @@ -65,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.9.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" checks: dependency: "direct dev" description: @@ -160,6 +208,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" http_multi_server: dependency: transitive description: @@ -192,6 +248,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" lints: dependency: "direct dev" description: @@ -272,6 +336,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" recase: dependency: "direct main" description: @@ -360,6 +432,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -400,6 +480,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" typed_data: dependency: transitive description: diff --git a/src/cli_gen/pubspec.yaml b/src/cli_gen/pubspec.yaml index 4a06364..d26f24e 100644 --- a/src/cli_gen/pubspec.yaml +++ b/src/cli_gen/pubspec.yaml @@ -29,3 +29,4 @@ dev_dependencies: lints: ^3.0.0 test: ^1.24.0 coverage: ^1.7.2 + build_runner: ^2.4.8 diff --git a/src/cli_gen/test/example_usage/args_example.dart b/src/cli_gen/test/example_usage/args_example.dart index 01b5a39..133af75 100644 --- a/src/cli_gen/test/example_usage/args_example.dart +++ b/src/cli_gen/test/example_usage/args_example.dart @@ -70,7 +70,8 @@ void defaultValues({ // -- DOC COMMENTS -- -@CliCommand() +// ignore: invalid_annotation_target +@cliCommand class DocComments { const DocComments({ required this.message, @@ -79,7 +80,6 @@ class DocComments { /// The message to display. final String message; } - // -- MULTI-SELECT TESTS -- @CliCommand() diff --git a/src/cli_gen/test/example_usage/cli_method_call.dart b/src/cli_gen/test/example_usage/cli_method_call.dart deleted file mode 100644 index d8b9b19..0000000 --- a/src/cli_gen/test/example_usage/cli_method_call.dart +++ /dev/null @@ -1,13 +0,0 @@ -enum MyFooEnum { - value1, - value2; - - factory MyFooEnum.parse(String value) { - return MyFooEnum.values.firstWhere( - (e) => e.name == value, - orElse: () => throw ArgumentError( - 'Invalid value for MyFooEnum: $value', - ), - ); - } -} diff --git a/src/cli_gen/test/example_usage/runner_and_subcommands.dart b/src/cli_gen/test/example_usage/runner_and_subcommands.dart deleted file mode 100644 index 22a40e7..0000000 --- a/src/cli_gen/test/example_usage/runner_and_subcommands.dart +++ /dev/null @@ -1,5 +0,0 @@ - -// import 'package:cli_annotations/cli_annotations.dart'; - -// @cliSubcommand -// class FooCommand {} \ No newline at end of file diff --git a/test/goldens/.gitignore b/test/goldens/.gitignore new file mode 100644 index 0000000..3a85790 --- /dev/null +++ b/test/goldens/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/test/goldens/README.md b/test/goldens/README.md new file mode 100644 index 0000000..3816eca --- /dev/null +++ b/test/goldens/README.md @@ -0,0 +1,2 @@ +A sample command-line application with an entrypoint in `bin/`, library code +in `lib/`, and example unit test in `test/`. diff --git a/test/goldens/analysis_options.yaml b/test/goldens/analysis_options.yaml new file mode 100644 index 0000000..ab8b0e7 --- /dev/null +++ b/test/goldens/analysis_options.yaml @@ -0,0 +1,8 @@ +include: package:lints/recommended.yaml + +analyzer: + errors: + void_checks: false + prefer_if_null_operators: false + exclude: + - "**/*.golden.dart" diff --git a/test/goldens/lib/args/args.dart b/test/goldens/lib/args/args.dart new file mode 100644 index 0000000..1d6d1a5 --- /dev/null +++ b/test/goldens/lib/args/args.dart @@ -0,0 +1,3 @@ +/// Tests various use cases for generating `ArgParser.addOption` expressions +/// and the user method invocation within `Command.run`. +library goldens.args; diff --git a/test/goldens/lib/args/default_values/default_values.dart b/test/goldens/lib/args/default_values/default_values.dart new file mode 100644 index 0000000..426de07 --- /dev/null +++ b/test/goldens/lib/args/default_values/default_values.dart @@ -0,0 +1,42 @@ +/// This file tests two generations: +/// 1. `ArgParser.addOption.defaultsTo` is a stringified default value (or +/// a boolean, if the option is a flag). +/// 2. The default value is copied to the userMethod invocation as the true +/// value (i.e. not stringified). +library goldens.args.default_values; + +import 'package:cli_annotations/cli_annotations.dart'; + +part 'default_values.g.dart'; + +@cliRunner +class DefaultValues extends _$DefaultValues { + @cliCommand + void defaultValues({ + String strVal = 'default', + int intVal = 42, + bool boolVal = true, + MyFooEnum enumVal = MyFooEnum.value1, + @Option(defaultsTo: 123) int? intAnnot, + }) {} + + @cliCommand + void defaultIterableValues({ + List listVal = const ['a', 'b', 'c'], + Set setVal = const {1, 2, 3}, + Set multiEnumVal = const {MyFooEnum.value1, MyFooEnum.value2}, + }) {} + + @cliCommand + void annotatedParams({ + @Option(defaultsTo: 123) int? numericValue, + // TODO: broken test + // @MultiOption(defaultsTo: ['a', 'b', 'c']) + // List multiString = const [], + @Flag(defaultsTo: true) bool flagVal = false, + }) {} +} + +enum MyFooEnum { value1, value2 } + +const someConstant = 42; diff --git a/test/goldens/lib/args/default_values/default_values.g.dart b/test/goldens/lib/args/default_values/default_values.g.dart new file mode 100644 index 0000000..5b13099 --- /dev/null +++ b/test/goldens/lib/args/default_values/default_values.g.dart @@ -0,0 +1,195 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'default_values.dart'; + +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$DefaultValues extends CommandRunner { + _$DefaultValues() + : super( + 'default-values', + '', + ) { + final upcastedType = (this as DefaultValues); + addCommand(DefaultValuesCommand(upcastedType.defaultValues)); + addCommand( + DefaultIterableValuesCommand(upcastedType.defaultIterableValues)); + addCommand(AnnotatedParamsCommand(upcastedType.annotatedParams)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class DefaultValuesCommand extends Command { + DefaultValuesCommand(this.userMethod) { + argParser + ..addOption( + 'str-val', + defaultsTo: 'default', + mandatory: false, + ) + ..addOption( + 'int-val', + defaultsTo: '42', + mandatory: false, + ) + ..addFlag( + 'bool-val', + defaultsTo: true, + ) + ..addOption( + 'enum-val', + defaultsTo: 'value1', + mandatory: false, + allowed: [ + 'value1', + 'value2', + ], + ) + ..addOption( + 'int-annot', + defaultsTo: '123', + mandatory: false, + ); + } + + final void Function({ + String strVal, + int intVal, + bool boolVal, + MyFooEnum enumVal, + int intAnnot, + }) userMethod; + + @override + String get name => 'default-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + strVal: (results['str-val'] as String?) ?? 'default', + intVal: results['int-val'] != null ? int.parse(results['int-val']) : 42, + boolVal: (results['bool-val'] as bool?) ?? true, + enumVal: results['enum-val'] != null + ? EnumParser(MyFooEnum.values).parse(results['enum-val']) + : MyFooEnum.value1, + intAnnot: + results['int-annot'] != null ? int.parse(results['int-annot']) : 123, + ); + } +} + +class DefaultIterableValuesCommand extends Command { + DefaultIterableValuesCommand(this.userMethod) { + argParser + ..addMultiOption( + 'list-val', + defaultsTo: [ + 'a', + 'b', + 'c', + ], + ) + ..addMultiOption( + 'set-val', + defaultsTo: [ + '1', + '2', + '3', + ], + ) + ..addMultiOption( + 'multi-enum-val', + defaultsTo: [ + 'value1', + 'value2', + ], + ); + } + + final void Function({ + List listVal, + Set setVal, + Set multiEnumVal, + }) userMethod; + + @override + String get name => 'default-iterable-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + listVal: results['list-val'] != null + ? List.from(results['list-val']) + : const ['a', 'b', 'c'], + setVal: results['set-val'] != null + ? List.from(results['set-val']).map(int.parse).toSet() + : const {1, 2, 3}, + multiEnumVal: results['multi-enum-val'] != null + ? List.from(results['multi-enum-val']) + .map(EnumParser(MyFooEnum.values).parse) + .toSet() + : const {MyFooEnum.value1, MyFooEnum.value2}, + ); + } +} + +class AnnotatedParamsCommand extends Command { + AnnotatedParamsCommand(this.userMethod) { + argParser + ..addOption( + 'numeric-value', + defaultsTo: '123', + mandatory: false, + ) + ..addFlag( + 'flag-val', + defaultsTo: true, + ); + } + + final void Function({ + int numericValue, + bool flagVal, + }) userMethod; + + @override + String get name => 'annotated-params'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + numericValue: results['numeric-value'] != null + ? int.parse(results['numeric-value']) + : 123, + flagVal: (results['flag-val'] as bool?) ?? true, + ); + } +} diff --git a/test/goldens/lib/args/default_values/default_values.g.golden.dart b/test/goldens/lib/args/default_values/default_values.g.golden.dart new file mode 100644 index 0000000..b379ab2 --- /dev/null +++ b/test/goldens/lib/args/default_values/default_values.g.golden.dart @@ -0,0 +1,191 @@ +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$DefaultValues extends CommandRunner { + _$DefaultValues() + : super( + 'default-values', + '', + ) { + final upcastedType = (this as DefaultValues); + addCommand(DefaultValuesCommand(upcastedType.defaultValues)); + addCommand( + DefaultIterableValuesCommand(upcastedType.defaultIterableValues)); + addCommand(AnnotatedParamsCommand(upcastedType.annotatedParams)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class DefaultValuesCommand extends Command { + DefaultValuesCommand(this.userMethod) { + argParser + ..addOption( + 'str-val', + defaultsTo: 'default', + mandatory: false, + ) + ..addOption( + 'int-val', + defaultsTo: '42', + mandatory: false, + ) + ..addFlag( + 'bool-val', + defaultsTo: true, + ) + ..addOption( + 'enum-val', + defaultsTo: 'value1', + mandatory: false, + allowed: [ + 'value1', + 'value2', + ], + ) + ..addOption( + 'int-annot', + defaultsTo: '123', + mandatory: false, + ); + } + + final void Function({ + String strVal, + int intVal, + bool boolVal, + MyFooEnum enumVal, + int intAnnot, + }) userMethod; + + @override + String get name => 'default-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + strVal: results['str-val'] != null ? results['str-val'] : 'default', + intVal: results['int-val'] != null ? int.parse(results['int-val']) : 42, + boolVal: results['bool-val'] != null ? results['bool-val'] : true, + enumVal: results['enum-val'] != null + ? EnumParser(MyFooEnum.values).parse(results['enum-val']) + : MyFooEnum.value1, + intAnnot: + results['int-annot'] != null ? int.parse(results['int-annot']) : 123, + ); + } +} + +class DefaultIterableValuesCommand extends Command { + DefaultIterableValuesCommand(this.userMethod) { + argParser + ..addMultiOption( + 'list-val', + defaultsTo: [ + 'a', + 'b', + 'c', + ], + ) + ..addMultiOption( + 'set-val', + defaultsTo: [ + '1', + '2', + '3', + ], + ) + ..addMultiOption( + 'multi-enum-val', + defaultsTo: [ + 'value1', + 'value2', + ], + ); + } + + final void Function({ + List listVal, + Set setVal, + Set multiEnumVal, + }) userMethod; + + @override + String get name => 'default-iterable-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + listVal: results['list-val'] != null + ? List.from(results['list-val']) + : const ['a', 'b', 'c'], + setVal: results['set-val'] != null + ? List.from(results['set-val']).map(int.parse).toSet() + : const {1, 2, 3}, + multiEnumVal: results['multi-enum-val'] != null + ? List.from(results['multi-enum-val']) + .map(EnumParser(MyFooEnum.values).parse) + .toSet() + : const {MyFooEnum.value1, MyFooEnum.value2}, + ); + } +} + +class AnnotatedParamsCommand extends Command { + AnnotatedParamsCommand(this.userMethod) { + argParser + ..addOption( + 'numeric-value', + defaultsTo: '123', + mandatory: false, + ) + ..addFlag( + 'flag-val', + defaultsTo: true, + ); + } + + final void Function({ + int numericValue, + bool flagVal, + }) userMethod; + + @override + String get name => 'annotated-params'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + numericValue: results['numeric-value'] != null + ? int.parse(results['numeric-value']) + : 123, + flagVal: results['flag-val'] != null ? results['flag-val'] : true, + ); + } +} diff --git a/test/goldens/lib/args/multi_select/multi_select.dart b/test/goldens/lib/args/multi_select/multi_select.dart new file mode 100644 index 0000000..ed0e13d --- /dev/null +++ b/test/goldens/lib/args/multi_select/multi_select.dart @@ -0,0 +1,20 @@ +import 'package:cli_annotations/cli_annotations.dart'; + +part 'multi_select.g.dart'; + +@cliRunner +class MultiSelect extends _$MultiSelect { + @cliCommand + void multiValues({ + required List multiString, + Set? multiInt = const {1, 5, 7}, + Iterable? multiEnum, + }) {} + + @cliCommand + void singleValues({ + int multiInt = 1, + }) {} +} + +enum MyFooEnum { value1, value2 } diff --git a/test/goldens/lib/args/multi_select/multi_select.g.dart b/test/goldens/lib/args/multi_select/multi_select.g.dart new file mode 100644 index 0000000..acad23d --- /dev/null +++ b/test/goldens/lib/args/multi_select/multi_select.g.dart @@ -0,0 +1,101 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'multi_select.dart'; + +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$MultiSelect extends CommandRunner { + _$MultiSelect() + : super( + 'multi-select', + '', + ) { + final upcastedType = (this as MultiSelect); + addCommand(MultiValuesCommand(upcastedType.multiValues)); + addCommand(SingleValuesCommand(upcastedType.singleValues)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class MultiValuesCommand extends Command { + MultiValuesCommand(this.userMethod) { + argParser + ..addMultiOption('multi-string') + ..addMultiOption( + 'multi-int', + defaultsTo: [ + '1', + '5', + '7', + ], + ) + ..addMultiOption('multi-enum'); + } + + final void Function({ + required List multiString, + Set multiInt, + Iterable multiEnum, + }) userMethod; + + @override + String get name => 'multi-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + multiString: List.from(results['multi-string']), + multiInt: results['multi-int'] != null + ? List.from(results['multi-int']).map(int.parse).toSet() + : const {1, 5, 7}, + multiEnum: List.from(results['multi-enum']) + .map(EnumParser(MyFooEnum.values).parse), + ); + } +} + +class SingleValuesCommand extends Command { + SingleValuesCommand(this.userMethod) { + argParser.addOption( + 'multi-int', + defaultsTo: '1', + mandatory: false, + ); + } + + final void Function({int multiInt}) userMethod; + + @override + String get name => 'single-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + multiInt: + results['multi-int'] != null ? int.parse(results['multi-int']) : 1); + } +} diff --git a/test/goldens/lib/args/multi_select/multi_select.g.golden.dart b/test/goldens/lib/args/multi_select/multi_select.g.golden.dart new file mode 100644 index 0000000..8defe8b --- /dev/null +++ b/test/goldens/lib/args/multi_select/multi_select.g.golden.dart @@ -0,0 +1,97 @@ +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$MultiSelect extends CommandRunner { + _$MultiSelect() + : super( + 'multi-select', + '', + ) { + final upcastedType = (this as MultiSelect); + addCommand(MultiValuesCommand(upcastedType.multiValues)); + addCommand(SingleValuesCommand(upcastedType.singleValues)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class MultiValuesCommand extends Command { + MultiValuesCommand(this.userMethod) { + argParser + ..addMultiOption('multi-string') + ..addMultiOption( + 'multi-int', + defaultsTo: [ + '1', + '5', + '7', + ], + ) + ..addMultiOption('multi-enum'); + } + + final void Function({ + required List multiString, + Set multiInt, + Iterable multiEnum, + }) userMethod; + + @override + String get name => 'multi-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + multiString: List.from(results['multi-string']), + multiInt: results['multi-int'] != null + ? List.from(results['multi-int']).map(int.parse).toSet() + : const {1, 5, 7}, + multiEnum: List.from(results['multi-enum']) + .map(EnumParser(MyFooEnum.values).parse), + ); + } +} + +class SingleValuesCommand extends Command { + SingleValuesCommand(this.userMethod) { + argParser.addOption( + 'multi-int', + defaultsTo: '1', + mandatory: false, + ); + } + + final void Function({int multiInt}) userMethod; + + @override + String get name => 'single-values'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + multiInt: + results['multi-int'] != null ? int.parse(results['multi-int']) : 1); + } +} diff --git a/test/goldens/lib/args/named_positional/named_positional.dart b/test/goldens/lib/args/named_positional/named_positional.dart new file mode 100644 index 0000000..4d91938 --- /dev/null +++ b/test/goldens/lib/args/named_positional/named_positional.dart @@ -0,0 +1,20 @@ +import 'package:cli_annotations/cli_annotations.dart'; + +part 'named_positional.g.dart'; + +@cliRunner +class NamedPositional extends _$NamedPositional { + @CliCommand() + void positional( + String reqValue, [ + String? optValue, + String defValue = 'default', + ]) {} + + @cliCommand + void named({ + required String reqValue, + String? optValue, + String defValue = 'default', + }) {} +} diff --git a/test/goldens/lib/args/named_positional/named_positional.g.dart b/test/goldens/lib/args/named_positional/named_positional.g.dart new file mode 100644 index 0000000..b36240d --- /dev/null +++ b/test/goldens/lib/args/named_positional/named_positional.g.dart @@ -0,0 +1,116 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'named_positional.dart'; + +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$NamedPositional extends CommandRunner { + _$NamedPositional() + : super( + 'named-positional', + '', + ) { + final upcastedType = (this as NamedPositional); + addCommand(PositionalCommand(upcastedType.positional)); + addCommand(NamedCommand(upcastedType.named)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class PositionalCommand extends Command { + PositionalCommand(this.userMethod) { + argParser + ..addOption( + 'req-value', + mandatory: true, + ) + ..addOption( + 'opt-value', + mandatory: false, + ) + ..addOption( + 'def-value', + defaultsTo: 'default', + mandatory: false, + ); + } + + final void Function( + String, [ + String, + String, + ]) userMethod; + + @override + String get name => 'positional'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + results['req-value'], + results['opt-value'], + (results['def-value'] as String?) ?? 'default', + ); + } +} + +class NamedCommand extends Command { + NamedCommand(this.userMethod) { + argParser + ..addOption( + 'req-value', + mandatory: true, + ) + ..addOption( + 'opt-value', + mandatory: false, + ) + ..addOption( + 'def-value', + defaultsTo: 'default', + mandatory: false, + ); + } + + final void Function({ + required String reqValue, + String optValue, + String defValue, + }) userMethod; + + @override + String get name => 'named'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + reqValue: results['req-value'], + optValue: results['opt-value'], + defValue: (results['def-value'] as String?) ?? 'default', + ); + } +} diff --git a/test/goldens/lib/args/named_positional/named_positional.g.golden.dart b/test/goldens/lib/args/named_positional/named_positional.g.golden.dart new file mode 100644 index 0000000..06a50e0 --- /dev/null +++ b/test/goldens/lib/args/named_positional/named_positional.g.golden.dart @@ -0,0 +1,112 @@ +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$NamedPositional extends CommandRunner { + _$NamedPositional() + : super( + 'named-positional', + '', + ) { + final upcastedType = (this as NamedPositional); + addCommand(PositionalCommand(upcastedType.positional)); + addCommand(NamedCommand(upcastedType.named)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class PositionalCommand extends Command { + PositionalCommand(this.userMethod) { + argParser + ..addOption( + 'req-value', + mandatory: true, + ) + ..addOption( + 'opt-value', + mandatory: false, + ) + ..addOption( + 'def-value', + defaultsTo: 'default', + mandatory: false, + ); + } + + final void Function( + String, [ + String, + String, + ]) userMethod; + + @override + String get name => 'positional'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + results['req-value'], + results['opt-value'], + results['def-value'] != null ? results['def-value'] : 'default', + ); + } +} + +class NamedCommand extends Command { + NamedCommand(this.userMethod) { + argParser + ..addOption( + 'req-value', + mandatory: true, + ) + ..addOption( + 'opt-value', + mandatory: false, + ) + ..addOption( + 'def-value', + defaultsTo: 'default', + mandatory: false, + ); + } + + final void Function({ + required String reqValue, + String optValue, + String defValue, + }) userMethod; + + @override + String get name => 'named'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + reqValue: results['req-value'], + optValue: results['opt-value'], + defValue: results['def-value'] != null ? results['def-value'] : 'default', + ); + } +} diff --git a/test/goldens/lib/args/types/types.dart b/test/goldens/lib/args/types/types.dart new file mode 100644 index 0000000..d89904c --- /dev/null +++ b/test/goldens/lib/args/types/types.dart @@ -0,0 +1,40 @@ +import 'package:cli_annotations/cli_annotations.dart'; + +part 'types.g.dart'; + +@cliRunner +class Types extends _$Types { + @cliCommand + void primativeTypes( + String stringValue, + int intValue, + bool boolValue, + ) {} + + @cliCommand + void userTypes( + MyFooEnum enumValue, { + MyFooEnum enumValue2 = MyFooEnum.value1, + @Option(parser: Email.fromString) Email emailValue2 = const Email('foo'), + int constVar = someConstant, + @Option(parser: customParser) int customParserOption = 0, + @Option(parser: ProductId.fromString) ProductId? productId, + }) {} +} + +enum MyFooEnum { value1, value2 } + +const someConstant = 42; + +int customParser(String value) => int.parse(value); + +extension type const Email(String value) { + factory Email.fromString(String value) => Email(value); +} + +class ProductId { + final String value; + const ProductId(this.value); + + factory ProductId.fromString(String value) => ProductId(value); +} diff --git a/test/goldens/lib/args/types/types.g.dart b/test/goldens/lib/args/types/types.g.dart new file mode 100644 index 0000000..051ff77 --- /dev/null +++ b/test/goldens/lib/args/types/types.g.dart @@ -0,0 +1,149 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'types.dart'; + +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$Types extends CommandRunner { + _$Types() + : super( + 'types', + '', + ) { + final upcastedType = (this as Types); + addCommand(PrimativeTypesCommand(upcastedType.primativeTypes)); + addCommand(UserTypesCommand(upcastedType.userTypes)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class PrimativeTypesCommand extends Command { + PrimativeTypesCommand(this.userMethod) { + argParser + ..addOption( + 'string-value', + mandatory: true, + ) + ..addOption( + 'int-value', + mandatory: true, + ) + ..addFlag('bool-value'); + } + + final void Function( + String, + int, + bool, + ) userMethod; + + @override + String get name => 'primative-types'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + results['string-value'], + int.parse(results['int-value']), + results['bool-value'], + ); + } +} + +class UserTypesCommand extends Command { + UserTypesCommand(this.userMethod) { + argParser + ..addOption( + 'enum-value', + mandatory: true, + allowed: [ + 'value1', + 'value2', + ], + ) + ..addOption( + 'enum-value2', + defaultsTo: 'value1', + mandatory: false, + allowed: [ + 'value1', + 'value2', + ], + ) + ..addOption( + 'email-value2', + defaultsTo: 'foo', + mandatory: false, + ) + ..addOption( + 'const-var', + defaultsTo: '42', + mandatory: false, + ) + ..addOption( + 'custom-parser-option', + defaultsTo: '0', + mandatory: false, + ) + ..addOption( + 'product-id', + mandatory: false, + ); + } + + final void Function( + MyFooEnum, { + MyFooEnum enumValue2, + Email emailValue2, + int constVar, + int customParserOption, + ProductId productId, + }) userMethod; + + @override + String get name => 'user-types'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + EnumParser(MyFooEnum.values).parse(results['enum-value']), + enumValue2: results['enum-value2'] != null + ? EnumParser(MyFooEnum.values).parse(results['enum-value2']) + : MyFooEnum.value1, + emailValue2: results['email-value2'] != null + ? Email.fromString(results['email-value2']) + : const Email('foo'), + constVar: results['const-var'] != null + ? int.parse(results['const-var']) + : someConstant, + customParserOption: results['custom-parser-option'] != null + ? customParser(results['custom-parser-option']) + : 0, + productId: ProductId.fromString(results['product-id']), + ); + } +} diff --git a/test/goldens/lib/args/types/types.g.golden.dart b/test/goldens/lib/args/types/types.g.golden.dart new file mode 100644 index 0000000..5e0ae0b --- /dev/null +++ b/test/goldens/lib/args/types/types.g.golden.dart @@ -0,0 +1,145 @@ +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$Types extends CommandRunner { + _$Types() + : super( + 'types', + '', + ) { + final upcastedType = (this as Types); + addCommand(PrimativeTypesCommand(upcastedType.primativeTypes)); + addCommand(UserTypesCommand(upcastedType.userTypes)); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class PrimativeTypesCommand extends Command { + PrimativeTypesCommand(this.userMethod) { + argParser + ..addOption( + 'string-value', + mandatory: true, + ) + ..addOption( + 'int-value', + mandatory: true, + ) + ..addFlag('bool-value'); + } + + final void Function( + String, + int, + bool, + ) userMethod; + + @override + String get name => 'primative-types'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + results['string-value'], + int.parse(results['int-value']), + results['bool-value'], + ); + } +} + +class UserTypesCommand extends Command { + UserTypesCommand(this.userMethod) { + argParser + ..addOption( + 'enum-value', + mandatory: true, + allowed: [ + 'value1', + 'value2', + ], + ) + ..addOption( + 'enum-value2', + defaultsTo: 'value1', + mandatory: false, + allowed: [ + 'value1', + 'value2', + ], + ) + ..addOption( + 'email-value2', + defaultsTo: 'foo', + mandatory: false, + ) + ..addOption( + 'const-var', + defaultsTo: '42', + mandatory: false, + ) + ..addOption( + 'custom-parser-option', + defaultsTo: '0', + mandatory: false, + ) + ..addOption( + 'product-id', + mandatory: false, + ); + } + + final void Function( + MyFooEnum, { + MyFooEnum enumValue2, + Email emailValue2, + int constVar, + int customParserOption, + ProductId productId, + }) userMethod; + + @override + String get name => 'user-types'; + + @override + String get description => ''; + + @override + void run() { + final results = argResults!; + return userMethod( + EnumParser(MyFooEnum.values).parse(results['enum-value']), + enumValue2: results['enum-value2'] != null + ? EnumParser(MyFooEnum.values).parse(results['enum-value2']) + : MyFooEnum.value1, + emailValue2: results['email-value2'] != null + ? Email.fromString(results['email-value2']) + : const Email('foo'), + constVar: results['const-var'] != null + ? int.parse(results['const-var']) + : someConstant, + customParserOption: results['custom-parser-option'] != null + ? customParser(results['custom-parser-option']) + : 0, + productId: ProductId.fromString(results['product-id']), + ); + } +} diff --git a/test/goldens/lib/commands/command/command.dart b/test/goldens/lib/commands/command/command.dart new file mode 100644 index 0000000..8b638dd --- /dev/null +++ b/test/goldens/lib/commands/command/command.dart @@ -0,0 +1,14 @@ +library goldens.commands.runner; + +import 'package:cli_annotations/cli_annotations.dart'; + +part 'command.g.dart'; + +@cliSubcommand +class FooBarSubcommand extends _$FooBarSubcommand { + @cliCommand + int foo() => 42; + + @cliCommand + int bar() => 42; +} diff --git a/test/goldens/lib/commands/command/command.g.dart b/test/goldens/lib/commands/command/command.g.dart new file mode 100644 index 0000000..41c3bf5 --- /dev/null +++ b/test/goldens/lib/commands/command/command.g.dart @@ -0,0 +1,55 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'command.dart'; + +// ************************************************************************** +// SubcommandGenerator +// ************************************************************************** + +class _$FooBarSubcommand extends Command { + _$FooBarSubcommand() { + final upcastedType = (this as FooBarSubcommand); + addSubcommand(FooCommand(upcastedType.foo)); + addSubcommand(BarCommand(upcastedType.bar)); + } + + @override + String get name => 'foo-bar'; + + @override + String get description => ''; +} + +class FooCommand extends Command { + FooCommand(this.userMethod); + + final int Function() userMethod; + + @override + String get name => 'foo'; + + @override + String get description => ''; + + @override + int run() { + return userMethod(); + } +} + +class BarCommand extends Command { + BarCommand(this.userMethod); + + final int Function() userMethod; + + @override + String get name => 'bar'; + + @override + String get description => ''; + + @override + int run() { + return userMethod(); + } +} diff --git a/test/goldens/lib/commands/runner/runner.dart b/test/goldens/lib/commands/runner/runner.dart new file mode 100644 index 0000000..c2a7a75 --- /dev/null +++ b/test/goldens/lib/commands/runner/runner.dart @@ -0,0 +1,28 @@ +library goldens.commands.runner; + +import 'package:cli_annotations/cli_annotations.dart'; + +part 'runner.g.dart'; + +@cliRunner +class FooBarRunner extends _$FooBarRunner { + @cliMount + Command get bar => BarCommand(); + + @cliCommand + void foo() {} +} + +@cliSubcommand +class BarCommand extends _$BarCommand {} + +/// Some runner description from doc comment. +@CliRunner( + name: 'some-runner', + description: 'Some runner description from annotation.', + displayStackTrace: true, +) +class Runner extends _$Runner { + @cliMount + BarCommand get fooBar => BarCommand(); +} diff --git a/test/goldens/lib/commands/runner/runner.g.dart b/test/goldens/lib/commands/runner/runner.g.dart new file mode 100644 index 0000000..a7b3eb5 --- /dev/null +++ b/test/goldens/lib/commands/runner/runner.g.dart @@ -0,0 +1,83 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'runner.dart'; + +// ************************************************************************** +// SubcommandGenerator +// ************************************************************************** + +class _$BarCommand extends Command { + _$BarCommand(); + + @override + String get name => 'bar'; + + @override + String get description => ''; +} + +// ************************************************************************** +// CliRunnerGenerator +// ************************************************************************** + +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$FooBarRunner extends CommandRunner { + _$FooBarRunner() + : super( + 'foo-bar', + '', + ) { + final upcastedType = (this as FooBarRunner); + addCommand(FooCommand(upcastedType.foo)); + addCommand(upcastedType.bar); + } + + @override + Future runCommand(ArgResults topLevelResults) async { + try { + return await super.runCommand(topLevelResults); + } on UsageException catch (e) { + stdout.writeln('${e.message}\n'); + stdout.writeln(e.usage); + } + } +} + +class FooCommand extends Command { + FooCommand(this.userMethod); + + final void Function() userMethod; + + @override + String get name => 'foo'; + + @override + String get description => ''; + + @override + void run() { + return userMethod(); + } +} + +/// Some runner description from annotation. +/// +/// A class for invoking [Command]s based on raw command-line arguments. +/// +/// The type argument `T` represents the type returned by [Command.run] and +/// [CommandRunner.run]; it can be ommitted if you're not using the return +/// values. +class _$Runner extends CommandRunner { + _$Runner() + : super( + 'some-runner', + 'Some runner description from annotation.', + ) { + final upcastedType = (this as Runner); + addCommand(upcastedType.fooBar); + } +} diff --git a/test/goldens/lib/commands/subcommand/subcommand.dart b/test/goldens/lib/commands/subcommand/subcommand.dart new file mode 100644 index 0000000..f301510 --- /dev/null +++ b/test/goldens/lib/commands/subcommand/subcommand.dart @@ -0,0 +1,17 @@ +library goldens.commands.runner; + +import 'package:cli_annotations/cli_annotations.dart'; + +part 'subcommand.g.dart'; + +@cliSubcommand +class FooBarSubcommand extends _$FooBarSubcommand { + @cliMount + BarCommand get bar => BarCommand(); + + @cliCommand + int foo() => 42; +} + +@cliSubcommand +class BarCommand extends _$BarCommand {} diff --git a/test/goldens/lib/commands/subcommand/subcommand.g.dart b/test/goldens/lib/commands/subcommand/subcommand.g.dart new file mode 100644 index 0000000..f891713 --- /dev/null +++ b/test/goldens/lib/commands/subcommand/subcommand.g.dart @@ -0,0 +1,48 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'subcommand.dart'; + +// ************************************************************************** +// SubcommandGenerator +// ************************************************************************** + +class _$FooBarSubcommand extends Command { + _$FooBarSubcommand() { + final upcastedType = (this as FooBarSubcommand); + addSubcommand(FooCommand(upcastedType.foo)); + addSubcommand(upcastedType.bar); + } + + @override + String get name => 'foo-bar'; + + @override + String get description => ''; +} + +class FooCommand extends Command { + FooCommand(this.userMethod); + + final int Function() userMethod; + + @override + String get name => 'foo'; + + @override + String get description => ''; + + @override + int run() { + return userMethod(); + } +} + +class _$BarCommand extends Command { + _$BarCommand(); + + @override + String get name => 'bar'; + + @override + String get description => ''; +} diff --git a/test/goldens/lib/goldens.dart b/test/goldens/lib/goldens.dart new file mode 100644 index 0000000..f64ad72 --- /dev/null +++ b/test/goldens/lib/goldens.dart @@ -0,0 +1,3 @@ +int calculate() { + return 6 * 7; +} diff --git a/test/goldens/lib/integration/main.dart b/test/goldens/lib/integration/main.dart new file mode 100644 index 0000000..1225554 --- /dev/null +++ b/test/goldens/lib/integration/main.dart @@ -0,0 +1,3 @@ +Future main() async { + // TODO: any integration tests that check runtime behavior +} diff --git a/test/goldens/pubspec.lock b/test/goldens/pubspec.lock new file mode 100644 index 0000000..34a4108 --- /dev/null +++ b/test/goldens/pubspec.lock @@ -0,0 +1,571 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: "direct dev" + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + url: "https://pub.dev" + source: hosted + version: "4.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + url: "https://pub.dev" + source: hosted + version: "2.4.8" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + url: "https://pub.dev" + source: hosted + version: "7.3.0" + build_test: + dependency: "direct dev" + description: + name: build_test + sha256: "260dbba934f41b0a42935e9cae1f5731b94f0c3e489dc97bcf8e281265aaa5ae" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 + url: "https://pub.dev" + source: hosted + version: "8.9.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_annotations: + dependency: "direct main" + description: + path: "../../src/cli_annotations" + relative: true + source: path + version: "0.1.0-dev.4" + cli_gen: + dependency: "direct dev" + description: + path: "../../src/cli_gen" + relative: true + source: path + version: "0.1.0-dev.4" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + url: "https://pub.dev" + source: hosted + version: "2.3.4" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: "4186c61b32f99e60f011f7160e32c89a758ae9b1d0c6d28e2c02ef0382300e2b" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: "direct dev" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct main" + description: + name: test + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + url: "https://pub.dev" + source: hosted + version: "1.25.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + url: "https://pub.dev" + source: hosted + version: "0.6.0" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246 + url: "https://pub.dev" + source: hosted + version: "14.0.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.0 <4.0.0" diff --git a/test/goldens/pubspec.yaml b/test/goldens/pubspec.yaml new file mode 100644 index 0000000..8d18c9f --- /dev/null +++ b/test/goldens/pubspec.yaml @@ -0,0 +1,21 @@ +name: goldens +version: 1.0.0 +publish_to: none + +environment: + sdk: ^3.3.0 + +dependencies: + # cli_annotations: ^0.1.0-dev.4 + cli_annotations: + path: ../../src/cli_annotations + test: ^1.25.2 + +dev_dependencies: + build: ^2.4.1 + build_runner: ^2.4.8 + build_test: ^2.2.2 + cli_gen: + path: ../../src/cli_gen + lints: ^3.0.0 + path: ^1.9.0 diff --git a/test/goldens/pubspec_overrides.yaml b/test/goldens/pubspec_overrides.yaml new file mode 100644 index 0000000..c56eb29 --- /dev/null +++ b/test/goldens/pubspec_overrides.yaml @@ -0,0 +1,6 @@ +# melos_managed_dependency_overrides: cli_annotations,cli_gen +dependency_overrides: + cli_annotations: + path: ../../src/cli_annotations + cli_gen: + path: ../../src/cli_gen diff --git a/test/goldens/test/args/default_values/default_values_test.dart b/test/goldens/test/args/default_values/default_values_test.dart new file mode 100644 index 0000000..2524fa5 --- /dev/null +++ b/test/goldens/test/args/default_values/default_values_test.dart @@ -0,0 +1,37 @@ +// ignore: depend_on_referenced_packages +// ignore_for_file: unused_local_variable + +import 'dart:io'; + +import 'package:build/build.dart'; +import 'package:build_test/build_test.dart'; +import 'package:cli_gen/builder.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +Future main() async { + final dirPath = Directory.current.path; + final userFilePath = 'lib/args/default_values/default_values.dart'; + final genFilePath = 'lib/args/default_values/default_values.g.dart'; + + final goldenPath = 'lib/args/default_values/default_values.g.golden.dart'; + + final fileContents = File(p.join(dirPath, userFilePath)).readAsStringSync(); + final genFileContents = File(p.join(dirPath, genFilePath)).readAsStringSync(); + final goldenContents = File(p.join(dirPath, goldenPath)).readAsStringSync(); + + group('default values golden tests -', () { + test('standard values', () async { + await testBuilder( + cliGenerator(BuilderOptions({})), + { + 'a|foo/default_values.dart': fileContents, + }, + reader: await PackageAssetReader.currentIsolate(), + outputs: { + 'a|foo/default_values.cli_generator.g.part': goldenContents, + }, + ); + }); + }); +} diff --git a/test/goldens/test/args/multi_select/multi_select_test.dart b/test/goldens/test/args/multi_select/multi_select_test.dart new file mode 100644 index 0000000..e0ef159 --- /dev/null +++ b/test/goldens/test/args/multi_select/multi_select_test.dart @@ -0,0 +1,37 @@ +// ignore: depend_on_referenced_packages +// ignore_for_file: unused_local_variable + +import 'dart:io'; + +import 'package:build/build.dart'; +import 'package:build_test/build_test.dart'; +import 'package:cli_gen/builder.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +Future main() async { + final dirPath = Directory.current.path; + final userFilePath = 'lib/args/multi_select/multi_select.dart'; + final genFilePath = 'lib/args/multi_select/multi_select.g.dart'; + + final goldenPath = 'lib/args/multi_select/multi_select.g.golden.dart'; + + final fileContents = File(p.join(dirPath, userFilePath)).readAsStringSync(); + final genFileContents = File(p.join(dirPath, genFilePath)).readAsStringSync(); + final goldenContents = File(p.join(dirPath, goldenPath)).readAsStringSync(); + + group('multi_select golden tests -', () { + test('standard values', () async { + await testBuilder( + cliGenerator(BuilderOptions({})), + { + 'a|foo/multi_select.dart': fileContents, + }, + reader: await PackageAssetReader.currentIsolate(), + outputs: { + 'a|foo/multi_select.cli_generator.g.part': goldenContents, + }, + ); + }); + }); +} diff --git a/test/goldens/test/args/named_positional/named_positional_test.dart b/test/goldens/test/args/named_positional/named_positional_test.dart new file mode 100644 index 0000000..8bb1f8c --- /dev/null +++ b/test/goldens/test/args/named_positional/named_positional_test.dart @@ -0,0 +1,37 @@ +// ignore: depend_on_referenced_packages +// ignore_for_file: unused_local_variable + +import 'dart:io'; + +import 'package:build/build.dart'; +import 'package:build_test/build_test.dart'; +import 'package:cli_gen/builder.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +Future main() async { + final dirPath = Directory.current.path; + final userFilePath = 'lib/args/named_positional/named_positional.dart'; + final genFilePath = 'lib/args/named_positional/named_positional.g.dart'; + + final goldenPath = 'lib/args/named_positional/named_positional.g.golden.dart'; + + final fileContents = File(p.join(dirPath, userFilePath)).readAsStringSync(); + final genFileContents = File(p.join(dirPath, genFilePath)).readAsStringSync(); + final goldenContents = File(p.join(dirPath, goldenPath)).readAsStringSync(); + + group('named_positional golden tests -', () { + test('standard values', () async { + await testBuilder( + cliGenerator(BuilderOptions({})), + { + 'a|foo/named_positional.dart': fileContents, + }, + reader: await PackageAssetReader.currentIsolate(), + outputs: { + 'a|foo/named_positional.cli_generator.g.part': goldenContents, + }, + ); + }); + }); +} diff --git a/test/goldens/test/args/types/types_test.dart b/test/goldens/test/args/types/types_test.dart new file mode 100644 index 0000000..f041a9f --- /dev/null +++ b/test/goldens/test/args/types/types_test.dart @@ -0,0 +1,37 @@ +// ignore: depend_on_referenced_packages +// ignore_for_file: unused_local_variable + +import 'dart:io'; + +import 'package:build/build.dart'; +import 'package:build_test/build_test.dart'; +import 'package:cli_gen/builder.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +Future main() async { + final dirPath = Directory.current.path; + final userFilePath = 'lib/args/types/types.dart'; + final genFilePath = 'lib/args/types/types.g.dart'; + + final goldenPath = 'lib/args/types/types.g.golden.dart'; + + final fileContents = File(p.join(dirPath, userFilePath)).readAsStringSync(); + final genFileContents = File(p.join(dirPath, genFilePath)).readAsStringSync(); + final goldenContents = File(p.join(dirPath, goldenPath)).readAsStringSync(); + + group('types golden tests -', () { + test('standard values', () async { + await testBuilder( + cliGenerator(BuilderOptions({})), + { + 'a|foo/types.dart': fileContents, + }, + reader: await PackageAssetReader.currentIsolate(), + outputs: { + 'a|foo/types.cli_generator.g.part': goldenContents, + }, + ); + }); + }); +}