From 249dc37380fc81d82e0896fd91d8f46288739fe1 Mon Sep 17 00:00:00 2001 From: spideythewebhead Date: Fri, 14 Apr 2023 18:10:08 +0300 Subject: [PATCH] Tachyon migration --- .github/workflows/release.yml | 2 +- .github/workflows/validate_plugin.yml | 2 +- assets/screenshots/007.png | Bin 5346 -> 0 bytes assets/screenshots/009.png | Bin 14066 -> 0 bytes assets/screenshots/010.png | Bin 21246 -> 0 bytes assets/screenshots/011.png | Bin 23928 -> 0 bytes assets/screenshots/dataclass.png | Bin 0 -> 35226 bytes assets/screenshots/enum.png | Bin 0 -> 28188 bytes assets/screenshots/union.png | Bin 0 -> 71892 bytes examples/README.md | 4 +- .../data_class_plugin_options.yaml | 7 - .../lib/data_class/copy_with.gen.dart | 4 +- .../lib/data_class/default_value.gen.dart | 4 +- .../from_json/custom_json_converter.gen.dart | 4 +- .../data_class/from_json/json_key.gen.dart | 4 +- .../lib/data_class/from_json/simple.gen.dart | 4 +- .../lib/data_class/generics.gen.dart | 4 +- .../lib/data_class/hash_and_equality.gen.dart | 4 +- .../lib/data_class/inheritance.gen.dart | 4 +- .../lib/data_class/simple.gen.dart | 4 +- .../to_json/custom_json_converter.gen.dart | 4 +- .../lib/data_class/to_json/json_key.gen.dart | 4 +- .../lib/data_class/to_json/simple.gen.dart | 4 +- .../lib/union/copy_with.dart | 2 +- .../lib/union/copy_with.gen.dart | 4 +- .../lib/union/default_value.dart | 2 +- .../lib/union/default_value.gen.dart | 4 +- .../lib/union/from_json/json_key.dart | 2 +- .../lib/union/from_json/json_key.gen.dart | 4 +- .../lib/union/from_json/simple.dart | 2 +- .../lib/union/from_json/simple.gen.dart | 4 +- .../lib/union/generics.dart | 4 +- .../lib/union/generics.gen.dart | 4 +- .../lib/union/hash_and_equality.dart | 2 +- .../lib/union/hash_and_equality.gen.dart | 4 +- .../lib/union/shared_fields.dart | 2 +- .../lib/union/shared_fields.gen.dart | 4 +- .../lib/union/simple.dart | 2 +- .../lib/union/simple.gen.dart | 4 +- .../lib/union/to_json/json_key.dart | 2 +- .../lib/union/to_json/json_key.gen.dart | 4 +- .../lib/union/to_json/simple.dart | 2 +- .../lib/union/to_json/simple.gen.dart | 4 +- examples/file_generation_mode/pubspec.lock | 144 ++--- examples/file_generation_mode/pubspec.yaml | 7 +- .../file_generation_mode/tachyon_config.yaml | 8 + examples/in_place_mode/.gitignore | 6 - examples/in_place_mode/analysis_options.yaml | 1 - .../data_class_plugin_options.yaml | 16 - .../lib/data_class/copy_with.dart | 34 -- .../data_class_with_super_class.dart | 107 ---- .../lib/data_class/default_data_class.dart | 56 -- .../from_json/camel/simple_usage.dart | 27 - .../from_json/default_value_usage.dart | 30 - .../data_class/from_json/json_key_usage.dart | 41 -- .../from_json/kebab/simple_usage.dart | 27 - .../from_json/null_field_usage.dart | 24 - .../from_json/pascal/simple_usage.dart | 27 - .../data_class/from_json/simple_usage.dart | 27 - .../from_json/snake/simple_usage.dart | 27 - .../lib/data_class/hash_and_equals.dart | 48 -- .../to_json/camel/simple_usage.dart | 27 - .../data_class/to_json/json_key_usage.dart | 32 - .../to_json/kebab/simple_usage.dart | 27 - .../to_json/pascal/simple_usage.dart | 27 - .../lib/data_class/to_json/simple_usage.dart | 58 -- .../to_json/snake/simple_usage.dart | 27 - .../lib/enums/enum_annotation.dart | 37 -- .../lib/enums/enum_constructor.dart | 14 - .../lib/enums/enum_to_string.dart | 27 - .../in_place_mode/lib/enums/from_json.dart | 33 -- examples/in_place_mode/lib/enums/to_json.dart | 29 - .../in_place_mode/lib/json_converter.dart | 136 ----- .../in_place_mode/lib/unions/data_class.dart | 196 ------ .../lib/unions/default_value.dart | 70 --- .../in_place_mode/lib/unions/from_json.dart | 115 ---- .../lib/unions/shared_fields.dart | 183 ------ .../in_place_mode/lib/unions/to_json.dart | 98 --- examples/in_place_mode/pubspec.lock | 404 ------------- examples/in_place_mode/pubspec.yaml | 16 - package/.gitignore | 1 + package/CHANGELOG.md | 31 + package/README.md | 289 ++------- package/bin/data_class_plugin.dart | 49 -- package/data_class_plugin_options.yaml | 10 - .../lib/{plugin.dart => analyzer_plugin.dart} | 0 .../src/analyzer_plugin/analyzer_plugin.dart | 9 +- .../analyzer_plugin_starter.dart | 2 +- .../web_socket_plugin_server.dart | 2 +- package/lib/src/annotations/union.dart | 31 + package/lib/src/backend/code_generator.dart | 515 +++------------- .../src/backend/core/custom_dart_object.dart | 66 --- .../src/backend/core/custom_dart_type.dart | 73 --- .../src/backend/core/declaration_finder.dart | 194 ------ .../src/backend/core/declaration_info.dart | 22 - .../core/find_package_path_by_import.dart | 95 --- .../core/find_package_path_by_import.gen.dart | 50 -- .../backend/core/generators/constructor.dart | 40 +- .../backend/core/generators/copy_with.dart | 73 ++- .../backend/core/generators/from_json.dart | 67 ++- .../core/generators/hash_and_equals.dart | 15 +- .../src/backend/core/generators/to_json.dart | 48 +- .../backend/core/generators/to_string.dart | 11 +- .../core/generators/union_from_json.dart | 6 +- .../backend/core/generators/union_when.dart | 5 +- .../core/packages_dependency_graph.dart | 22 - .../backend/core/parse_file_extension.dart | 62 -- .../src/backend/core/parsed_file_data.dart | 20 - .../backend/core/parsed_file_data.gen.dart | 56 -- .../backend/core/parsed_files_registry.dart | 24 - package/lib/src/backend/core/typedefs.dart | 3 - package/lib/src/cli.dart | 1 - package/lib/src/cli/cli.dart | 29 - .../commands/analyze/analyze_argument.dart | 48 -- .../cli/commands/analyze/analyze_command.dart | 120 ---- package/lib/src/cli/commands/arguments.dart | 67 --- .../lib/src/cli/commands/base_command.dart | 26 - .../cli/commands/generate/build_command.dart | 36 -- .../commands/generate/generate_command.dart | 36 -- .../cli/commands/generate/watch_command.dart | 46 -- .../commands/install/install_argument.dart | 39 -- .../cli/commands/install/install_command.dart | 57 -- package/lib/src/cli/commands/mixins.dart | 31 - .../cli/commands/resync/resync_argument.dart | 23 - .../cli/commands/resync/resync_command.dart | 183 ------ package/lib/src/common/code_writer.dart | 39 -- .../core/generators => common}/generator.dart | 0 .../src/contributors/available_assists.dart | 4 +- .../class/data_class_contributor.dart | 57 +- .../class/union_assist_contributor.dart | 29 +- .../common/to_string_assist_contributor.dart | 114 ---- .../enum_annotation_assist_contributor.dart | 3 +- .../contributors/generators/copy_with.dart | 4 +- .../contributors/generators/from_json.dart | 6 +- .../generators/hash_and_equals.dart | 4 +- .../src/contributors/generators/to_json.dart | 6 +- .../contributors/generators/to_string.dart | 4 +- .../file_generation_data_class_delegate.dart | 29 +- .../file_generation_union_delegate.dart | 33 +- .../in_place_data_class_delegate.dart | 240 -------- .../in_place/in_place_union_delegate.dart | 561 ------------------ package/lib/src/exceptions.gen.dart | 4 +- .../src/extensions/annotation_extensions.dart | 19 +- .../lib/src/extensions/core_extensions.dart | 10 +- .../src/options/data_class_options.gen.dart | 4 +- .../options/data_class_plugin_options.dart | 61 +- .../data_class_plugin_options.gen.dart | 27 +- package/lib/src/options/enum_options.gen.dart | 4 +- package/lib/src/options/extensions.dart | 4 + package/lib/src/options/json_options.gen.dart | 4 +- .../lib/src/options/options_config.gen.dart | 4 +- package/lib/src/options/union_options.dart | 3 + .../lib/src/options/union_options.gen.dart | 4 +- package/lib/src/tools/logger/ansi.dart | 166 ------ .../lib/src/tools/logger/console_logger.dart | 96 --- package/lib/src/tools/logger/file_logger.dart | 110 ---- package/lib/src/tools/logger/logger.dart | 61 -- .../lib/src/tools/logger/no_op_logger.dart | 38 -- .../lib/src/tools/logger/plugin_logger.dart | 249 -------- package/lib/src/typedefs.dart | 3 - .../src/visitors/class_collector_visitor.dart | 23 - package/lib/src/visitors/class_visitor.dart | 33 -- package/lib/src/visitors/visitors.dart | 4 +- package/pubspec.lock | 397 ------------- package/pubspec.yaml | 26 +- package/tachyon_config.yaml | 10 + package/tachyon_plugin_config.yaml | 9 + .../data_class_assist_contributor_test.dart | 4 +- .../data_class/test_files/in_1.dart | 10 - .../in_10_from_json_snake_case.dart | 15 - .../test_files/in_10_to_json_snake_case.dart | 15 - .../data_class/test_files/in_11_super.dart | 15 - .../test_files/in_12_no_fields_const.dart | 17 - .../test_files/in_13_no_fields.dart | 16 - .../data_class/test_files/in_1_simple.dart | 8 + .../data_class/test_files/in_2.dart | 12 - .../test_files/in_2_const_constructor.dart | 16 + .../data_class/test_files/in_3.dart | 12 - .../data_class/test_files/in_3_from_json.dart | 10 + .../data_class/test_files/in_4.dart | 12 - .../data_class/test_files/in_4_to_json.dart | 10 + .../data_class/test_files/in_5.dart | 12 - .../test_files/in_5_default_value.dart | 11 + .../in_6_convert_final_fields_to_getters.dart | 10 + .../test_files/in_7_from_json_camel_case.dart | 15 - .../test_files/in_7_inheritance.dart | 19 + .../test_files/in_7_to_json_camel_case.dart | 15 - .../test_files/in_8_from_json_kebab_case.dart | 15 - .../test_files/in_8_to_json_kebab_case.dart | 15 - .../in_9_from_json_pascal_case.dart | 15 - .../test_files/in_9_to_json_pascal_case.dart | 15 - .../data_class/test_files/out_1.dart | 22 - .../out_10_from_json_snake_case.dart | 31 - .../test_files/out_10_to_json_snake_case.dart | 31 - .../data_class/test_files/out_11_super.dart | 53 -- .../test_files/out_12_no_fields_const.dart | 22 - .../test_files/out_13_no_fields.dart | 21 - .../data_class/test_files/out_1_simple.dart | 16 + .../data_class/test_files/out_2.dart | 16 - .../test_files/out_2_const_constructor.dart | 16 + .../data_class/test_files/out_3.dart | 26 - .../test_files/out_3_from_json.dart | 21 + .../data_class/test_files/out_4.dart | 16 - .../data_class/test_files/out_4_to_json.dart | 21 + .../data_class/test_files/out_5.dart | 16 - .../test_files/out_5_default_value.dart | 20 + ...out_6_convert_final_fields_to_getters.dart | 20 + .../out_7_from_json_camel_case.dart | 31 - .../test_files/out_7_inheritance.dart | 33 ++ .../test_files/out_7_to_json_camel_case.dart | 31 - .../out_8_from_json_kebab_case.dart | 31 - .../test_files/out_8_to_json_kebab_case.dart | 31 - .../out_9_from_json_pascal_case.dart | 31 - .../test_files/out_9_to_json_pascal_case.dart | 31 - .../json_key/json_key_annotation_test.dart | 39 -- .../json_key/test_files/in_from_json.dart | 25 - .../json_key/test_files/in_ignore.dart | 20 - .../json_key/test_files/in_name.dart | 17 - .../test_files/in_name_convention_camel.dart | 17 - .../test_files/in_name_convention_kebab.dart | 17 - .../test_files/in_name_convention_pascal.dart | 17 - .../test_files/in_name_convention_snake.dart | 17 - .../json_key/test_files/in_to_json.dart | 24 - .../json_key/test_files/out_from_json.dart | 31 - .../json_key/test_files/out_ignore.dart | 33 -- .../json_key/test_files/out_name.dart | 30 - .../test_files/out_name_convention_camel.dart | 30 - .../test_files/out_name_convention_kebab.dart | 30 - .../out_name_convention_pascal.dart | 30 - .../test_files/out_name_convention_snake.dart | 30 - .../json_key/test_files/out_to_json.dart | 30 - .../union/test_files/in_1_simple.dart | 7 + .../test_files/in_2_positional_parameter.dart | 7 + .../test_files/in_3_named_parameter.dart | 7 + .../union/test_files/in_4_from_json.dart | 9 + .../union/test_files/in_5_to_json.dart | 9 + .../union/test_files/in_data_class.dart | 18 - .../union/test_files/in_from_json.dart | 20 - .../union/test_files/in_from_options.dart | 10 - .../union/test_files/in_shared_fields.dart | 26 - .../union/test_files/in_to_json.dart | 21 - .../test_files/in_union_field_value.dart | 28 - .../union/test_files/out_1_simple.dart | 9 + .../out_2_positional_parameter.dart | 9 + .../test_files/out_3_named_parameter.dart | 9 + .../union/test_files/out_4_from_json.dart | 14 + .../union/test_files/out_5_to_json.dart | 14 + .../union/test_files/out_data_class.dart | 166 ------ .../union/test_files/out_from_json.dart | 105 ---- .../union/test_files/out_from_options.dart | 92 --- .../union/test_files/out_shared_fields.dart | 181 ------ .../union/test_files/out_to_json.dart | 109 ---- .../test_files/out_union_field_value.dart | 56 -- .../union/union_annotation_test.dart | 7 +- .../assists/contributor_assists_test.dart | 7 +- .../class/to_string/test_files/in_1.dart | 15 - .../class/to_string/test_files/in_2.dart | 13 - .../class/to_string/test_files/out_1.dart | 24 - .../class/to_string/test_files/out_2.dart | 21 - .../to_string_assist_contributor_test.dart | 25 - .../enum/to_string/test_files/in_1.dart | 12 - .../enum/to_string/test_files/in_2.dart | 15 - .../enum/to_string/test_files/in_3.dart | 7 - .../enum/to_string/test_files/out_1.dart | 21 - .../enum/to_string/test_files/out_2.dart | 23 - .../enum/to_string/test_files/out_3.dart | 16 - .../to_string/to_string_contributor_test.dart | 25 - package/test/contributors/utils/utils.dart | 15 +- .../test/options/data_class_options_test.dart | 4 +- .../data_class_plugin_options_test.dart | 16 +- package/test/options/enum_options_test.dart | 4 +- package/test/options/json_options_test.dart | 4 +- package/test/options/union_options_test.dart | 4 +- package/tools/analyzer_plugin/bin/plugin.dart | 2 +- package/tools/analyzer_plugin/pubspec.lock | 196 ------ package/tools/analyzer_plugin/pubspec.yaml | 4 +- 276 files changed, 992 insertions(+), 9229 deletions(-) delete mode 100644 assets/screenshots/007.png delete mode 100644 assets/screenshots/009.png delete mode 100644 assets/screenshots/010.png delete mode 100644 assets/screenshots/011.png create mode 100644 assets/screenshots/dataclass.png create mode 100644 assets/screenshots/enum.png create mode 100644 assets/screenshots/union.png create mode 100644 examples/file_generation_mode/tachyon_config.yaml delete mode 100644 examples/in_place_mode/.gitignore delete mode 100644 examples/in_place_mode/analysis_options.yaml delete mode 100644 examples/in_place_mode/data_class_plugin_options.yaml delete mode 100644 examples/in_place_mode/lib/data_class/copy_with.dart delete mode 100644 examples/in_place_mode/lib/data_class/data_class_with_super_class.dart delete mode 100644 examples/in_place_mode/lib/data_class/default_data_class.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/camel/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/default_value_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/json_key_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/kebab/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/null_field_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/pascal/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/from_json/snake/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/hash_and_equals.dart delete mode 100644 examples/in_place_mode/lib/data_class/to_json/camel/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/to_json/json_key_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/to_json/kebab/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/to_json/pascal/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/to_json/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/data_class/to_json/snake/simple_usage.dart delete mode 100644 examples/in_place_mode/lib/enums/enum_annotation.dart delete mode 100644 examples/in_place_mode/lib/enums/enum_constructor.dart delete mode 100644 examples/in_place_mode/lib/enums/enum_to_string.dart delete mode 100644 examples/in_place_mode/lib/enums/from_json.dart delete mode 100644 examples/in_place_mode/lib/enums/to_json.dart delete mode 100644 examples/in_place_mode/lib/json_converter.dart delete mode 100644 examples/in_place_mode/lib/unions/data_class.dart delete mode 100644 examples/in_place_mode/lib/unions/default_value.dart delete mode 100644 examples/in_place_mode/lib/unions/from_json.dart delete mode 100644 examples/in_place_mode/lib/unions/shared_fields.dart delete mode 100644 examples/in_place_mode/lib/unions/to_json.dart delete mode 100644 examples/in_place_mode/pubspec.lock delete mode 100644 examples/in_place_mode/pubspec.yaml create mode 100644 package/.gitignore delete mode 100644 package/bin/data_class_plugin.dart rename package/lib/{plugin.dart => analyzer_plugin.dart} (100%) delete mode 100644 package/lib/src/backend/core/custom_dart_object.dart delete mode 100644 package/lib/src/backend/core/custom_dart_type.dart delete mode 100644 package/lib/src/backend/core/declaration_finder.dart delete mode 100644 package/lib/src/backend/core/declaration_info.dart delete mode 100644 package/lib/src/backend/core/find_package_path_by_import.dart delete mode 100644 package/lib/src/backend/core/find_package_path_by_import.gen.dart delete mode 100644 package/lib/src/backend/core/packages_dependency_graph.dart delete mode 100644 package/lib/src/backend/core/parse_file_extension.dart delete mode 100644 package/lib/src/backend/core/parsed_file_data.dart delete mode 100644 package/lib/src/backend/core/parsed_file_data.gen.dart delete mode 100644 package/lib/src/backend/core/parsed_files_registry.dart delete mode 100644 package/lib/src/backend/core/typedefs.dart delete mode 100644 package/lib/src/cli.dart delete mode 100644 package/lib/src/cli/cli.dart delete mode 100644 package/lib/src/cli/commands/analyze/analyze_argument.dart delete mode 100644 package/lib/src/cli/commands/analyze/analyze_command.dart delete mode 100644 package/lib/src/cli/commands/arguments.dart delete mode 100644 package/lib/src/cli/commands/base_command.dart delete mode 100644 package/lib/src/cli/commands/generate/build_command.dart delete mode 100644 package/lib/src/cli/commands/generate/generate_command.dart delete mode 100644 package/lib/src/cli/commands/generate/watch_command.dart delete mode 100644 package/lib/src/cli/commands/install/install_argument.dart delete mode 100644 package/lib/src/cli/commands/install/install_command.dart delete mode 100644 package/lib/src/cli/commands/mixins.dart delete mode 100644 package/lib/src/cli/commands/resync/resync_argument.dart delete mode 100644 package/lib/src/cli/commands/resync/resync_command.dart delete mode 100644 package/lib/src/common/code_writer.dart rename package/lib/src/{backend/core/generators => common}/generator.dart (100%) delete mode 100644 package/lib/src/contributors/common/to_string_assist_contributor.dart delete mode 100644 package/lib/src/contributors_delegates/in_place/in_place_data_class_delegate.dart delete mode 100644 package/lib/src/contributors_delegates/in_place/in_place_union_delegate.dart delete mode 100644 package/lib/src/tools/logger/ansi.dart delete mode 100644 package/lib/src/tools/logger/console_logger.dart delete mode 100644 package/lib/src/tools/logger/file_logger.dart delete mode 100644 package/lib/src/tools/logger/logger.dart delete mode 100644 package/lib/src/tools/logger/no_op_logger.dart delete mode 100644 package/lib/src/tools/logger/plugin_logger.dart delete mode 100644 package/lib/src/visitors/class_collector_visitor.dart delete mode 100644 package/lib/src/visitors/class_visitor.dart delete mode 100644 package/pubspec.lock create mode 100644 package/tachyon_config.yaml create mode 100644 package/tachyon_plugin_config.yaml delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_1.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_10_from_json_snake_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_10_to_json_snake_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_11_super.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_12_no_fields_const.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_13_no_fields.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_1_simple.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_2.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_2_const_constructor.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_3.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_3_from_json.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_4.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_4_to_json.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_5.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_5_default_value.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_6_convert_final_fields_to_getters.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_7_from_json_camel_case.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/in_7_inheritance.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_7_to_json_camel_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_8_from_json_kebab_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_8_to_json_kebab_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_9_from_json_pascal_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/in_9_to_json_pascal_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_1.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_10_from_json_snake_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_10_to_json_snake_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_11_super.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_12_no_fields_const.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_13_no_fields.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_1_simple.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_2.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_2_const_constructor.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_3.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_3_from_json.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_4.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_4_to_json.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_5.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_5_default_value.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_6_convert_final_fields_to_getters.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_7_from_json_camel_case.dart create mode 100644 package/test/contributors/annotations/data_class/test_files/out_7_inheritance.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_7_to_json_camel_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_8_from_json_kebab_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_8_to_json_kebab_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_9_from_json_pascal_case.dart delete mode 100644 package/test/contributors/annotations/data_class/test_files/out_9_to_json_pascal_case.dart delete mode 100644 package/test/contributors/annotations/json_key/json_key_annotation_test.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_from_json.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_ignore.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_name.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_name_convention_camel.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_name_convention_kebab.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_name_convention_pascal.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_name_convention_snake.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/in_to_json.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_from_json.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_ignore.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_name.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_name_convention_camel.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_name_convention_kebab.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_name_convention_pascal.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_name_convention_snake.dart delete mode 100644 package/test/contributors/annotations/json_key/test_files/out_to_json.dart create mode 100644 package/test/contributors/annotations/union/test_files/in_1_simple.dart create mode 100644 package/test/contributors/annotations/union/test_files/in_2_positional_parameter.dart create mode 100644 package/test/contributors/annotations/union/test_files/in_3_named_parameter.dart create mode 100644 package/test/contributors/annotations/union/test_files/in_4_from_json.dart create mode 100644 package/test/contributors/annotations/union/test_files/in_5_to_json.dart delete mode 100644 package/test/contributors/annotations/union/test_files/in_data_class.dart delete mode 100644 package/test/contributors/annotations/union/test_files/in_from_json.dart delete mode 100644 package/test/contributors/annotations/union/test_files/in_from_options.dart delete mode 100644 package/test/contributors/annotations/union/test_files/in_shared_fields.dart delete mode 100644 package/test/contributors/annotations/union/test_files/in_to_json.dart delete mode 100644 package/test/contributors/annotations/union/test_files/in_union_field_value.dart create mode 100644 package/test/contributors/annotations/union/test_files/out_1_simple.dart create mode 100644 package/test/contributors/annotations/union/test_files/out_2_positional_parameter.dart create mode 100644 package/test/contributors/annotations/union/test_files/out_3_named_parameter.dart create mode 100644 package/test/contributors/annotations/union/test_files/out_4_from_json.dart create mode 100644 package/test/contributors/annotations/union/test_files/out_5_to_json.dart delete mode 100644 package/test/contributors/annotations/union/test_files/out_data_class.dart delete mode 100644 package/test/contributors/annotations/union/test_files/out_from_json.dart delete mode 100644 package/test/contributors/annotations/union/test_files/out_from_options.dart delete mode 100644 package/test/contributors/annotations/union/test_files/out_shared_fields.dart delete mode 100644 package/test/contributors/annotations/union/test_files/out_to_json.dart delete mode 100644 package/test/contributors/annotations/union/test_files/out_union_field_value.dart delete mode 100644 package/test/contributors/class/to_string/test_files/in_1.dart delete mode 100644 package/test/contributors/class/to_string/test_files/in_2.dart delete mode 100644 package/test/contributors/class/to_string/test_files/out_1.dart delete mode 100644 package/test/contributors/class/to_string/test_files/out_2.dart delete mode 100644 package/test/contributors/class/to_string/to_string_assist_contributor_test.dart delete mode 100644 package/test/contributors/enum/to_string/test_files/in_1.dart delete mode 100644 package/test/contributors/enum/to_string/test_files/in_2.dart delete mode 100644 package/test/contributors/enum/to_string/test_files/in_3.dart delete mode 100644 package/test/contributors/enum/to_string/test_files/out_1.dart delete mode 100644 package/test/contributors/enum/to_string/test_files/out_2.dart delete mode 100644 package/test/contributors/enum/to_string/test_files/out_3.dart delete mode 100644 package/test/contributors/enum/to_string/to_string_contributor_test.dart delete mode 100644 package/tools/analyzer_plugin/pubspec.lock diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a0f368b..b679f6e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: - name: 🎯 Setup Dart uses: dart-lang/setup-dart@v1.4 with: - sdk: "2.19.2" + sdk: "3.0.3" - name: 📦 Install Dependencies run: dart pub get diff --git a/.github/workflows/validate_plugin.yml b/.github/workflows/validate_plugin.yml index d5b38ee..9b1c148 100644 --- a/.github/workflows/validate_plugin.yml +++ b/.github/workflows/validate_plugin.yml @@ -14,7 +14,7 @@ on: dart_sdk: required: false type: string - default: "2.19.2" + default: "3.0.3" runs_on: required: false type: string diff --git a/assets/screenshots/007.png b/assets/screenshots/007.png deleted file mode 100644 index 5fa41c74b6b92197d9753e5de58cd64b7e96a807..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5346 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 diff --git a/assets/screenshots/010.png b/assets/screenshots/010.png deleted file mode 100644 index 48321755c5bd2fe4fe1c893f4dc467e6c967b9b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21246 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 e 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 Tk{L`E00000NkvXXu0mjfNFUPa literal 0 HcmV?d00001 diff --git a/assets/screenshots/enum.png b/assets/screenshots/enum.png new file mode 100644 index 0000000000000000000000000000000000000000..75ec0806afa23d6cb8963626017b04e77dd597fd GIT binary patch literal 28188 zcmZ^K1yEek5+ww8cXxMpcMBfegS&emxDD>^7M$P^+&uw;ySqF4^8aq_Zq;tVR1I&6 zJ6F2Re3p}tAa!za z{Az7y0R~2!;GZBQ+b>EuXrvxZjs?RIK`U9Vj4dfe)C@0Gj%pLCMWo357EFyK7ZqK! zsq1uUR)4&?U0wCPiWD~BTWdQnUAt`Lhb=slsUYw9aEC9b!}Hr`CiY1i0tn7EZjAc! zbott-vszeV)GpkR#J2#uW;Xe#L8no4DUWP1%` z-qDR(jEzG=PYB=f{4Fw0IAKux$x}(iLW0@hY5Sx@v~n;J;Fdu?k1rS7G_X<{f?A(G%$gIOW}0c+zh77yK7xoZuG!}K)l0^j zSaj+R^7L%FzrVjED3l5=OnA+3I@hZ@$Uuh zRU+a6JcMzRQ<8!?fFiB4JZC9V;Nl9J3MOcXvyTqjh# zU}o+UQL^}WEmLDt2^72qwyrcO90laay7TrxJ;sIoxUXC))p%k+;79`6R6GU^s*CV+ z5>2YxIp0IB@09Px&AMy1Ok#5CnItJHtn#Od@=rmcq=*rsq^QvUoVeD;=D=pQVAbbq$E3UN@cr`lSo&D zB-4lS)zOHe)~>dH%Po;GXZkEngzLCjfc8tI#R_zJAni_=*$E((O2T32lB z%LflVC?Xy*AYhW=lvXE}T2#hVgZYO6SLfRxiS}sL~L7;4ix{s#G{taU+Qx`d140m`Vwh6V*bXV3=(0( zDpMFjsd5y3suwVpkP?V22&jIZMHKF`rGA&^D+qu$H-jDAr<^RR=t|5PtcpNZuow(B ziaQEv7DMyv+>s)eK#xRLF?rZhNly)6GwGc@=j?tbW4(pfbL+RWl6eTV0h9w+q( zPa>I=ldRIZj7}M}`Xek;h66ce(2YAR0X^88)xMMdz z|F^Y~gNF7snb;t&@EhEXIQy==HSWW9UL&sCs4PZQzaokBTGK;3QUwypZ?)N@^}S65 zF!cgM2j1{&JerT}#jk*5zwOVg?c9<$|Hl{aI2mNc`F@pQV6jqq<`Kf|TdovCf zsw_DpKLWa&KvDHsX+n>z|7nGa-z6X)=`R!HDy(?eE?BZ6k+o*OHkcAO`4%fhOi+@s z&%d=b){fdjsOk1(c`k@db#`JY=C-ECgA=llKyNZ9h|xtz?$)*MQpB=uyxwXnvp%KEh72aG=Av7JAk8NNOS&E zlyz#P$)tTFhgMbn0_@4Tca@bZ)wmg@AV5B`@3s5{|JV6rDtsm%5huy2?0A7aqRz`v zH66OA9_b^sAS##<37uySPf#=mMFgw{SyEp$4bQAYLzFHi;M-`hkiqq2kfD&DdXKnB z1Hi=!OM$m7{Sc#3@Z@w8D!;pdcrdb*k%QS+oW6M>2{krAdZ{NTDoToxNK-g#1ER+CSNsRE8m&Zm(=PnMpJAuNNmX(e#b*r#OGAtf&eEem)MUJ`1Oef+p*nQtf z+jvIi@*eDml%`bc@I{i);wX)Su8p&;U5%bMk)hT`7w{g{xzRw3j*+BJnqPH0J&B2l z`Z~fb>FYa=Cn6FmE+&0X32m=+d}0H3cy^AT);ak`or$jxAJ`82<~a-jhw_;`L6+9x zyl9?NR{MigB=CcD79R__%+~7W80qQ!cHE`tODX}>uc2#X2VdK~lM39jtpkKaxj#@d z_Qbngebl)dYCE}T0)QQSpX^$_x(@)mU+`@7OUw;H<$}q2;eA~RB|gx6?~npRTsqwq z+-HZ@3-BObgZSBlnHf&PQ=VhY6ReMnbV?4NPMchWYmNTq9jk5V{T`$;VP7Vq* z?A`mDFkq!&S97|lT@}TqW5C=jeb%3s_LYrEOu{-kfk`vxb@vtSbvFm1TIl!jl&y&* zXU}x*SX`V|K)d6L+@CI^h}_x?u6^ILUJ!Q54ba|%i_m~3SJ$_Mqw_nq{P%!;+< zsAYqyOC(sK8t~E1N9FA@!#Ky!xZKeR3v&jT-48O=)M@w8dEANF77s-V8By~`#XsC= zLP-RtL{(O-t!-6R**4uwdBZ%>Fspl~r}Kuw_z68a9(MdIlAB`e+|Ycg7r<>Q8Dvmm zHR#pm8)4y)`j0}U;<)8ehz4x%W;?DlD-vY$ODYl?`ir_wXIP2k=rFEsP>e^u7B!b- zL^YtFdccT@^(tn$6F2|SOipW$o1Ds0lq}9wG76AZ@x&48ACfJC6Dz&MJJV6l`z|ej zPLL_!Sgdlo{4;WWJ=ZZ0yyA>~-jQfKaRL^(8TaWhKPbur1M7?$Y&iy7>)dfjg>0wK zjp%OeEBvuOj@q)R8;Yah^E;)T2Mq~MOFTZ>FQJ>nI)QA#oPFjh-$m&b8A>?fr+{K zUi)&OEy9^SQ~7Tjmzy$nX+-#G{Ks~VgLd2nvtjvKFSE;Y z6Ek%_dG1b^D@Q@;FlU0-qbBcO-qh;boQhGiPKGYHpa3;_*9)+evp2y<6Sik#ES%C4 z+VT@TEC@akKFkzQ%to~{)3N$UiCxEqAoEy+6G8k&pxPM1qVo1xR@vOF$Vh3FhvAaG zgnb%b`25k7t8VA`ClZFKZKpn=3*ukrPIElQJN4u2Be8J684gTkGJ7nz6=;pb*@_yj z=?v@n;(OVbC3m4rS=zit{K?C~l()@GA?Y;ywg!&ElreHQZz{8QRa+^cf$K|qc7m4$ zok>G!!Ik}}PmuW%n5VJG5T8EU>lvDKu}n)Eo2sKVT;?PuGf)n%p~sSsiO$laxS zq)16|z*B;Pz}q|chm%{RPuRD8JsmA)Y^WIZW!86(h}qCYKETGtkyQmwb7-;PfinR7 zQMKZAW;jNW_S2_NaImnDzf9|A))#`!MyB3_4RDqG9crlr^~1S2F~^3=;wr1g*4R*+ zmq88vR2%QOu)o4#5Kn(xY!y&hPssje72%43GYQbYUG=atEJqK8qBT&7BVJ6ha2gTI znvG(1l2mtBG2p=w?8rcvcbmvW?VGa`LZA+F9ToXGzkKl4o^u`~_E2|dtWM&1UQ^a> zYnQV6=b~YsyQ7~fGC#g85aCL_uBU#HX-H$y`?izGL%O?baN zwuV7`*U}ci$GyCD!W3qnCg-Dy-Njr))n>0QrAZsNw&kijPtuej3TwT{nv9~ROujwU zPnI_l4VL_*_P50qrIjN<3uz4kll#7|zA)zqP8YlEB%P38A}+JWnW1RKZl}kW;OSyr z8oMO)=Ap{9jb3HiHLFsEzGqI00`LGI-IKv5B-wUosS@_P=Z$&&&I|*`SNt;nh-`*) zi8TJT6TxTQ%E#?U+sIM9kU%fOUe!^`$u8)g8LOY&P7ks~HNF{PeeT4=_$w#FcRsJL z5U_~wLo=(p9-}fSMsc0~*1Yz2y6T!@(FN8TPV-eJYIdLCFcK>&X-j?#e#1y-H@lY= z;B%nhzZqYiS`v(ZsxYbUwC6`q>j%ee5TLa=b`>h|lUCjtQ8ywZ@wYjXPTK>)x_A=` zv(uTp!|T52tBm2sMgdNA0C?K!@GW91zFPbkN4mKu|L2h&KC=C(cd^1?{{&=_*qtVs zKzs%Zc5F#Wj4EW@2iKXQ5+I0KFTKDC#g^RS(kips!BFWvm3(G2Wyp_HV_< zuTML3h{x>{h)aaUGLSO@#zl1|y9WLpqvClM5x^#Ty+$$GdBD6J`+5ZiVh}Jaw{4{M z_2ZPVQ7J3vN`m#;K(Smnb^WwC#mld^{I-{L8}dkJ#igs0j2$QEluX?}%cw=DA zNJ-U(bc=U9O;7pdv2M2rS87uPn7P_wj$G`eC&7=6z~h|jzYCShse95_7bi5ctF~Kx zoNKD{YuscxB+9Zy{Wd1=&wqA&RGtwv`}?EwfEYwd%O05@G0WfZ{Y@yn14&XbyEi5) z?-#eRX?|I3qRNNdXAN}q8h^Qi}wnYF9&8L_hFKj63#;=`U z0CrI-QN*1ZxQeWrbA#-Y>OlcX2}?_m#prZu8OgN%j9o$oZcWWTnqi}dJ|^)T*6cY% zXCYxnf-#^!rUfl!(M|@GI&Db_<9m?M)>dqsJFl5AbBl}7KsuaMHrcnjad8caf@Rjy zf!H#-OV7YSL!zEng_4>^)W;nrdW?4?dfYL&dZUacJ&yYKnY47!7TET-oilOJ6P^dm ztLdH?ztVTc$w>1jN+I=a1Fg1-;l3Y^=S8LS6LZ2#2oae3++VZl86(D$g|dC9c0^^0CjP z0SC^QS1hwt!WFoEdtz!PQ%FQ_%`%r)UcECB9l^Y+za)3-3v1^AxqN1gM}VkTN{nvcF<>c+2b;Z3SBejQ4l&^9>8Lm}ajMm~9+X$sXs|dzn^CLv(|EvGpZQ z(62$J#%*t76L_BP?zFQ%IS1xMulEHTPV1{}t5-WD>V}4FrDmXs%2gnj@t4UM-mFsN zczA_sYH3mZQm4+@+Q=0FU&Du^mGzcg`+8C~xLuoEbe-U=)SbHyPB1uma4yXacXgFM z`L(igh`Nv|WpqYL5=q5Chyxb~YmX$Lyd_l)i^u4W3_qU+aO^nxVZ}*q*)8wC- zk2}lk&x{BA9@#E!gk6Ty>wW%9!>zON{SKCI?I2KAX?x|W(1#dnfFFefZjk8ZnrOKW zEaWE>QOHk0tfTF2L0^R`AHCjopE?3&zk%V@fTzN+5QGZjgR z1hvzT7Z}Ts&{~X?wkO@TSf>AROziQ;Bai|M742|*KX20FP7DGlk~aT(!cd{Rq`t>I zR-_ev?)bT}^!T7>UAyGlC&A+Li1FG)!Qu4KeS`aFW&LHrs6m<_xK>_C!eCO>GRKF) z`VfgPsWd-2!n7YJFV5PBN7P1_T6LD~5wUiLX{kA-W=cJel-F{d9K^*N9)&XV#YliY zr&fM))f>Uurn;=S{IbJL6k8ebpcK!U(1GoG3p@>5QXy}N_{MzJa++fA^JgiI!9&VvGub zqrJm`Oo3?0y#xWe&$%~H4W`}sc}P&5j0+MxKTsb%^;_TxzI#LASRTtF-kAlOv7iKe zjxq5XJiDSqVi}FuJgREY(ODV*%8XncqtS*{+9n&QmL5&n$b#uA*G^iA;k6rT)Uvz& zub!VxS+9qiEeK!77-wy%WnAZPdC7zQDlYIh+mtjN=){2uf}5jzxi9;nzd}5XuG^p9 zH0%UoeW0eDTU^n6{Q4}YOUm#5ey5mzC*=3NkM*HRt^P{nU(WySyX`x?=xH$m$XYb` zu431~TO>1`v)Bcy^xg;g#|zFKR9>9h(ym_vOGjG%h`Akv^fA0}$>UDX4lX|7!#zcc z{H)XwTb9!8J>ie>c!J9W@U zXuoY1EBD5t)Ry&xxU?x^m6`VlUt z^y+Y5@?(Ew^|)0fN=YAqY($$1OcZnZU3bATh@yp;sWkq~E{t_M=MDu9nUdmIN?$Hn z;OQr$fwyWk347>3gA7u|#LEw;)fukufZBJgz2AO9cIJB1ba9xgU^;fAY^O8;kr`FNT3@(52}6 z7h!8jDxdq1gp!%6=*)_vL(jkfTSp2Ol-jx+{8}=W^>yMeC@IPCMo2}ii7xJH4mFNlkZ53~WSn?wDQE+49F=rc z7YZwtZtu`19-f&&t+37jQjtR|N1?svBOW|DI{E?a5@{SXDNpSKPYUSkrDb+vJ-s0& zjva4fRd^uCjD%em=?x(7jCfs%_~OIfyF=*#`z+{DH`{SjZFf;tFg~H_?Nc)nSyd9)0ER$JO5RSU=2^YEoA$cvXfbnL_hF`OGCD-bR1&6y&#o7*R=s(igI5x|1M zFav7*4mMtnWi=H_08@|gCAe0lg+-d5UHdcmt?eWIDq%+spP1vqq)oiaz4#0XF&z#O z|B8N37~Y&64*}cg{BPuLje~~IA!$iCGO;_Z3uM`vn7l4Oc#v2>d+5|wLF{RDOz&vV z8O`IiwqUfn6gjxTH!YtkUWZrDd>>-f2wAqe_%sJyRR1$-mEH9!d!|&<$ zo!cMKp|^wYQ(3xzOegKIwU<9WT7`^DHdgbxEPgKi&t9?n)9Y13vyrbi4R3NIIqW%P zS+QNd9_*av6y)+3ZC$0ihYIuAyrJNHnsHRtOLLZ2=g{OPYio@aXQv0(I3AmB;^Gku zn|~bervzrw0DQTd(SB#|tj6T`8-jYPyO!V;nGJFat~HNNyqp2C3{XJ}FWpHxa>NPE z<)Y&%Cf8;%olPzcx5ZlRupeF66GIT}UeOTnoOL%_ucDMmzvGx*# zhB0u@*NF2S0hR=_dh3mGG(?sz&W{X?+ zir|!nntA?e-{PT_Z%Y?noH`-7i1NmOp)~t%Wx4*U!8$OnTE4lS~ zv(w@S{NIg3A1S>>i~a5g1F@z&gZKe|97;ChM%M=cn8W5){PSgrAFm#hWW}p`&N~wdyF2 zgBEIG{B5chuQ0V#8i1N53qGUf#fNB6?`#Hjoom;vCp*{GfsKF5SbCHMU@jS@PmRdB zf3@o%fa+1!A5mCXSR|0x~uVNCw^%Jv_)Ipa`OmaEE|YKFj3XnrA2}}H_v(iG8!hr&;IX! z|4Z{p!&v{D+W&9Jfr1fgu$NC8H!@nX7PMF&^gL_YF2K zZqBHG7Yk&3c2R0G{^7(=M7&{z~Jc9N0SE|}v|Fb{qFzq9}$ zYX%0JZsbX05i@~2VV0H?-#YzoG_HFJmzn``?7XMe&pAzx`O-@*$gph~4P4M|R+60@ zLUpA0w|l0yg94Xr6yiDOaFUcF+`~bUfaSG^7=>zYw_@!4=h?5@K`8R&$E@DTcQ=u3 zjG(Mvu6r=vU0+XMYAU%BWQ)~~5rl;*AC=9Q83FfC`W7J>HX)6V;wLwo*<(!7 z{uzq>=-8-8Atww(k7{cK)7-K6`Sr?`H>U zXC1mTfx->$liU!a%wd&UQbvx<=en@5N|NGkCX_RwyZo|H-e@NAQ~zPbK03Xl6Hb4|CB$S zer9<4&O8}WV`3jip%%oI^HmE6FFlKJtZ}@t?L0-ukVWI=W=`?8m;SxI0DdL@yM?z; zZYz0`+V_Mgk0d?p*{`10K#pC32ENL{0@u-hRAA$wS{m2#z^S&jJ{>!6=Iy5gt=-)^ zUQ~T*%tT)iGm#(9_D8BtIHkC4G5^vPPs8At6G)Di?#zW-6ZW^2{^hw({g#IpR>f{> zJ#aDEq5z@|)Fn;?AdL12oVSSdPO0P{fe`AxL}=EH>8+PvCxn=Qss|@hax9zVjVLrP zEU}q|Jc&V8&kLhbJa;Rark3D=+etF6uBP-j-MX+40B*yr2zKfym?#kJWoe1d?7#fL zHr+-S4A8Flv#XRF*|s68V-5EX9t3Q@D0xsr|DdGgF&rEc1?db`JSIVwtXHc-WnF10 zI*_uNYar5La2(k=mQ@twvgX7AY!~$Ni;4}@<*b#Bn{^Ihf|MPeVW{uGW?m!ouI$0< z{G6gGm(6=qjh_bMfL_I~odOiCf9P75ztXL)T{RsyDp9qEt$U0V_SF#!16VpP+OHT$ zCVG;L@cfzShYRBd?(83DVQhaw^SH+(;#g_vGxE#L!JymqteMwC{Ac=p;#`!pl+2wW zNtR4g3l6?)Mag4C&Tr-W49hFpHv`mxgp&q4wpm)0zCS#8yJXbDYs&RqZCmaxxNhRU z;dfnv(6%aX{gq#lyRZ%|}|4B2SXz z)A0Ls_GZPY+ecAIE1-XxLTF;-i1Olbk>Ak)(Xl2bBf~InnFHeHbkj$Sm_KqGN3oI6 z-^)|x>$}kZ?+(-#6y}UKkpF%A_0)v_Be^BR%hM>yH)8h(qp5b!9YbJ;AZ1|5YX7$; z9q7km@6%^^B^aK|b0KdlGmh5HZXQ5K11(i0n9^7MwiZIAL>)LNQU0kP3=X{l^Xbbj ztO9q@G=Cmd&-*tqR~COJF3vQ&Qopy88r+Gx36ljX&jj}?1DRJVFu&wu=dPCZ5j0{n zNdAm7++AUpn4yFge(dPKjjtx7eH9%00Tv_Qe0y*lcVWZrzDt%AC#Gb9RxKqNG^qtV zB_b^+Q+z38U@tde22ZQc$pL9cjP&4dUMANh@wQ{54q6+2--R2>$#-H5oOQ|3 z`6`a#N@w(euhpm!_xZTUZ5++Uj6)R~a(_l$a(>R?+iF=N%xbeHE33wr7QXRYCc%I7(GF+H_0 zi=GSf_CKA)Ds36P%~vASQ>0$$RSqU8wK2xZ!hDFAM7jy?0pd+uc%t=ax+(R78c2cT zif}7{NGyH8L=Gq@fJhT=C_&Y$N(WpPfJ4==XO6M`T!`m9urYTb0Wg*;b(WIGpRf|6 zS|FFX`T5AGnBvyrkknK*c^)4+nZqbh_Ns%+S`Jaj33&#m1@w0%7Cah>OisZb-*V4s+=Qt5cU`4pcC0wvxOBkQ ziU;ZXkfy}0#!YGauj+iLE}5B{B5T{M*l$my%aP&mB~^|&Fpou#1Z=dCZ8xGDwLXC2 z?yPH0O?fd;K`OF{=(-asmVsvX6^B)e4AJ&nxY}O8&sJU>Qd?AxEGVx?Q^I1__Hk~H zOLhu;@9ILn*_1^z4-Q1F25Wz1SE_~v5%ZG3| zFFpIEH4ebb!ulN`vT>2^sXnKD6ZRzrZ}-YXaVXt9lc_`T@i9kP4-^@%ZBLx;dCX>J z5m-e7DAL)m5H(eg^!I@ILuuNigao0;_W%k_EDM@HH9qYfu&{{aUy24DJdLd!NGUmE zv?Ms*s3|14352@VAfaH2=B3Ee#w%)nl(x?`b{fZ~#@9Ik&^FtH?~sj;Z#x_;A|<6p z_}F4vdnP?_bhmf+tq*R%EhF>eo`RASv!pgk>$?K<>=hSTac-_da4?ruQvoD2)J~B` zyAcco?u(C5fOh5Y--}xQFX9N|D3Y5<7dh@2$42 zLgQK|3bzkHn%P1CRn>+X1bHV4ke3Rg0vPlpZv4_~bh<~s84#l-f4~8vD?HS)erdaR zsfnHk&24HUN*iTTR4+$Se0Y(Ao8j7C(^J#2hYwLJ)0%Rje~|UXku|;9fo%_v#jrYW zF%{nbL$rsaW$uI(iS9zERIrQiwuih;i_2PYcsedm%6^ zCuBs?GoYvYz303q&;P*#e|ZcnJ)=3fjZeGaYH`-W&cbYK<&^)nUf^su5~smynTgg< z!>{|meQLTZGe`_WrQ4qZ48ARKaNdE8#+z84L`U_ZxiItz3w)oj}cl;N!+`;k|)8ER=`0nBl_0gEbug`fYTUITP0x)LD6

-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 Y^x5U~?nwvnkuZS5dsUfAsgGa&52VagDgXcg literal 0 HcmV?d00001 diff --git a/assets/screenshots/union.png b/assets/screenshots/union.png new file mode 100644 index 0000000000000000000000000000000000000000..51827e3e1877325d344bb6dd2a6f3969c7a8e2df GIT binary patch literal 71892 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

@ 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 TUVLaaV*mnAS3j3^P6 { +sealed class AsyncResult { const AsyncResult._(); const factory AsyncResult.loading() = AsyncResultLoading; @@ -30,7 +30,7 @@ abstract class User { } @Union() -abstract class UnionWithGenericConstraints { +sealed class UnionWithGenericConstraints { const UnionWithGenericConstraints._(); factory UnionWithGenericConstraints.data(T data) = UnionWithGenericConstraintsData; diff --git a/examples/file_generation_mode/lib/union/generics.gen.dart b/examples/file_generation_mode/lib/union/generics.gen.dart index 55257a7..5c47c3d 100644 --- a/examples/file_generation_mode/lib/union/generics.gen.dart +++ b/examples/file_generation_mode/lib/union/generics.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'generics.dart'; diff --git a/examples/file_generation_mode/lib/union/hash_and_equality.dart b/examples/file_generation_mode/lib/union/hash_and_equality.dart index f151568..10e608e 100644 --- a/examples/file_generation_mode/lib/union/hash_and_equality.dart +++ b/examples/file_generation_mode/lib/union/hash_and_equality.dart @@ -4,7 +4,7 @@ import 'package:file_generation_mode/pretty_print.dart'; part 'hash_and_equality.gen.dart'; @Union() -abstract class AsyncResult { +sealed class AsyncResult { const AsyncResult._(); /// Shorthand constructor diff --git a/examples/file_generation_mode/lib/union/hash_and_equality.gen.dart b/examples/file_generation_mode/lib/union/hash_and_equality.gen.dart index da041f9..62879d8 100644 --- a/examples/file_generation_mode/lib/union/hash_and_equality.gen.dart +++ b/examples/file_generation_mode/lib/union/hash_and_equality.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'hash_and_equality.dart'; diff --git a/examples/file_generation_mode/lib/union/shared_fields.dart b/examples/file_generation_mode/lib/union/shared_fields.dart index d30f3b2..63227d4 100644 --- a/examples/file_generation_mode/lib/union/shared_fields.dart +++ b/examples/file_generation_mode/lib/union/shared_fields.dart @@ -4,7 +4,7 @@ import 'package:file_generation_mode/pretty_print.dart'; part 'shared_fields.gen.dart'; @Union() -abstract class HttpResponse { +sealed class HttpResponse { const HttpResponse._(); factory HttpResponse.ok({ diff --git a/examples/file_generation_mode/lib/union/shared_fields.gen.dart b/examples/file_generation_mode/lib/union/shared_fields.gen.dart index a66dc7e..ee6ed4b 100644 --- a/examples/file_generation_mode/lib/union/shared_fields.gen.dart +++ b/examples/file_generation_mode/lib/union/shared_fields.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'shared_fields.dart'; diff --git a/examples/file_generation_mode/lib/union/simple.dart b/examples/file_generation_mode/lib/union/simple.dart index 0ac88f8..e1c7d5b 100644 --- a/examples/file_generation_mode/lib/union/simple.dart +++ b/examples/file_generation_mode/lib/union/simple.dart @@ -4,7 +4,7 @@ import 'package:file_generation_mode/pretty_print.dart'; part 'simple.gen.dart'; @Union() -abstract class AsyncResult { +sealed class AsyncResult { const AsyncResult._(); /// Shorthand constructor diff --git a/examples/file_generation_mode/lib/union/simple.gen.dart b/examples/file_generation_mode/lib/union/simple.gen.dart index 32b41b4..d20feb6 100644 --- a/examples/file_generation_mode/lib/union/simple.gen.dart +++ b/examples/file_generation_mode/lib/union/simple.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'simple.dart'; diff --git a/examples/file_generation_mode/lib/union/to_json/json_key.dart b/examples/file_generation_mode/lib/union/to_json/json_key.dart index 9b48c54..6da2db4 100644 --- a/examples/file_generation_mode/lib/union/to_json/json_key.dart +++ b/examples/file_generation_mode/lib/union/to_json/json_key.dart @@ -21,7 +21,7 @@ abstract class Post { } @Union() -abstract class GetPostsResponse { +sealed class GetPostsResponse { const GetPostsResponse._(); factory GetPostsResponse.error() = GetPostsResponseError; diff --git a/examples/file_generation_mode/lib/union/to_json/json_key.gen.dart b/examples/file_generation_mode/lib/union/to_json/json_key.gen.dart index e494591..5e1199d 100644 --- a/examples/file_generation_mode/lib/union/to_json/json_key.gen.dart +++ b/examples/file_generation_mode/lib/union/to_json/json_key.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'json_key.dart'; diff --git a/examples/file_generation_mode/lib/union/to_json/simple.dart b/examples/file_generation_mode/lib/union/to_json/simple.dart index 68c1e9e..fa93cf3 100644 --- a/examples/file_generation_mode/lib/union/to_json/simple.dart +++ b/examples/file_generation_mode/lib/union/to_json/simple.dart @@ -29,7 +29,7 @@ abstract class Post { unionJsonKey: 'code', unionFallbackJsonValue: 'error', ) -abstract class GetPostsResponse { +sealed class GetPostsResponse { const GetPostsResponse._(); // You can use @UnionJsonKeyValue(key) to specific a custom value for the constructor to match diff --git a/examples/file_generation_mode/lib/union/to_json/simple.gen.dart b/examples/file_generation_mode/lib/union/to_json/simple.gen.dart index f95ae4d..c609cfd 100644 --- a/examples/file_generation_mode/lib/union/to_json/simple.gen.dart +++ b/examples/file_generation_mode/lib/union/to_json/simple.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'simple.dart'; diff --git a/examples/file_generation_mode/pubspec.lock b/examples/file_generation_mode/pubspec.lock index 65f87e3..6d79b1f 100644 --- a/examples/file_generation_mode/pubspec.lock +++ b/examples/file_generation_mode/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "8c7478991c7bbde2c1e18034ac697723176a5d3e7e0ca06c7f9aed69b6f388d7" + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a url: "https://pub.dev" source: hosted - version: "51.0.0" + version: "61.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "120fe7ce25377ba616bb210e7584983b163861f45d6ec446744d507e3943881b" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.13.0" analyzer_plugin: dependency: transitive description: @@ -29,18 +29,18 @@ packages: dependency: transitive description: name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.2" convert: dependency: transitive description: @@ -69,41 +69,41 @@ packages: dependency: transitive description: name: coverage - sha256: d2494157c32b303f47dedee955b1479f2979c4ff66934eb7c0def44fd9e0267a + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" url: "https://pub.dev" source: hosted - version: "1.6.1" + version: "1.6.3" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" dart_style: dependency: transitive description: name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.3.1" data_class_plugin: dependency: "direct main" description: path: "../../package" relative: true source: path - version: "0.3.1" + version: "1.0.0-tachyon.dev.5" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" frontend_server_client: dependency: transitive description: @@ -116,10 +116,10 @@ packages: dependency: transitive description: name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" http_multi_server: dependency: transitive description: @@ -140,66 +140,66 @@ packages: dependency: transitive description: name: io - sha256: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: "direct dev" description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.0" logging: dependency: transitive description: name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" matcher: dependency: transitive description: name: matcher - sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.14" + version: "0.12.16" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime: dependency: transitive description: name: mime - sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" node_preamble: dependency: transitive description: name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" package_config: dependency: transitive description: @@ -228,10 +228,10 @@ packages: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" rxdart: dependency: transitive description: @@ -244,34 +244,34 @@ packages: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" shelf_static: dependency: transitive description: name: shelf_static - sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" source_map_stack_trace: dependency: transitive description: @@ -284,18 +284,18 @@ packages: dependency: transitive description: name: source_maps - sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" url: "https://pub.dev" source: hosted - version: "0.10.11" + version: "0.10.12" source_span: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -320,6 +320,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + tachyon: + dependency: "direct dev" + description: + name: tachyon + sha256: b9acc6ccdfd8b920a60531b481b8ed10075e7e3a183af498371471629b4f52cc + url: "https://pub.dev" + source: hosted + version: "0.0.5" term_glyph: dependency: transitive description: @@ -332,58 +340,58 @@ packages: dependency: "direct dev" description: name: test - sha256: "98403d1090ac0aa9e33dfc8bf45cc2e0c1d5c58d7cb832cee1e50bf14f37961d" + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" url: "https://pub.dev" source: hosted - version: "1.22.1" + version: "1.24.3" test_api: dependency: transitive description: name: test_api - sha256: c9282698e2982b6c3817037554e52f99d4daba493e8028f8112a83d68ccd0b12 + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.4.17" + version: "0.6.0" test_core: dependency: transitive description: name: test_core - sha256: c9e4661a5e6285b795d47ba27957ed8b6f980fc020e98b218e276e88aff02168 + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" url: "https://pub.dev" source: hosted - version: "0.4.21" + version: "0.5.3" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" vm_service: dependency: transitive description: name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + sha256: f3743ca475e0c9ef71df4ba15eb2d7684eecd5c8ba20a462462e4e8b561b2e11 url: "https://pub.dev" source: hosted - version: "9.4.0" + version: "11.6.0" watcher: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.0" webkit_inspection_protocol: dependency: transitive description: @@ -396,9 +404,9 @@ packages: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.0.0 <4.0.0" diff --git a/examples/file_generation_mode/pubspec.yaml b/examples/file_generation_mode/pubspec.yaml index f98d3a8..c0f7b3f 100644 --- a/examples/file_generation_mode/pubspec.yaml +++ b/examples/file_generation_mode/pubspec.yaml @@ -4,12 +4,13 @@ version: 1.0.0 publish_to: none environment: - sdk: '>=2.18.0 <3.0.0' + sdk: ">=3.0.0 <4.0.0" dependencies: data_class_plugin: path: ../../package dev_dependencies: - lints: ^2.0.0 - test: ^1.16.0 + lints: ^2.1.0 + tachyon: ^0.0.5 + test: ^1.24.3 diff --git a/examples/file_generation_mode/tachyon_config.yaml b/examples/file_generation_mode/tachyon_config.yaml new file mode 100644 index 0000000..678b3aa --- /dev/null +++ b/examples/file_generation_mode/tachyon_config.yaml @@ -0,0 +1,8 @@ +file_generation_paths: + - "lib/data_class/**" + - "lib/union/**" + +generated_file_line_length: 100 + +plugins: + - data_class_plugin diff --git a/examples/in_place_mode/.gitignore b/examples/in_place_mode/.gitignore deleted file mode 100644 index 3c8a157..0000000 --- a/examples/in_place_mode/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build output. -build/ diff --git a/examples/in_place_mode/analysis_options.yaml b/examples/in_place_mode/analysis_options.yaml deleted file mode 100644 index b68648d..0000000 --- a/examples/in_place_mode/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: ../../package/analysis_options.yaml diff --git a/examples/in_place_mode/data_class_plugin_options.yaml b/examples/in_place_mode/data_class_plugin_options.yaml deleted file mode 100644 index ac92b67..0000000 --- a/examples/in_place_mode/data_class_plugin_options.yaml +++ /dev/null @@ -1,16 +0,0 @@ -generation_mode: in_place - -json: - # default case for naming a json key - key_name_convention: camel_case - # key_name_conventions glob match takes precedence over key_name_convention - key_name_conventions: - kebab_case: - - "lib/data_class/from_json/kebab/**.dart" - - "lib/data_class/to_json/kebab/**.dart" - pascal_case: - - "lib/data_class/from_json/pascal/**.dart" - - "lib/data_class/to_json/pascal/**.dart" - snake_case: - - "lib/data_class/from_json/snake/**.dart" - - "lib/data_class/to_json/snake/**.dart" diff --git a/examples/in_place_mode/lib/data_class/copy_with.dart b/examples/in_place_mode/lib/data_class/copy_with.dart deleted file mode 100644 index 75a5f44..0000000 --- a/examples/in_place_mode/lib/data_class/copy_with.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - copyWith: true, - fromJson: false, - toJson: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - this.permissions, - }); - - final String id; - final String username; - final List? permissions; - - /// Creates a new instance of [User] with optional new values - User copyWith({ - final String? id, - final String? username, - final List? permissions, - }) { - return User( - id: id ?? this.id, - username: username ?? this.username, - permissions: permissions ?? this.permissions, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/data_class_with_super_class.dart b/examples/in_place_mode/lib/data_class/data_class_with_super_class.dart deleted file mode 100644 index 81835eb..0000000 --- a/examples/in_place_mode/lib/data_class/data_class_with_super_class.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -class Person { - /// Shorthand constructor - const Person({ - required this.name, - required this.age, - }); - - final String name; - final String age; -} - -class User extends Person { - /// Shorthand constructor - const User({ - required super.age, - required super.name, - required this.username, - required this.id, - }); - - @JsonKey(name: '_username') - final String username; - final String id; - - /// Returns a string with the properties of [User] - @override - String toString() { - String value = 'User{}'; - assert(() { - value = 'User@<$hexIdentity>{username: $username, id: $id, name: $name, age: $age}'; - return true; - }()); - return value; - } -} - -@DataClass() -class Admin extends User { - /// Shorthand constructor - const Admin({ - required super.id, - required super.age, - required super.name, - required super.username, - required this.permissions, - }); - - final List permissions; - - /// Returns a string with the properties of [Admin] - @override - String toString() { - String value = 'Admin{}'; - assert(() { - value = - 'Admin@<$hexIdentity>{permissions: $permissions, username: $username, id: $id, name: $name, age: $age}'; - return true; - }()); - return value; - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - permissions, - username, - id, - name, - age, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is Admin && - runtimeType == other.runtimeType && - deepEquality(permissions, other.permissions) && - username == other.username && - id == other.id && - name == other.name && - age == other.age; - } - - /// Creates a new instance of [Admin] with optional new values - Admin copyWith({ - final List? permissions, - final String? username, - final String? id, - final String? name, - final String? age, - }) { - return Admin( - permissions: permissions ?? this.permissions, - username: username ?? this.username, - id: id ?? this.id, - name: name ?? this.name, - age: age ?? this.age, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/default_data_class.dart b/examples/in_place_mode/lib/data_class/default_data_class.dart deleted file mode 100644 index 11c4c60..0000000 --- a/examples/in_place_mode/lib/data_class/default_data_class.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass() -class User { - /// Shorthand constructor - const User({ - required this.username, - required this.id, - }); - - final String username; - final String id; - - /// Returns a string with the properties of [User] - @override - String toString() { - String value = 'User{}'; - assert(() { - value = 'User@<$hexIdentity>{username: $username, id: $id}'; - return true; - }()); - return value; - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - username, - id, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is User && - runtimeType == other.runtimeType && - username == other.username && - id == other.id; - } - - /// Creates a new instance of [User] with optional new values - User copyWith({ - final String? username, - final String? id, - }) { - return User( - username: username ?? this.username, - id: id ?? this.id, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/camel/simple_usage.dart b/examples/in_place_mode/lib/data_class/from_json/camel/simple_usage.dart deleted file mode 100644 index 1ae997e..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/camel/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsAVariable: json['thisIsAVariable'] as String, - thisIsADifferentVariable: json['thisIsADifferentVariable'] as String, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/default_value_usage.dart b/examples/in_place_mode/lib/data_class/from_json/default_value_usage.dart deleted file mode 100644 index 0f4be5f..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/default_value_usage.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - this.friends = const {}, - }); - - final Map friends; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - friends: json['friends'] == null - ? const {} - : { - for (final MapEntry e0 - in (json['friends'] as Map).entries) - e0.key: User.fromJson(e0.value), - }, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/json_key_usage.dart b/examples/in_place_mode/lib/data_class/from_json/json_key_usage.dart deleted file mode 100644 index 7df5872..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/json_key_usage.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - this.appId = 'app_id', - }); - - @JsonKey(name: '_id') - final String id; - - @JsonKey(fromJson: _usernameConverter) - final String username; - - @JsonKey(ignore: true) - final String appId; - - // fields with initial values are ignored - final int isSpecial = 0; - - static String _usernameConverter(dynamic value, Map json, String keyName) { - return value ?? ''; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - id: json['_id'] as String, - username: User._usernameConverter(json['username'], json, 'username'), - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/kebab/simple_usage.dart b/examples/in_place_mode/lib/data_class/from_json/kebab/simple_usage.dart deleted file mode 100644 index 18cc900..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/kebab/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsAVariable: json['this-is-a-variable'] as String, - thisIsADifferentVariable: json['this-is-a-different-variable'] as String, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/null_field_usage.dart b/examples/in_place_mode/lib/data_class/from_json/null_field_usage.dart deleted file mode 100644 index 1ebc123..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/null_field_usage.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - this.avatarUrl, - }); - - final String? avatarUrl; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - avatarUrl: json['avatarUrl'] == null ? null : json['avatarUrl'] as String, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/pascal/simple_usage.dart b/examples/in_place_mode/lib/data_class/from_json/pascal/simple_usage.dart deleted file mode 100644 index 2064d11..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/pascal/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsAVariable: json['ThisIsAVariable'] as String, - thisIsADifferentVariable: json['ThisIsADifferentVariable'] as String, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/simple_usage.dart b/examples/in_place_mode/lib/data_class/from_json/simple_usage.dart deleted file mode 100644 index 532813a..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - }); - - final String id; - final String username; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - id: json['id'] as String, - username: json['username'] as String, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/from_json/snake/simple_usage.dart b/examples/in_place_mode/lib/data_class/from_json/snake/simple_usage.dart deleted file mode 100644 index da0176d..0000000 --- a/examples/in_place_mode/lib/data_class/from_json/snake/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsAVariable: json['this_is_a_variable'] as String, - thisIsADifferentVariable: json['this_is_a_different_variable'] as String, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/hash_and_equals.dart b/examples/in_place_mode/lib/data_class/hash_and_equals.dart deleted file mode 100644 index be2873f..0000000 --- a/examples/in_place_mode/lib/data_class/hash_and_equals.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - hashAndEquals: false, - fromJson: false, - toJson: true, - $toString: true, -) -class Point { - /// Shorthand constructor - Point({ - required this.x, - required this.y, - }); - - final double x; - final double y; - - /// Converts [Point] to a [Map] json - Map toJson() { - return { - 'x': x, - 'y': y, - }; - } - - /// Returns a string with the properties of [Point] - @override - String toString() { - String value = 'Point{}'; - assert(() { - value = 'Point@<$hexIdentity>{x: $x, y: $y}'; - return true; - }()); - return value; - } - - /// Creates a new instance of [Point] with optional new values - Point copyWith({ - final double? x, - final double? y, - }) { - return Point( - x: x ?? this.x, - y: y ?? this.y, - ); - } -} diff --git a/examples/in_place_mode/lib/data_class/to_json/camel/simple_usage.dart b/examples/in_place_mode/lib/data_class/to_json/camel/simple_usage.dart deleted file mode 100644 index 1583787..0000000 --- a/examples/in_place_mode/lib/data_class/to_json/camel/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'thisIsAVariable': thisIsAVariable, - 'thisIsADifferentVariable': thisIsADifferentVariable, - }; - } -} diff --git a/examples/in_place_mode/lib/data_class/to_json/json_key_usage.dart b/examples/in_place_mode/lib/data_class/to_json/json_key_usage.dart deleted file mode 100644 index ff4d282..0000000 --- a/examples/in_place_mode/lib/data_class/to_json/json_key_usage.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - }); - - @JsonKey(toJson: _toIdMapper) - final String id; - final String username; - - static String _toIdMapper(dynamic id) { - return '__${id}__'; - } - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'id': User._toIdMapper(id), - 'username': username, - }; - } -} diff --git a/examples/in_place_mode/lib/data_class/to_json/kebab/simple_usage.dart b/examples/in_place_mode/lib/data_class/to_json/kebab/simple_usage.dart deleted file mode 100644 index 3e52776..0000000 --- a/examples/in_place_mode/lib/data_class/to_json/kebab/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'this-is-a-variable': thisIsAVariable, - 'this-is-a-different-variable': thisIsADifferentVariable, - }; - } -} diff --git a/examples/in_place_mode/lib/data_class/to_json/pascal/simple_usage.dart b/examples/in_place_mode/lib/data_class/to_json/pascal/simple_usage.dart deleted file mode 100644 index db272bf..0000000 --- a/examples/in_place_mode/lib/data_class/to_json/pascal/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'ThisIsAVariable': thisIsAVariable, - 'ThisIsADifferentVariable': thisIsADifferentVariable, - }; - } -} diff --git a/examples/in_place_mode/lib/data_class/to_json/simple_usage.dart b/examples/in_place_mode/lib/data_class/to_json/simple_usage.dart deleted file mode 100644 index f4d1050..0000000 --- a/examples/in_place_mode/lib/data_class/to_json/simple_usage.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - this.email, - }); - - final String id; - final String username; - final String? email; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'id': id, - 'username': username, - 'email': email, - }; - } -} - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class GetUsersResponse { - /// Shorthand constructor - GetUsersResponse({ - required this.ok, - required this.users, - }); - - final bool ok; - final List users; - - /// Converts [GetUsersResponse] to a [Map] json - Map toJson() { - return { - 'ok': ok, - 'users': [ - for (final User i0 in users) i0.toJson(), - ], - }; - } -} diff --git a/examples/in_place_mode/lib/data_class/to_json/snake/simple_usage.dart b/examples/in_place_mode/lib/data_class/to_json/snake/simple_usage.dart deleted file mode 100644 index c44c861..0000000 --- a/examples/in_place_mode/lib/data_class/to_json/snake/simple_usage.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsAVariable, - required this.thisIsADifferentVariable, - }); - - final String thisIsAVariable; - final String thisIsADifferentVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'this_is_a_variable': thisIsAVariable, - 'this_is_a_different_variable': thisIsADifferentVariable, - }; - } -} diff --git a/examples/in_place_mode/lib/enums/enum_annotation.dart b/examples/in_place_mode/lib/enums/enum_annotation.dart deleted file mode 100644 index ad5d26d..0000000 --- a/examples/in_place_mode/lib/enums/enum_annotation.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Enum( - toJson: true, - fromJson: true, - $toString: true, -) -enum Category { - science(1), - finance(2), - music(3), - tech(4); - - /// Default constructor of [Category] - const Category(this.id); - - final int id; - - /// Returns a string with the properties of [Category] - @override - String toString() { - String value = 'Category{}'; - assert(() { - value = 'Category@<$hexIdentity>{id: $id}'; - return true; - }()); - return value; - } - - /// Converts [Category] to a json value - int toJson() => id; - - /// Creates an instance of [Category] from [json] - factory Category.fromJson(int json) { - return Category.values.firstWhere((Category e) => e.id == json); - } -} diff --git a/examples/in_place_mode/lib/enums/enum_constructor.dart b/examples/in_place_mode/lib/enums/enum_constructor.dart deleted file mode 100644 index 3c17458..0000000 --- a/examples/in_place_mode/lib/enums/enum_constructor.dart +++ /dev/null @@ -1,14 +0,0 @@ -enum EnumCtor { - value1(0, 'a'), - value2(1, 'b'), - value3(2, 'c'); - - /// Default constructor of [EnumCtor] - const EnumCtor( - this.a, - this.b, - ); - - final int a; - final String b; -} diff --git a/examples/in_place_mode/lib/enums/enum_to_string.dart b/examples/in_place_mode/lib/enums/enum_to_string.dart deleted file mode 100644 index b051a17..0000000 --- a/examples/in_place_mode/lib/enums/enum_to_string.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -enum Colors { - red('#FF0000', 0.5), - green('#008000', 0.7), - blue('#0000FF', 0.4); - - /// Default constructor of [Colors] - const Colors( - this.hex, - this.opacity, - ); - - final String hex; - final double opacity; - - /// Returns a string with the properties of [Colors] - @override - String toString() { - String value = 'Colors{}'; - assert(() { - value = 'Colors.$name@<$hexIdentity>{hex: $hex, opacity: $opacity}'; - return true; - }()); - return value; - } -} diff --git a/examples/in_place_mode/lib/enums/from_json.dart b/examples/in_place_mode/lib/enums/from_json.dart deleted file mode 100644 index 950a479..0000000 --- a/examples/in_place_mode/lib/enums/from_json.dart +++ /dev/null @@ -1,33 +0,0 @@ -// fromJson uses .name of the enum -enum Category1 { - science, - sports, - arts, - financial; - - /// Default constructor of [Category1] - const Category1(); - - /// Creates an instance of [Category1] from [json] - factory Category1.fromJson(String json) { - return Category1.values.firstWhere((Category1 value) => value.name == json); - } -} - -// fromJson single final field -enum Category2 { - science(0), - sports(1000), - arts(2000), - financial(3000); - - /// Default constructor of [Category2] - const Category2(this.value); - - final int value; - - /// Creates an instance of [Category2] from [json] - factory Category2.fromJson(int json) { - return Category2.values.firstWhere((Category2 e) => e.value == json); - } -} diff --git a/examples/in_place_mode/lib/enums/to_json.dart b/examples/in_place_mode/lib/enums/to_json.dart deleted file mode 100644 index aff7d69..0000000 --- a/examples/in_place_mode/lib/enums/to_json.dart +++ /dev/null @@ -1,29 +0,0 @@ -// toJson uses .name of the enum -enum Category1 { - science, - sports, - arts, - financial; - - /// Default constructor of [Category1] - const Category1(); - - /// Converts [Category1] to a json value - String toJson() => name; -} - -// toJson single final field -enum Category2 { - science(0), - sports(1000), - arts(2000), - financial(3000); - - /// Default constructor of [Category2] - const Category2(this.value); - - final int value; - - /// Converts [Category2] to a json value - int toJson() => value; -} diff --git a/examples/in_place_mode/lib/json_converter.dart b/examples/in_place_mode/lib/json_converter.dart deleted file mode 100644 index 729c18a..0000000 --- a/examples/in_place_mode/lib/json_converter.dart +++ /dev/null @@ -1,136 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -// Assume this is in external package -class LatLng { - LatLng({ - required this.lat, - required this.lng, - }); - - final double lat; - final double lng; - - /// Returns a string with the properties of [LatLng] - @override - String toString() { - String value = 'LatLng{}'; - assert(() { - value = 'LatLng@<$hexIdentity>{lat: $lat, lng: $lng}'; - return true; - }()); - return value; - } -} - -// Create a custom converter -class LatLngConverter implements JsonConverter { - const LatLngConverter(); - - @override - String toJson(LatLng value) { - return '${value.lat}|${value.lng}'; - } - - @override - LatLng fromJson(String value, Map json, String keyName) { - final List values = value.split('|').map(double.parse).toList(growable: false); - return LatLng(lat: values[0], lng: values[1]); - } -} - -@DataClass( - $toString: false, - copyWith: false, - hashAndEquals: false, - fromJson: true, - toJson: true, -) -class ClassWithLatLngField { - /// Shorthand constructor - ClassWithLatLngField({ - required this.datetime, - required this.uri, - required this.latLng, - }); - - // DateTime and Uri are supported out of the box - final DateTime datetime; - final Uri uri; - final LatLng latLng; - - /// Creates an instance of [ClassWithLatLngField] from [json] - factory ClassWithLatLngField.fromJson(Map json) { - return ClassWithLatLngField( - datetime: jsonConverterRegistrant.find(DateTime).fromJson(json['datetime'], json, 'datetime') - as DateTime, - uri: jsonConverterRegistrant.find(Uri).fromJson(json['uri'], json, 'uri') as Uri, - latLng: - jsonConverterRegistrant.find(LatLng).fromJson(json['latLng'], json, 'latLng') as LatLng, - ); - } - - /// Converts [ClassWithLatLngField] to a [Map] json - Map toJson() { - return { - 'datetime': jsonConverterRegistrant.find(DateTime).toJson(datetime), - 'uri': jsonConverterRegistrant.find(Uri).toJson(uri), - 'latLng': jsonConverterRegistrant.find(LatLng).toJson(latLng), - }; - } -} - -@DataClass( - $toString: false, - copyWith: false, - hashAndEquals: false, - fromJson: true, - toJson: true, -) -class ClassWithLatLngConverterAnnotation { - /// Shorthand constructor - ClassWithLatLngConverterAnnotation({ - required this.datetime, - required this.uri, - required this.latLng, - }); - - // DateTime and Uri are supported out of the box - final DateTime datetime; - final Uri uri; - - @LatLngConverter() - final LatLng latLng; - - /// Creates an instance of [ClassWithLatLngConverterAnnotation] from [json] - factory ClassWithLatLngConverterAnnotation.fromJson(Map json) { - return ClassWithLatLngConverterAnnotation( - datetime: jsonConverterRegistrant.find(DateTime).fromJson(json['datetime'], json, 'datetime') - as DateTime, - uri: jsonConverterRegistrant.find(Uri).fromJson(json['uri'], json, 'uri') as Uri, - latLng: const LatLngConverter().fromJson(json['latLng'], json, 'latLng'), - ); - } - - /// Converts [ClassWithLatLngConverterAnnotation] to a [Map] json - Map toJson() { - return { - 'datetime': jsonConverterRegistrant.find(DateTime).toJson(datetime), - 'uri': jsonConverterRegistrant.find(Uri).toJson(uri), - 'latLng': const LatLngConverter().toJson(latLng), - }; - } -} - -void main() { - jsonConverterRegistrant.register(const LatLngConverter()); - - final ClassWithLatLngField o = ClassWithLatLngField.fromJson( - { - 'datetime': DateTime.now().toIso8601String(), - 'uri': 'https://google.com', - 'latLng': '0.01|0.99', - }, - ); - - print(o); -} diff --git a/examples/in_place_mode/lib/unions/data_class.dart b/examples/in_place_mode/lib/unions/data_class.dart deleted file mode 100644 index 7c716a8..0000000 --- a/examples/in_place_mode/lib/unions/data_class.dart +++ /dev/null @@ -1,196 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - copyWith: true, - hashAndEquals: true, - $toString: true, - fromJson: false, - toJson: false, -) -abstract class AsyncResult { - const AsyncResult._(); - - const factory AsyncResult.data({ - required T data, - }) = AsyncResultData; - - const factory AsyncResult.loading() = AsyncResultLoading; - - const factory AsyncResult.error({ - required Object error, - StackTrace? stackTrace, - }) = AsyncResultError; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(AsyncResultData value) data, - required R Function() loading, - required R Function(AsyncResultError value) error, - }) { - if (this is AsyncResultData) { - return data(this as AsyncResultData); - } - if (this is AsyncResultLoading) { - return loading(); - } - if (this is AsyncResultError) { - return error(this as AsyncResultError); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(AsyncResultData value)? data, - R Function()? loading, - R Function(AsyncResultError value)? error, - required R Function() orElse, - }) { - if (this is AsyncResultData) { - return data?.call(this as AsyncResultData) ?? orElse(); - } - if (this is AsyncResultLoading) { - return loading?.call() ?? orElse(); - } - if (this is AsyncResultError) { - return error?.call(this as AsyncResultError) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class AsyncResultData extends AsyncResult { - const AsyncResultData({ - required this.data, - }) : super._(); - - final T data; - - /// Creates a new instance of [AsyncResultData] with optional new values - AsyncResultData copyWith({ - final T? data, - }) { - return AsyncResultData( - data: data ?? this.data, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - data, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AsyncResultData && runtimeType == other.runtimeType && data == other.data; - } - - /// Returns a string with the properties of [AsyncResultData] - @override - String toString() { - String value = 'AsyncResultData{}'; - assert(() { - value = 'AsyncResultData<$T>@<$hexIdentity>{data: $data}'; - return true; - }()); - return value; - } -} - -class AsyncResultLoading extends AsyncResult { - const AsyncResultLoading() : super._(); - - /// Creates a new instance of [AsyncResultLoading] with optional new values - AsyncResultLoading copyWith() { - return AsyncResultLoading(); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AsyncResultLoading && runtimeType == other.runtimeType; - } - - /// Returns a string with the properties of [AsyncResultLoading] - @override - String toString() { - String value = 'AsyncResultLoading{}'; - assert(() { - value = 'AsyncResultLoading<$T>@<$hexIdentity>{}'; - return true; - }()); - return value; - } -} - -class AsyncResultError extends AsyncResult { - const AsyncResultError({ - required this.error, - this.stackTrace, - }) : super._(); - - final Object error; - final StackTrace? stackTrace; - - /// Creates a new instance of [AsyncResultError] with optional new values - AsyncResultError copyWith({ - final Object? error, - final StackTrace? stackTrace, - }) { - return AsyncResultError( - error: error ?? this.error, - stackTrace: stackTrace ?? this.stackTrace, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - error, - stackTrace, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AsyncResultError && - runtimeType == other.runtimeType && - error == other.error && - stackTrace == other.stackTrace; - } - - /// Returns a string with the properties of [AsyncResultError] - @override - String toString() { - String value = 'AsyncResultError{}'; - assert(() { - value = 'AsyncResultError<$T>@<$hexIdentity>{error: $error, stackTrace: $stackTrace}'; - return true; - }()); - return value; - } -} diff --git a/examples/in_place_mode/lib/unions/default_value.dart b/examples/in_place_mode/lib/unions/default_value.dart deleted file mode 100644 index 55b120e..0000000 --- a/examples/in_place_mode/lib/unions/default_value.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -class User { - /// Shorthand constructor - const User({ - required this.username, - }); - - final String username; - - static const User none = User(username: ''); -} - -@Union( - copyWith: false, - $toString: false, - hashAndEquals: false, - fromJson: false, - toJson: false, -) -abstract class UnionWithDefaultValues { - const UnionWithDefaultValues._(); - - const factory UnionWithDefaultValues.impl({ - @DefaultValue(User.none) User value, - @DefaultValue('') String value2, - @DefaultValue(User(username: '')) User value3, - @DefaultValue(0) int value4, - @DefaultValue(true) bool value5, - }) = Impl; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(Impl value) impl, - }) { - if (this is Impl) { - return impl(this as Impl); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(Impl value)? impl, - required R Function() orElse, - }) { - if (this is Impl) { - return impl?.call(this as Impl) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class Impl extends UnionWithDefaultValues { - const Impl({ - this.value = User.none, - this.value2 = '', - this.value3 = const User(username: ''), - this.value4 = 0, - this.value5 = true, - }) : super._(); - - final User value; - final String value2; - final User value3; - final int value4; - final bool value5; -} diff --git a/examples/in_place_mode/lib/unions/from_json.dart b/examples/in_place_mode/lib/unions/from_json.dart deleted file mode 100644 index 0a53405..0000000 --- a/examples/in_place_mode/lib/unions/from_json.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - copyWith: false, - hashAndEquals: false, - $toString: false, - fromJson: true, - toJson: false, -) -abstract class Response { - const Response._(); - - /// Creates an instance of [Response] from [json] - factory Response.fromJson(Map json) { - switch (json['status']) { - case 'ok': - return ResponseOk.fromJson(json); - case 'unauthorized': - return ResponseUnauthorized.fromJson(json); - default: - return ResponseError.fromJson(json); - } - } - - const factory Response.ok({ - required int data, - }) = ResponseOk; - - const factory Response.unauthorized() = ResponseUnauthorized; - - const factory Response.error({ - required Object type, - @JsonKey(ignore: true) StackTrace? stackTrace, - }) = ResponseError; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(ResponseOk value) ok, - required R Function() unauthorized, - required R Function(ResponseError value) error, - }) { - if (this is ResponseOk) { - return ok(this as ResponseOk); - } - if (this is ResponseUnauthorized) { - return unauthorized(); - } - if (this is ResponseError) { - return error(this as ResponseError); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(ResponseOk value)? ok, - R Function()? unauthorized, - R Function(ResponseError value)? error, - required R Function() orElse, - }) { - if (this is ResponseOk) { - return ok?.call(this as ResponseOk) ?? orElse(); - } - if (this is ResponseUnauthorized) { - return unauthorized?.call() ?? orElse(); - } - if (this is ResponseError) { - return error?.call(this as ResponseError) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class ResponseOk extends Response { - const ResponseOk({ - required this.data, - }) : super._(); - - final int data; - - /// Creates an instance of [ResponseOk] from [json] - factory ResponseOk.fromJson(Map json) { - return ResponseOk( - data: json['data'] as int, - ); - } -} - -class ResponseUnauthorized extends Response { - const ResponseUnauthorized() : super._(); - - /// Creates an instance of [ResponseUnauthorized] from [json] - factory ResponseUnauthorized.fromJson(Map json) { - return const ResponseUnauthorized(); - } -} - -class ResponseError extends Response { - const ResponseError({ - required this.type, - this.stackTrace, - }) : super._(); - - final Object type; - final StackTrace? stackTrace; - - /// Creates an instance of [ResponseError] from [json] - factory ResponseError.fromJson(Map json) { - return ResponseError( - type: jsonConverterRegistrant.find(Object).fromJson(json['type'], json, 'type') as Object, - ); - } -} diff --git a/examples/in_place_mode/lib/unions/shared_fields.dart b/examples/in_place_mode/lib/unions/shared_fields.dart deleted file mode 100644 index 6d65e4c..0000000 --- a/examples/in_place_mode/lib/unions/shared_fields.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - copyWith: true, - hashAndEquals: true, - $toString: true, - fromJson: false, - toJson: false, -) -abstract class User { - const User._(); - - const factory User.normal({ - required String id, - required String username, - String? email, - }) = UserNormal; - - const factory User.admin({ - required String id, - required String username, - String? email, - }) = UserAdmin; - - String get id; - String get username; - String? get email; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(UserNormal value) normal, - required R Function(UserAdmin value) admin, - }) { - if (this is UserNormal) { - return normal(this as UserNormal); - } - if (this is UserAdmin) { - return admin(this as UserAdmin); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(UserNormal value)? normal, - R Function(UserAdmin value)? admin, - required R Function() orElse, - }) { - if (this is UserNormal) { - return normal?.call(this as UserNormal) ?? orElse(); - } - if (this is UserAdmin) { - return admin?.call(this as UserAdmin) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class UserNormal extends User { - const UserNormal({ - required this.id, - required this.username, - this.email, - }) : super._(); - - @override - final String id; - @override - final String username; - @override - final String? email; - - /// Creates a new instance of [UserNormal] with optional new values - UserNormal copyWith({ - final String? id, - final String? username, - final String? email, - }) { - return UserNormal( - id: id ?? this.id, - username: username ?? this.username, - email: email ?? this.email, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - id, - username, - email, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is UserNormal && - runtimeType == other.runtimeType && - id == other.id && - username == other.username && - email == other.email; - } - - /// Returns a string with the properties of [UserNormal] - @override - String toString() { - String value = 'UserNormal{}'; - assert(() { - value = 'UserNormal@<$hexIdentity>{id: $id, username: $username, email: $email}'; - return true; - }()); - return value; - } -} - -class UserAdmin extends User { - const UserAdmin({ - required this.id, - required this.username, - this.email, - }) : super._(); - - @override - final String id; - @override - final String username; - @override - final String? email; - - /// Creates a new instance of [UserAdmin] with optional new values - UserAdmin copyWith({ - final String? id, - final String? username, - final String? email, - }) { - return UserAdmin( - id: id ?? this.id, - username: username ?? this.username, - email: email ?? this.email, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - id, - username, - email, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is UserAdmin && - runtimeType == other.runtimeType && - id == other.id && - username == other.username && - email == other.email; - } - - /// Returns a string with the properties of [UserAdmin] - @override - String toString() { - String value = 'UserAdmin{}'; - assert(() { - value = 'UserAdmin@<$hexIdentity>{id: $id, username: $username, email: $email}'; - return true; - }()); - return value; - } -} diff --git a/examples/in_place_mode/lib/unions/to_json.dart b/examples/in_place_mode/lib/unions/to_json.dart deleted file mode 100644 index 0003522..0000000 --- a/examples/in_place_mode/lib/unions/to_json.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - copyWith: false, - hashAndEquals: false, - $toString: false, - fromJson: false, - toJson: true, -) -abstract class ToJson { - const ToJson._(); - - const factory ToJson.json1({ - required int v1, - required String v2, - }) = Json1; - - const factory ToJson.json2({ - required Map v1, - required List v2, - }) = Json2; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(Json1 value) json1, - required R Function(Json2 value) json2, - }) { - if (this is Json1) { - return json1(this as Json1); - } - if (this is Json2) { - return json2(this as Json2); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(Json1 value)? json1, - R Function(Json2 value)? json2, - required R Function() orElse, - }) { - if (this is Json1) { - return json1?.call(this as Json1) ?? orElse(); - } - if (this is Json2) { - return json2?.call(this as Json2) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } - - /// Converts [ToJson] to [Map] json - Map toJson(); -} - -class Json1 extends ToJson { - const Json1({ - required this.v1, - required this.v2, - }) : super._(); - - final int v1; - final String v2; - - /// Converts [Json1] to a [Map] json - @override - Map toJson() { - return { - 'v1': v1, - 'v2': v2, - }; - } -} - -class Json2 extends ToJson { - const Json2({ - required this.v1, - required this.v2, - }) : super._(); - - final Map v1; - final List v2; - - /// Converts [Json2] to a [Map] json - @override - Map toJson() { - return { - 'v1': { - for (final MapEntry e0 in v1.entries) e0.key: e0.value, - }, - 'v2': [ - for (final int i0 in v2) i0, - ], - }; - } -} diff --git a/examples/in_place_mode/pubspec.lock b/examples/in_place_mode/pubspec.lock deleted file mode 100644 index f9e1449..0000000 --- a/examples/in_place_mode/pubspec.lock +++ /dev/null @@ -1,404 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" - url: "https://pub.dev" - source: hosted - version: "50.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" - url: "https://pub.dev" - source: hosted - version: "5.2.0" - analyzer_plugin: - dependency: transitive - description: - name: analyzer_plugin - sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d - url: "https://pub.dev" - source: hosted - version: "0.11.2" - args: - dependency: transitive - description: - name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 - url: "https://pub.dev" - source: hosted - version: "2.3.1" - async: - dependency: transitive - description: - name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 - url: "https://pub.dev" - source: hosted - version: "2.10.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - collection: - dependency: transitive - description: - name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 - url: "https://pub.dev" - source: hosted - version: "1.17.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: d2494157c32b303f47dedee955b1479f2979c4ff66934eb7c0def44fd9e0267a - url: "https://pub.dev" - source: hosted - version: "1.6.1" - crypto: - dependency: transitive - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" - source: hosted - version: "3.0.2" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" - url: "https://pub.dev" - source: hosted - version: "2.2.4" - data_class_plugin: - dependency: "direct main" - description: - path: "../../package" - relative: true - source: path - version: "0.3.1" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "82715f8041a85a534a7bf64400b2ee0bb3d594ccf695d97c0bb017259657ff5d" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - glob: - dependency: transitive - description: - name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - 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: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" - url: "https://pub.dev" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" - url: "https://pub.dev" - source: hosted - version: "0.6.5" - lints: - dependency: "direct dev" - description: - name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - logging: - dependency: transitive - description: - name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 - url: "https://pub.dev" - source: hosted - version: "1.1.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" - url: "https://pub.dev" - source: hosted - version: "0.12.13" - meta: - dependency: transitive - description: - name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" - url: "https://pub.dev" - source: hosted - version: "1.8.0" - mime: - dependency: transitive - description: - name: mime - sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a - url: "https://pub.dev" - source: hosted - version: "1.0.2" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" - source: hosted - version: "1.8.3" - 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: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" - source: hosted - version: "0.27.7" - shelf: - dependency: transitive - description: - name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c - url: "https://pub.dev" - source: hosted - version: "1.4.0" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 - url: "https://pub.dev" - source: hosted - version: "3.0.1" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c - url: "https://pub.dev" - source: hosted - version: "1.1.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - 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: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" - url: "https://pub.dev" - source: hosted - version: "0.10.11" - source_span: - dependency: transitive - description: - name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" - source: hosted - version: "1.9.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - 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 dev" - description: - name: test - sha256: "98403d1090ac0aa9e33dfc8bf45cc2e0c1d5c58d7cb832cee1e50bf14f37961d" - url: "https://pub.dev" - source: hosted - version: "1.22.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: c9282698e2982b6c3817037554e52f99d4daba493e8028f8112a83d68ccd0b12 - url: "https://pub.dev" - source: hosted - version: "0.4.17" - test_core: - dependency: transitive - description: - name: test_core - sha256: c9e4661a5e6285b795d47ba27957ed8b6f980fc020e98b218e276e88aff02168 - url: "https://pub.dev" - source: hosted - version: "0.4.21" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 - url: "https://pub.dev" - source: hosted - version: "9.4.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" - url: "https://pub.dev" - source: hosted - version: "3.1.1" -sdks: - dart: ">=2.18.0 <3.0.0" diff --git a/examples/in_place_mode/pubspec.yaml b/examples/in_place_mode/pubspec.yaml deleted file mode 100644 index 0882fec..0000000 --- a/examples/in_place_mode/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: in_place_mode -description: Example app for data_class_plugin -version: 1.0.0 -publish_to: "none" -# homepage: https://www.example.com - -environment: - sdk: ">=2.17.0 <3.0.0" - -dependencies: - data_class_plugin: - path: ../../package - -dev_dependencies: - lints: ^2.0.1 - test: ^1.22.1 diff --git a/package/.gitignore b/package/.gitignore new file mode 100644 index 0000000..08c7575 --- /dev/null +++ b/package/.gitignore @@ -0,0 +1 @@ +**/pubspec.lock \ No newline at end of file diff --git a/package/CHANGELOG.md b/package/CHANGELOG.md index 23a35ac..a4667dd 100644 --- a/package/CHANGELOG.md +++ b/package/CHANGELOG.md @@ -1,3 +1,34 @@ +## 1.0.0 + +- Stable release with `Tachyon` + +## 1.0.0-tachyon.dev.5 + +- Fix tools/analyzer_plugin dependency version of data_class_plugin + +## 1.0.0-tachyon.dev.4 + +- Fix automatic conversion for final fields on data classes + +## 1.0.0-tachyon.dev.3 + +- Update tachyon to 0.0.5 + +## 1.0.0-tachyon.dev.2 + +- Fix tools/analyzer_plugin dependency version of data_class_plugin + +## 1.0.0-tachyon.dev.1 + +**Breaking changes**: + +- Migration to [Tachyon](https://github.com/spideythewebhead/tachyon) +- Removed "In place" only code generation + +Other: + +- Use sealed instead of abstract for unions if dart 3 is available + ## 0.3.1 - Add support for required positional arguments in Unions [(issue #299)](https://github.com/spideythewebhead/data_class_plugin/issues/299) diff --git a/package/README.md b/package/README.md index b496818..64b5aeb 100644 --- a/package/README.md +++ b/package/README.md @@ -8,11 +8,7 @@ [![Pub Publisher](https://img.shields.io/pub/publisher/data_class_plugin)](https://github.com/spideythewebhead) --> -**Data Class Plugin** is a tool that uses the Dart Analysis Server to generate code on-the-fly. - -> This package is experimental and still under development, thus do not use it for applications in production. - -NOTE: **The "in_place" mode has been deprecated and no new features will be added. It's recommended to use it only for prototyping and use "file" mode for production level projects.** +**Data Class Plugin** code generator powered by `Tachyon`. --- @@ -20,7 +16,6 @@ NOTE: **The "in_place" mode has been deprecated and no new features will be adde - [How it works](#how-it-works) - [Installation](#installation) -- [File generation](#file-generation) - [Generate the code you want](#generate-the-code-you-want) - [DataClass Annotation](#dataclass-annotation) - [Union Annotation](#union-annotation) @@ -29,7 +24,7 @@ NOTE: **The "in_place" mode has been deprecated and no new features will be adde - [Configuration](#configuration) - [Configuration file](#configuration-file) - [Available options](#available-options) - - [Configuration examples](#configuration-examples) + - [Configuration examples](#configuration-supported-values) - [Notes](#notes) - [Examples](#examples) - [Development](#development) @@ -39,17 +34,37 @@ NOTE: **The "in_place" mode has been deprecated and no new features will be adde ## How it works -**Data Class Plugin** uses the [analyzer](https://pub.dev/packages/analyzer) system and [analyzer plugin](https://pub.dev/packages/analyzer_plugin) -to get access on the source code, parse it and provide actions based on that. +**Data Class Plugin** uses `Tachyon` as it's build engine to provide fast code generation. Also this plugin uses the [analyzer](https://pub.dev/packages/analyzer) system and [analyzer plugin](https://pub.dev/packages/analyzer_plugin) +to get access on the source code, parse it and provide `code actions` based on that. + +These `code actions` are similar to the ones provide by the language - e.g. `wrap with try/catch` - so you don't need to rely on snippets or manually typing any boilerplate code. ## Installation -1. In your project's pubspec.yaml add on `dependencies` the following +1. In your project's `pubspec.yaml` add + ```yaml dependencies: - data_class_plugin: ^0.2.0 + data_class_plugin: any + + dev_dependencies: + tachyon: any ``` -1. Update your `analysis_options.yaml` _(in case you don't have it, just create a new one)_ + +1. Create `tachyon_config.yaml` on the project's root folder + + ```yaml + file_generation_paths: # which files/paths to include for build + - "file/path/to/watch" + - "another/one" + + generated_file_line_length: 80 # default line length + + plugins: + - data_class_plugin # register data_class_plugin + ``` + +1. Update your `analysis_options.yaml` (to enable `code action`) **Minimal analysis_options.yaml** @@ -82,17 +97,16 @@ to get access on the source code, parse it and provide actions based on that. ### DataClass Annotation -1. Create a simple class, annotate it with `@DataClass()` and provide `final public` fields for your model. +1. Create a simple class, annotate it with `@DataClass()` and provide `abstract getter` fields for your model. ```dart @DataClass() class User { - final String id; - final String username; + String get id; + String get username; } ``` -1. Place the cursor anywhere inside the `User` class 1. Run code actions on your IDE VSCode @@ -105,94 +119,33 @@ to get access on the source code, parse it and provide actions based on that. 1. **Windows/Linux:** Alt + Enter 1. **MacOS:** ⌘ + Enter -1. Select `Generate data class` - - - -Available methods are: - -1. **copyWith** +1. Select `Generate data/union classes` - Generates a new instance of the class with optionally provide new fields values. + - _If no value is provided (default), then **true** is assumed._ +This will generate all the boilerplate code on the source file. - ```dart - MyClass copyWith(...) { ... } - ``` - -1. **hashAndEquals** - - Implements hashCode and equals methods. +Hint: _Fields declared with final (e.g. final String id;) will be automatically coverters to abstract getters._ - _If no value is provided (default), then **true** is assumed._ +Now to generate the part file code (part directive inserted by the code action) you need to run tachyon. - ```dart - @override - bool operator ==(Object other) { ... } - - @override - int get hashCode { ... } - ``` +Executing tachyon: -1. **$toString** +`dart run tachyon build` - Implements toString method. +See more options about tachyon by executing: `dart run tachyon --help` - _If no value is provided (default), then **true** is assumed._ +**Note**: _As you can see on the screenshot `@DataClass` annotations provides a variety of options to choose from. While this is ok, in many cases you might prefer to set these options on `path match` or `project level`._ - ```dart - @override - String toString() { ... } - ``` - -1. **fromJson** - - Generates a factory constructor that creates a new instance from a Map. - - _If no value is provided (default), then **false** is assumed._ - - ```dart - factory MyClass.fromJson(Map json) { ... } - ``` - -1. **toJson** - - Generates a function that coverts this instance to a Map. - - _If no value is provided (default), then **false** is assumed._ - - ```dart - Map toJson() { ... } - ``` - -_This configuration can be overriden in `data_class_plugin_options.yaml`, see [Configuration](#Configuration)_. +_Check [Configuration](#Configuration) section to find more option about `data_class_plugin_options.yaml`_ ### Union Annotation Adding this annotation to a class enables it to create union types. - - -Available union annotation toggles are: - -1. **dataClass** - - Toggles code generation for **toString**, **copyWith**, **equals** and **hashCode**. - - _If no value is provided (default), then **true** is assumed._ - -1. **toJson** - - Toggles code generation for **fromJson**. - - _If no value is provided (default), then **true** is assumed._ + -1. **fromJson** - - Toggles code generation for **toJson**. - - _If no value is provided (default), then **true** is assumed._ +_This configuration can be overriden in `data_class_plugin_options.yaml`, see [Configuration](#Configuration)_. ### Enum Annotation @@ -206,56 +159,9 @@ Available union annotation toggles are: } ``` -1. Place the cursor anywhere inside the `Category` enum - -1. Run code actions on your IDE - - VSCode - - 1. **Windows/Linux:** Ctrl + . - 1. **MacOS:** ⌘ + . - - Intellij - - 1. **Windows/Linux:** Alt + Enter - 1. **MacOS:** ⌘ + Enter - 1. Select `Generate enum` - - -Available methods are: - -1. **$toString** - - Implements toString method. - - _If no value is provided (default), then **true** is assumed._ - - ```dart - @override - String toString() { ... } - ``` - -1. **fromJson** - - Generates a factory constructor that creates a new instance from a Map. - - _If no value is provided (default), then **false** is assumed._ - - ```dart - factory MyClass.fromJson(Map json) { ... } - ``` - -1. **toJson** - - Generates a function that coverts this instance to a Map. - - _If no value is provided (default), then **false** is assumed._ - - ```dart - Map toJson() { ... } - ``` + _This configuration can be overriden in `data_class_plugin_options.yaml`, see [Configuration](#Configuration)_. @@ -276,23 +182,13 @@ Even if you don't use the `@Enum()` annotation, you can still generate methods i 1. Run code actions on your IDE - VSCode - - 1. **Windows/Linux:** Ctrl + . - 1. **MacOS:** ⌘ + . - - Intellij - - 1. **Windows/Linux:** Alt + Enter - 1. **MacOS:** ⌘ + Enter - 1. A list with the following actions will be displayed 1. Generate constructor 1. Generate 'fromJson' 1. Generate 'toJson' 1. Generate 'toString' -> Enums can have an optional single field of primary type to be used in the _fromJson_ or _toJson_ transforms, +> Enums can have an optional single field of primitive type to be used in the _fromJson_ or _toJson_ transforms, > if not provided then the `.name` is used as the default json value. ```dart @@ -304,70 +200,18 @@ enum Category { } ``` - - ## Json Converters The plugin exposes a json converter registrant that be used through out the app to register your custom converters. This eliminates the need to annotate every single field with a custom converter like (json_serializable). By default the plugin provides 3 converters for the following classes: Duration, DateTime, Uri. -In case you want to override the default implementation of these converters you can do it by registering your custom converter with `jsonConverterRegistrant.register(cosnt MyCustomConverter())`. For more info on how to create and register a converter, see this [example](example/lib/json_converter.dart) +In case you want to override the default implementation of these converters you can do it by registering your custom converter with `jsonConverterRegistrant.register(const MyCustomConverter())`. For more info on how to create and register a converter, see this [example](examples/file_generation_mode/lib/data_class/from_json/custom_json_converter.dart) In case you want to provide a custom implementation for a single field that might contain complex logic for parsing/conversion you can use a [JsonConverter](lib/src/json_converter/json_converter.dart) implementation and annotate the specific field with the implementer class. See [example](example/lib/json_converter.dart) on `ClassWithLatLngConverterAnnotation` class. If implementing a `JsonConverter` is too complex for your case you can use the `JsonKey` `fromJson/toJson` functions. -## File generation - -In this mode most of the code generation happens on a generated file. - -You still need to generate some boilerplate code on the main class via actions, -but most of the code now is generated into a different file (like build_runner). - -The generated file has the format of `base_filename.gen.dart` - -To start with this mode you need to: - -1. Update data_class_plugin_options.yaml (See more options) - -```yaml -generation_mode: file (default in_place) - -# This option is **required** if **generation_mode** is "file" -# Specify which path matches should generate files -# If you update this option, you should re-run the generator -# or if it's for a specific folder/file(s) you are working on, you can update this without restarting -file_generation_paths: - - "a/glob/here" - - "an/oth/er/*.dart" - -# If you commit the generated files in git -# You can set the line length for the generated code too, so it won't fail in potential CI/CD workflows -generated_file_line_length: 80 (default) -``` - -1. Add a class - -```dart -@DataClass() -class User { - - String get id; - String get username; - - @DefaultValue('') - String get email; -} -``` - -Run the code actions like described previously. - -The actions will generate for you the constructor, methods and the part directive. - -Save the file and run the data_class_plugin CLI to generate -`dart run data_class_plugin generate ` - ## Configuration You can customize the generated code produced by **Data Class Plugin**. @@ -391,28 +235,19 @@ To create a custom configuration you need to add a file named `data_class_plugin Set the default values for the provided methods of the `@DataClass` annotation, by specifying the directories where they will be enabled or disabled. +1. `union` + + Set the default values for the provided methods of the `@Union` annotation, + by specifying the directories where they will be enabled or disabled. + 1. `enum` Set the default values for the provided methods of the `@Enum` annotation, by specifying the directories where they will be enabled or disabled. -#### Configuration examples +#### Configuration supported values ```yaml -generation_mode: in_place (default) | file - -# This option is **required** if **generation_mode** is "file" -# Which path matches should generate files -# If you update this option, you should re-run the genenator -# or if it's for a specific folder/file(s) you are working on, you can update this without restarting -file_generation_paths: - - "a/glob/here" - - "an/oth/er/*.dart" - -# If you commit the generated files in git -# You can set the line length for the generated code too, so it won't fail in potential CI/CD workflows -generated_file_line_length: 80 (default) - json: # Default naming convention for json keys key_name_convention: camel_case (default) | snake_case | kebab_case | pascal_case @@ -432,11 +267,11 @@ data_class: # Default values for each options # copy_with (true), hash_and_equals (true), to_string (true), from_json (false),to_json (false), unmodifiable_collections (true) : - default: boolean - enabled: + default: boolean # default value is there is no match in enabled or disabled lists + enabled: # list of globs - "a/glob/here" - "another/glob/here" - disabled: + disabled: # list of globs - "a/glob/here" - "another/glob/here" @@ -445,13 +280,13 @@ union: # For each of the provided methods you can provide a configuration # The configuration can be an enabled or disabled field that contains a list of globs # Default values for each options - # copy_with (false), hash_and_equals (true), to_string (true) from_json(false), to_json (false), unmodifiable_collections (true) - : - default: boolean - enabled: + # copy_with (false), hash_and_equals (true), to_string (true) from_json(false), to_json (false), unmodifiable_collections (true), when (true) + : + default: boolean # default value is there is no match in enabled or disabled lists + enabled: # list of globs - "a/glob/here" - "another/glob/here" - disabled: + disabled: # list of globs - "a/glob/here" - "another/glob/here" @@ -462,11 +297,11 @@ enum: # Default values for each options # to_string (false), from_json(false), to_json (false) : - default: boolean - enabled: + default: boolean # default value is there is no match in enabled or disabled lists + enabled: # list of globs - "a/glob/here" - "another/glob/here" - disabled: + disabled: # list of globs - "a/glob/here" - "another/glob/here" ``` diff --git a/package/bin/data_class_plugin.dart b/package/bin/data_class_plugin.dart deleted file mode 100644 index 9b1924a..0000000 --- a/package/bin/data_class_plugin.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'package:data_class_plugin/src/cli.dart'; -import 'package:data_class_plugin/src/exceptions.dart'; -import 'package:path/path.dart' as path; - -Future main(List args) async { - try { - await CliRunner().run(args); - exitCode = 0; - } on DcpException catch (e) { - e.when( - pubspecYamlNotFound: () { - stdout - .writeln('No pubspec.yaml found.. Run this command on the root folder of your project'); - }, - dartToolFolderNotFound: () { - stdout.writeln('Run "${Platform.executable} pub get" before running this tool'); - }, - requiresFileGenerationMode: () { - stdout.writeln('Code generation mode is set as "in_place"'); - }, - packageNotFound: (DcpExceptionPackageNotFound exception) { - final String executableBasename = path.basename(Platform.executable).toLowerCase(); - final bool isDartOrFlutterExecutable = - executableBasename == 'dart' || executableBasename == 'flutter'; - stdout - ..writeln() - ..writeln('Package ${exception.packageName} is not installed.') - ..writeln('To fix this either: ') - ..writeln( - ' 1. Run "${isDartOrFlutterExecutable ? executableBasename : ''} pub get"', - ) - ..writeln(' 2. Remove any imports related to "${exception.packageName}"'); - }, - missingDataClassPluginImport: (DcpExceptionMissingDataClassPluginImport exception) {}, - ); - - exitCode = 1; - } on UsageException catch (e) { - stdout - ..writeln(e.message) - ..writeln() - ..writeln(e.usage); - - exitCode = 1; - } -} diff --git a/package/data_class_plugin_options.yaml b/package/data_class_plugin_options.yaml index 8895a9c..6ee4501 100644 --- a/package/data_class_plugin_options.yaml +++ b/package/data_class_plugin_options.yaml @@ -1,13 +1,3 @@ -generation_mode: file - -file_generation_paths: - - "lib/src/options/**" - - "lib/src/backend/core/find_package_path_by_import.dart" - - "lib/src/backend/core/parsed_file_data.dart" - - "lib/src/exceptions.dart" - -generated_file_line_length: 100 - json: # key_name_conventions glob match takes precedence over key_name_convention key_name_conventions: diff --git a/package/lib/plugin.dart b/package/lib/analyzer_plugin.dart similarity index 100% rename from package/lib/plugin.dart rename to package/lib/analyzer_plugin.dart diff --git a/package/lib/src/analyzer_plugin/analyzer_plugin.dart b/package/lib/src/analyzer_plugin/analyzer_plugin.dart index 171b2dd..d67af06 100644 --- a/package/lib/src/analyzer_plugin/analyzer_plugin.dart +++ b/package/lib/src/analyzer_plugin/analyzer_plugin.dart @@ -4,11 +4,10 @@ import 'package:analyzer_plugin/plugin/assist_mixin.dart'; import 'package:analyzer_plugin/plugin/plugin.dart'; import 'package:analyzer_plugin/utilities/assist/assist.dart'; import 'package:data_class_plugin/src/contributors/class/class_contributors.dart'; -import 'package:data_class_plugin/src/contributors/common/to_string_assist_contributor.dart'; import 'package:data_class_plugin/src/contributors/enum/enum_contributors.dart'; -class DataClassPlugin extends ServerPlugin with AssistsMixin, DartAssistsMixin { - DataClassPlugin( +class DcpAnalyzerPlugin extends ServerPlugin with AssistsMixin, DartAssistsMixin { + DcpAnalyzerPlugin( final analyzer.ResourceProvider resourceProvider, ) : super(resourceProvider: resourceProvider); @@ -43,10 +42,6 @@ class DataClassPlugin extends ServerPlugin with AssistsMixin, DartAssistsMixin { EnumConstructorAssistContributor(path), EnumFromJsonAssistContributor(path), EnumToJsonAssistContributor(path), - - // Common contributors - ToStringAssistContributor(path), - // UnionAssistContributor(path), ]; } diff --git a/package/lib/src/analyzer_plugin/analyzer_plugin_starter.dart b/package/lib/src/analyzer_plugin/analyzer_plugin_starter.dart index 808750d..ff4d2f8 100644 --- a/package/lib/src/analyzer_plugin/analyzer_plugin_starter.dart +++ b/package/lib/src/analyzer_plugin/analyzer_plugin_starter.dart @@ -5,7 +5,7 @@ import 'package:analyzer_plugin/starter.dart'; import 'package:data_class_plugin/src/analyzer_plugin/analyzer_plugin.dart'; void start(Iterable args, SendPort sendPort) { - ServerPluginStarter(DataClassPlugin( + ServerPluginStarter(DcpAnalyzerPlugin( PhysicalResourceProvider.INSTANCE, )).start(sendPort); } diff --git a/package/lib/src/analyzer_plugin/web_socket_plugin_server.dart b/package/lib/src/analyzer_plugin/web_socket_plugin_server.dart index 2f467dc..175c948 100644 --- a/package/lib/src/analyzer_plugin/web_socket_plugin_server.dart +++ b/package/lib/src/analyzer_plugin/web_socket_plugin_server.dart @@ -4,7 +4,7 @@ import 'dart:io'; import 'package:analyzer_plugin/channel/channel.dart'; import 'package:analyzer_plugin/protocol/protocol.dart'; -import 'package:data_class_plugin/src/tools/logger/logger.dart'; +import 'package:tachyon/tachyon.dart'; // https://simonbinder.eu/posts/debugging_analysis_server_plugins/ diff --git a/package/lib/src/annotations/union.dart b/package/lib/src/annotations/union.dart index 1e54472..fc74ba3 100644 --- a/package/lib/src/annotations/union.dart +++ b/package/lib/src/annotations/union.dart @@ -26,6 +26,8 @@ class Union { this.unionJsonKey, this.unionFallbackJsonValue, this.unmodifiableCollections, + this.toJsonNamedKeyToFactoryName, + this.when, }); /// Toggles code generation for copyWith @@ -64,6 +66,35 @@ class Union { final String? unionFallbackJsonValue; final bool? unmodifiableCollections; + + /// Wraps the union fields into a new object with a key named after the factory + /// + /// ``` + /// @Union() + /// class Result{ + /// factory Result.data(int value) = ResultData; + /// + /// Map toJson(); + /// } + /// ... + /// + /// // toJson call this produce + /// + /// { + /// "data": { + /// "value": value + /// } + /// } + /// + /// instead of + /// + /// { + /// "value": value + /// } + /// ``` + final String? toJsonNamedKeyToFactoryName; + + final bool? when; } class UnionJsonKeyValue { diff --git a/package/lib/src/backend/code_generator.dart b/package/lib/src/backend/code_generator.dart index b93baed..300141c 100644 --- a/package/lib/src/backend/code_generator.dart +++ b/package/lib/src/backend/code_generator.dart @@ -1,405 +1,99 @@ import 'dart:async'; -import 'dart:io'; -import 'package:analyzer/dart/analysis/features.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:dart_style/dart_style.dart'; import 'package:data_class_plugin/src/annotations/constants.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_object.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_finder.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/find_package_path_by_import.dart'; import 'package:data_class_plugin/src/backend/core/generators/generators.dart'; import 'package:data_class_plugin/src/backend/core/generators/union_from_json.dart'; import 'package:data_class_plugin/src/backend/core/generators/union_when.dart'; -import 'package:data_class_plugin/src/backend/core/packages_dependency_graph.dart'; -import 'package:data_class_plugin/src/backend/core/parse_file_extension.dart'; -import 'package:data_class_plugin/src/backend/core/parsed_file_data.dart'; -import 'package:data_class_plugin/src/backend/core/parsed_files_registry.dart'; import 'package:data_class_plugin/src/backend/core/utils.dart' as utils; -import 'package:data_class_plugin/src/common/code_writer.dart'; -import 'package:data_class_plugin/src/common/utils.dart' as common_utils; import 'package:data_class_plugin/src/common/utils.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; -import 'package:data_class_plugin/src/tools/logger/plugin_logger.dart'; import 'package:data_class_plugin/src/typedefs.dart'; -import 'package:data_class_plugin/src/visitors/visitors.dart'; -import 'package:glob/glob.dart'; import 'package:path/path.dart' as path; -import 'package:rxdart/rxdart.dart'; -import 'package:watcher/watcher.dart'; - -final RegExp _dartFileNameMatcher = RegExp(r'^[a-zA-Z0-9_]+.dart$'); - -class CodeGenerator { - CodeGenerator({ - required this.directory, - PluginLogger? logger, - }) : _watcher = DirectoryWatcher(directory.path), - _logger = logger ?? PluginLogger(); - - final Directory directory; - final PluginLogger _logger; - final Watcher _watcher; - - final Map?> _activeWrites = ?>{}; - final DependencyGraph _dependencyGraph = DependencyGraph(); - final ParsedFilesRegistry _filesRegistry = ParsedFilesRegistry(); - - late final DeclarationFinder _declarationFinder = DeclarationFinder( - projectDirectoryPath: directory.path, - parsedFilesRegistry: _filesRegistry, - dependencyGraph: _dependencyGraph, - ); - - StreamSubscription? _watchSubscription; - - List get registeredFiles => _filesRegistry.keys.toList(growable: false); - - /// Watches this project for any files changes and rebuilds when necessary - Future watchProject({ - void Function()? onReady, - }) async { - final Completer completer = Completer(); - await indexProject(); - await buildProject(); - _watchSubscription = _watcher.events - .debounceTime(const Duration(milliseconds: 100)) - .listen(_onWatchEvent, onDone: () { - completer.complete(); - }); - await _watcher.ready; - onReady?.call(); - return completer.future; - } - - Future dispose() async { - await _watchSubscription?.cancel(); - } - - /// Indexes the project and creates links between source files - /// - /// [force] clears any previous indexing - Future indexProject({bool forceClear = false}) async { - _logger.info('~ Indexing project..'); - - if (forceClear) { - _filesRegistry.clear(); - _dependencyGraph.clear(); - } - - final Stopwatch stopwatch = Stopwatch()..start(); - - final DataClassPluginOptions pluginOptions = - await DataClassPluginOptions.fromFile(getDataClassPluginOptionsFile(directory.path)); - - final Iterable dartFiles = directory - .listSync(recursive: true) // - .where((FileSystemEntity entity) { - if (entity is! File || !_dartFileNameMatcher.hasMatch(path.basename(entity.path))) { - return false; - } - - return pluginOptions.allowedFilesGenerationPaths.any((Glob glob) { - return glob.matches( - path.relative(entity.absolute.path, from: directory.absolute.path), - ); - }); - }).cast(); - - Future index({ - required String targetFilePath, - required CompilationUnit compilationUnit, - }) async { - for (final Directive directive in compilationUnit.directives) { - String? directiveUri; - if (directive is NamespaceDirective) { - directiveUri = directive.uri.stringValue; - } - - if (directiveUri == null) { - continue; - } - - final String? dartFilePath = await findDartFileFromUri( - projectDirectoryPath: directory.path, - currentDirectoryPath: File(targetFilePath).parent.absolute.path, - uri: directiveUri, - ); - - if (dartFilePath == null || !File(dartFilePath).existsSync()) { - continue; - } - - if (_filesRegistry.containsKey(dartFilePath)) { - _dependencyGraph.add( - targetFilePath, - dartFilePath, - ); - continue; - } - - if (path.isWithin(directory.path, dartFilePath)) { - _dependencyGraph.add(targetFilePath, dartFilePath); - _filesRegistry[dartFilePath] = ParsedFileData( - absolutePath: dartFilePath, - compilationUnit: - dartFilePath.parse(featureSet: FeatureSet.latestLanguageVersion()).unit, - lastModifiedAt: File(dartFilePath).lastModifiedSync(), - ); - - await index( - targetFilePath: dartFilePath, - compilationUnit: _filesRegistry[dartFilePath]!.compilationUnit, - ); - } - } - } - - for (final File file in dartFiles) { - final String targetFilePath = file.absolute.path; - - if (_filesRegistry.containsKey(targetFilePath)) { - continue; - } - - _filesRegistry[targetFilePath] = ParsedFileData( - absolutePath: targetFilePath, - compilationUnit: targetFilePath.parse(featureSet: FeatureSet.latestLanguageVersion()).unit, - lastModifiedAt: file.lastModifiedSync(), - ); - - await index( - targetFilePath: targetFilePath, - compilationUnit: _filesRegistry[targetFilePath]!.compilationUnit, - ); - } - - stopwatch.stop(); - _logger.info('~ Indexed ${_filesRegistry.length} files in ${stopwatch.elapsedMilliseconds}ms'); - } - - /// Builds the project - /// - /// **Project must be indexed before it can correctly build** - Future buildProject() async { - _logger.info('~ Building project..'); - final Stopwatch stopwatch = Stopwatch()..start(); - - for (final MapEntry entry in _filesRegistry.entries) { - final String targetFilePath = entry.key; - await _generateCode( - targetFilePath: targetFilePath, - outputFilePath: targetFilePath.replaceFirst('.dart', '.gen.dart'), - compilationUnit: entry.value.compilationUnit, - ); - } - - stopwatch.stop(); - _logger.info('~ Completed build in ${stopwatch.elapsed.inMilliseconds}ms..'); - } - - void _onWatchEvent(WatchEvent event) async { - final String targetFilePath = path.normalize(event.path); - Completer? completer; +import 'package:tachyon/tachyon.dart'; +class DataClassPluginGenerator extends TachyonPluginCodeGenerator { + DataClassPluginOptions _getPluginOptionWithDefaultFallback(String projectDirPath) { try { - if (!_dartFileNameMatcher.hasMatch(path.basename(targetFilePath))) { - return; - } - - final String outputFilePath = targetFilePath.replaceFirst('.dart', '.gen.dart'); - await _activeWrites[outputFilePath]?.future; - - completer = Completer(); - _activeWrites[outputFilePath] = completer; - - if (event.type == ChangeType.REMOVE) { - try { - await File(outputFilePath).delete(); - } catch (_) {} - - return; - } - - await _generateCode(targetFilePath: targetFilePath, outputFilePath: outputFilePath); - } catch (error, stackTrace) { - _logger.exception(error, stackTrace); - } finally { - completer?.safeComplete(); + return DataClassPluginOptions.fromFile(getDataClassPluginOptionsFile( + projectDirPath, + )); + } catch (_) { + return const DataClassPluginOptions(); } } - Future _generateCode({ - required String targetFilePath, - required String outputFilePath, - bool skipDependencies = false, - CompilationUnit? compilationUnit, - String indent = '', - bool reportTime = true, - }) async { - final String relativeFilePath = path.relative(targetFilePath, from: directory.path); - final DataClassPluginOptions pluginOptions = await DataClassPluginOptions.fromFile( - common_utils.getDataClassPluginOptionsFile(directory.path)); - - if (!pluginOptions.allowedFilesGenerationPaths - .any((Glob glob) => glob.matches(relativeFilePath))) { - return; - } - - _logger.debug('$indent~ Checking $relativeFilePath'); - - late final Stopwatch? stopwatch; - if (reportTime) { - stopwatch = Stopwatch()..start(); - } else { - stopwatch = null; - } - - CodeWriter codeWriter = CodeWriter.stringBuffer(); - - if (compilationUnit == null) { - _filesRegistry[targetFilePath] = ParsedFileData( - absolutePath: targetFilePath, - compilationUnit: targetFilePath.parse(featureSet: FeatureSet.latestLanguageVersion()).unit, - lastModifiedAt: await File(targetFilePath).lastModified(), - ); - } - - compilationUnit ??= _filesRegistry[targetFilePath]!.compilationUnit; - + @override + FutureOr generate( + FileChangeBuildInfo buildInfo, + TachyonDeclarationFinder declarationFinder, + Logger logger, + ) async { + final CodeWriter codeWriter = CodeWriter.stringBuffer(); final ClassCollectorAstVisitor classCollectorVisitor = ClassCollectorAstVisitor(matcher: (ClassDeclaration node) { return node.metadata .any((Annotation meta) => meta.isDataClassAnnotation || meta.isUnionAnnotation); }); - compilationUnit.visitChildren(classCollectorVisitor); - - final List classDeclarations = classCollectorVisitor.matchedNodes; - - if (classDeclarations.isEmpty) { - final File outputFile = File(outputFilePath); - if (await outputFile.exists()) { - try { - await outputFile.delete(); - } catch (_) {} - } + buildInfo.compilationUnit.visitChildren(classCollectorVisitor); - if (!skipDependencies) { - await _rebuildDependants(targetFilePath: targetFilePath, indent: indent); - } - - if (reportTime) { - stopwatch!.stop(); - _logger.info( - '$indent~ Finished building $relativeFilePath in ${stopwatch.elapsed.inMilliseconds}ms'); - } - return; - } - - final List dataClasses = classDeclarations + final List dataClasses = classCollectorVisitor.matchedNodes .where((ClassDeclaration classDecl) => classDecl.hasDataClassAnnotation) .toList(growable: false); - final List unionClasses = classDeclarations + final List unionClasses = classCollectorVisitor.matchedNodes .where((ClassDeclaration classDecl) => classDecl.hasUnionAnnotation) .toList(growable: false); - _logger.debug('$indent~ Starting build for $relativeFilePath'); + final DataClassPluginOptions pluginOptions = + _getPluginOptionWithDefaultFallback(buildInfo.projectDirectoryPath); final JsonKeyNameConventionGetter jsonKeyNameConventionGetter = utils.getJsonKeyNameConvention( - targetFileRelativePath: path.relative(targetFilePath), + targetFileRelativePath: path.relative(buildInfo.targetFilePath), pluginOptions: pluginOptions, ); - codeWriter - ..writeln('// AUTO GENERATED - DO NOT MODIFY') - ..writeln() - ..writeln( - '// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field') - ..writeln() - ..writeln("part of '${path.basename(targetFilePath)}';") - ..writeln(); - await _generateDataClasses( + buildInfo: buildInfo, + declarationFinder: declarationFinder, codeWriter: codeWriter, pluginOptions: pluginOptions, - compilationUnit: compilationUnit, + compilationUnit: buildInfo.compilationUnit, classDeclarations: dataClasses, - targetFilePath: targetFilePath, - targetFileRelativePath: relativeFilePath, + targetFilePath: buildInfo.targetFilePath, + targetFileRelativePath: + path.relative(buildInfo.targetFilePath, from: buildInfo.projectDirectoryPath), jsonKeyNameConventionGetter: jsonKeyNameConventionGetter, + logger: logger, ); await _generateUnionClasses( + buildInfo: buildInfo, + declarationFinder: declarationFinder, codeWriter: codeWriter, pluginOptions: pluginOptions, - compilationUnit: compilationUnit, + compilationUnit: buildInfo.compilationUnit, classDeclarations: unionClasses, - targetFilePath: targetFilePath, - targetFileRelativePath: relativeFilePath, + targetFilePath: buildInfo.targetFilePath, + targetFileRelativePath: + path.relative(buildInfo.targetFilePath, from: buildInfo.projectDirectoryPath), jsonKeyNameConventionGetter: jsonKeyNameConventionGetter, + logger: logger, ); - final String content = codeWriter.content; - if (content.isEmpty) { - try { - await File(outputFilePath).delete(); - } catch (_) {} - } else { - try { - await File(outputFilePath).writeAsString(DartFormatter( - pageWidth: pluginOptions.generatedFileLineLength, - ).format(content)); - } on FormatterException catch (e) { - _logger - ..error('Invalid code generation for $relativeFilePath') - ..writeln(e); - } - } - - if (!skipDependencies) { - await _rebuildDependants(targetFilePath: targetFilePath, indent: indent); - } - - if (reportTime) { - stopwatch!.stop(); - _logger.info( - '$indent~ Finished building $relativeFilePath in ${stopwatch.elapsed.inMilliseconds}ms'); - } - } - - Future _rebuildDependants({ - required final String targetFilePath, - required final String indent, - }) async { - final List dependants = _dependencyGraph.getDependants(targetFilePath); - if (dependants.isEmpty) { - return; - } - - _logger.debug(' Rebuilding ${dependants.length} depandants..'); - await Future.wait(>[ - for (final String dependency in dependants) - _generateCode( - targetFilePath: dependency, - outputFilePath: dependency.replaceFirst('.dart', '.gen.dart'), - compilationUnit: _filesRegistry[dependency]?.compilationUnit, - indent: ' $indent', - skipDependencies: true, - reportTime: false, - ) - ]); + return codeWriter.content; } Future _generateDataClasses({ - required CodeWriter codeWriter, - required DataClassPluginOptions pluginOptions, - required CompilationUnit compilationUnit, - required List classDeclarations, - required String targetFilePath, - required String targetFileRelativePath, - required JsonKeyNameConventionGetter jsonKeyNameConventionGetter, + required final FileChangeBuildInfo buildInfo, + required final TachyonDeclarationFinder declarationFinder, + required final CodeWriter codeWriter, + required final DataClassPluginOptions pluginOptions, + required final CompilationUnit compilationUnit, + required final List classDeclarations, + required final String targetFilePath, + required final String targetFileRelativePath, + required final JsonKeyNameConventionGetter jsonKeyNameConventionGetter, + required final Logger logger, }) async { for (final ClassDeclaration classDeclaration in classDeclarations) { final String className = classDeclaration.name.lexeme; @@ -476,14 +170,8 @@ class CodeGenerator { generatedClassName: generatedClassName, classTypeParametersWithoutConstraints: classTypeParametersWithoutConstraints, jsonKeyNameConventionGetter: jsonKeyNameConventionGetter, - classDeclarationFinder: (String name) { - return _declarationFinder.findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - }, - logger: _logger, + classDeclarationFinder: declarationFinder.findClassOrEnum, + logger: logger, ).execute(); } @@ -493,14 +181,8 @@ class CodeGenerator { codeWriter: codeWriter, fields: fields, jsonKeyNameConventionGetter: jsonKeyNameConventionGetter, - classDeclarationFinder: (String name) { - return _declarationFinder.findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - }, - logger: _logger, + classDeclarationFinder: declarationFinder.findClassOrEnum, + logger: logger, ).execute(); } @@ -541,15 +223,11 @@ class CodeGenerator { // If that case is true then override the config for copyWith for the current class // as it would not make sense to have copyWith for super class and not a subclass if (classDeclaration.extendsClause?.superclass != null) { - final String superClassName = classDeclaration.extendsClause!.superclass.name.name; + final String superClassName = classDeclaration.extendsClause!.superclass.name2.lexeme; final ClassOrEnumDeclarationMatch? superClassMatch = - await _declarationFinder.findClassOrEnumDeclarationByName( - superClassName, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - + await declarationFinder.findClassOrEnum(superClassName); final NamedCompilationUnitMember? superClassDeclaration = superClassMatch?.node; + if (superClassDeclaration is ClassDeclaration && superClassDeclaration.hasDataClassAnnotation) { final AnnotationValueExtractor annotationValueExtractor = AnnotationValueExtractor( @@ -562,13 +240,12 @@ class CodeGenerator { } if (supportsCopyWith != null) { - _logger.warning( + logger.warning( '~ Overriden copyWith configuration for class <$className> based on super class <$superClassName>'); } } supportsCopyWith ??= dataClassAnnotationValueExtractor.getBool('copyWith') ?? - pluginOptions.dataClass - .effectiveCopyWith(path.relative(targetFileRelativePath, from: directory.path)); + pluginOptions.dataClass.effectiveCopyWith(targetFileRelativePath); if (supportsCopyWith) { await CopyWithGenerator( @@ -578,14 +255,8 @@ class CodeGenerator { generatedClassName: generatedClassName, classTypeParametersSource: classTypeParametersSource, classTypeParametersWithoutConstraints: classTypeParametersWithoutConstraints, - classDeclarationFinder: (String name) { - return _declarationFinder.findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - }, - projectDirectoryPath: directory.path, + classDeclarationFinder: declarationFinder.findClassOrEnum, + projectDirectoryPath: buildInfo.projectDirectoryPath, pluginOptions: pluginOptions, ).execute(); @@ -600,13 +271,16 @@ class CodeGenerator { } Future _generateUnionClasses({ - required CodeWriter codeWriter, - required DataClassPluginOptions pluginOptions, - required CompilationUnit compilationUnit, - required List classDeclarations, - required String targetFilePath, - required String targetFileRelativePath, - required JsonKeyNameConventionGetter jsonKeyNameConventionGetter, + required final FileChangeBuildInfo buildInfo, + required final TachyonDeclarationFinder declarationFinder, + required final CodeWriter codeWriter, + required final DataClassPluginOptions pluginOptions, + required final CompilationUnit compilationUnit, + required final List classDeclarations, + required final String targetFilePath, + required final String targetFileRelativePath, + required final JsonKeyNameConventionGetter jsonKeyNameConventionGetter, + required final Logger logger, }) async { for (final ClassDeclaration classDeclaration in classDeclarations) { final String className = classDeclaration.name.lexeme; @@ -634,13 +308,16 @@ class CodeGenerator { final AnnotationValueExtractor unionAnnotationValueExtractor = AnnotationValueExtractor(classDeclaration.unionAnnotation); - UnionWhenGenerator( - codeWriter: codeWriter, - className: className, - classTypeParametersSource: classTypeParametersSource, - classTypeParametersWithoutConstraints: classTypeParametersWithoutConstraints, - factoriesWithRedirectedConstructors: factoriesWithRedirectedConstructors, - ).execute(); + if (unionAnnotationValueExtractor.getBool('when') ?? + pluginOptions.union.effectiveWhen(targetFileRelativePath)) { + UnionWhenGenerator( + codeWriter: codeWriter, + className: className, + classTypeParametersSource: classTypeParametersSource, + classTypeParametersWithoutConstraints: classTypeParametersWithoutConstraints, + factoriesWithRedirectedConstructors: factoriesWithRedirectedConstructors, + ).execute(); + } if (unionAnnotationValueExtractor.getBool('fromJson') ?? pluginOptions.union.effectiveFromJson(targetFileRelativePath)) { @@ -705,31 +382,24 @@ class CodeGenerator { generatedClassName: generatedClassName, classTypeParametersWithoutConstraints: classTypeParametersWithoutConstraints, jsonKeyNameConventionGetter: jsonKeyNameConventionGetter, - classDeclarationFinder: (String name) { - return _declarationFinder.findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - }, - logger: _logger, + classDeclarationFinder: declarationFinder.findClassOrEnum, + logger: logger, ).execute(); } if (unionAnnotationValueExtractor.getBool('toJson') ?? pluginOptions.union.effectiveToJson(targetFileRelativePath)) { + final String? toJsonNamedKeyToFactoryName = + unionAnnotationValueExtractor.getString('toJsonNamedKeyToFactoryName'); await ToJsonGenerator( codeWriter: codeWriter, fields: fields, jsonKeyNameConventionGetter: jsonKeyNameConventionGetter, - classDeclarationFinder: (String name) { - return _declarationFinder.findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - }, - logger: _logger, + namedKeyToFactoryEntry: toJsonNamedKeyToFactoryName != null + ? "'$toJsonNamedKeyToFactoryName': '${ctor.name!.lexeme}'" + : null, + classDeclarationFinder: declarationFinder.findClassOrEnum, + logger: logger, ).execute(); } @@ -761,8 +431,7 @@ class CodeGenerator { codeWriter.writeln('}'); if (unionAnnotationValueExtractor.getBool('copyWith') ?? - pluginOptions.union - .effectiveCopyWith(path.relative(targetFileRelativePath, from: directory.path))) { + pluginOptions.union.effectiveCopyWith(targetFileRelativePath)) { await CopyWithGenerator( codeWriter: codeWriter, fields: fields, @@ -770,14 +439,8 @@ class CodeGenerator { generatedClassName: generatedClassName, classTypeParametersSource: classTypeParametersSource, classTypeParametersWithoutConstraints: classTypeParametersWithoutConstraints, - classDeclarationFinder: (String name) { - return _declarationFinder.findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - ); - }, - projectDirectoryPath: directory.path, + classDeclarationFinder: declarationFinder.findClassOrEnum, + projectDirectoryPath: buildInfo.projectDirectoryPath, pluginOptions: pluginOptions, ).execute(); diff --git a/package/lib/src/backend/core/custom_dart_object.dart b/package/lib/src/backend/core/custom_dart_object.dart deleted file mode 100644 index e5db469..0000000 --- a/package/lib/src/backend/core/custom_dart_object.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/extensions/extensions.dart'; - -class AnnotationValueExtractor { - AnnotationValueExtractor(this._annotation); - - final Annotation? _annotation; - late final List _arguments = - _annotation?.arguments?.arguments ?? const []; - - @override - String toString() { - return 'AnnotationValueExtractor($_arguments)'; - } - - Expression? getPositionedArgument(int position) { - try { - return _arguments[position]; - } catch (_) { - return null; - } - } - - String? getString(String fieldName) { - final NamedExpression? argument = _findNamedExpressionByName(fieldName); - final Expression? argumentExpression = argument?.expression; - if (argumentExpression is SimpleStringLiteral) { - return argumentExpression.stringValue; - } - return null; - } - - bool? getBool(String fieldName) { - final NamedExpression? argument = _findNamedExpressionByName(fieldName); - final Expression? argumentExpression = argument?.expression; - if (argumentExpression is BooleanLiteral) { - return argumentExpression.value; - } - return null; - } - - String? getEnumValue(String fieldName) { - final NamedExpression? argument = _findNamedExpressionByName(fieldName); - if (argument is NamedExpression && argument.expression is PrefixedIdentifier) { - return (argument.expression as PrefixedIdentifier).identifier.name; - } - return null; - } - - String? getFunction(String fieldName) { - final NamedExpression? argument = _findNamedExpressionByName(fieldName); - if (argument is NamedExpression) { - final Expression argumentExpression = argument.expression; - if (argumentExpression is Identifier) { - return argumentExpression.name; - } - } - return null; - } - - NamedExpression? _findNamedExpressionByName(String name) { - return _arguments.firstWhereOrNull((Expression expression) { - return expression is NamedExpression && expression.name.label.name == name; - }) as NamedExpression?; - } -} diff --git a/package/lib/src/backend/core/custom_dart_type.dart b/package/lib/src/backend/core/custom_dart_type.dart deleted file mode 100644 index e74022b..0000000 --- a/package/lib/src/backend/core/custom_dart_type.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; - -class CustomDartType { - CustomDartType( - this.name, - this.fullTypeName, - this.typeArguments, - ); - - factory CustomDartType._fromTypeAnnotation(TypeAnnotation? typeAnnotation) { - final List typeArguments = []; - - if (typeAnnotation is NamedType) { - final List arguments = - typeAnnotation.typeArguments?.arguments ?? const []; - for (final TypeAnnotation argument in arguments) { - typeArguments.add(argument.customDartType); - } - } - - return CustomDartType( - typeAnnotation?.beginToken.lexeme ?? 'dynamic', - typeAnnotation?.toSource() ?? 'dynamic', - List.unmodifiable(typeArguments), - ); - } - - final String name; - final String fullTypeName; - final List typeArguments; - - static final CustomDartType dynamic = CustomDartType( - 'dynamic', - 'dynamic', - List.unmodifiable(const []), - ); - - bool get isInt => name == 'int'; - - bool get isDouble => name == 'double'; - - bool get isDynamic => name == 'dynamic'; - - bool get isNum => name == 'num'; - - bool get isList => name == 'List'; - - bool get isMap => name == 'Map'; - - bool get isString => name == 'String'; - - bool get isBool => name == 'bool'; - - bool get isDuration => name == 'Duration'; - - bool get isDateTime => name == 'DateTime'; - - bool get isUri => name == 'Uri'; - - bool get isNullable => name == 'dynamic' || fullTypeName.endsWith('?'); - - bool get isPrimary { - return isString || isBool || isDouble || isInt || isNum; - } - - bool get isCollection { - return isList || isMap; - } -} - -extension CoreTypeOnTypeAnnotationX on TypeAnnotation? { - CustomDartType get customDartType => CustomDartType._fromTypeAnnotation(this); -} diff --git a/package/lib/src/backend/core/declaration_finder.dart b/package/lib/src/backend/core/declaration_finder.dart deleted file mode 100644 index 9390eca..0000000 --- a/package/lib/src/backend/core/declaration_finder.dart +++ /dev/null @@ -1,194 +0,0 @@ -import 'dart:io'; - -import 'package:analyzer/dart/analysis/features.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/find_package_path_by_import.dart'; -import 'package:data_class_plugin/src/backend/core/packages_dependency_graph.dart'; -import 'package:data_class_plugin/src/backend/core/parse_file_extension.dart'; -import 'package:data_class_plugin/src/backend/core/parsed_file_data.dart'; -import 'package:data_class_plugin/src/backend/core/parsed_files_registry.dart'; -import 'package:path/path.dart' as path; - -class DeclarationFinder { - DeclarationFinder({ - required final String projectDirectoryPath, - required final ParsedFilesRegistry parsedFilesRegistry, - required final DependencyGraph dependencyGraph, - }) : _projectDirectoryPath = projectDirectoryPath, - _parsedFilesRegistry = parsedFilesRegistry, - _dependencyGraph = dependencyGraph; - - final String _projectDirectoryPath; - final ParsedFilesRegistry _parsedFilesRegistry; - final DependencyGraph _dependencyGraph; - - Future findClassOrEnumDeclarationByName( - String name, { - required CompilationUnit compilationUnit, - required String targetFilePath, - }) async { - return await _findClassOrEnumDeclarationByName( - name, - compilationUnit: compilationUnit, - targetFilePath: targetFilePath, - currentDirectoryPath: File(targetFilePath).parent.absolute.path, - ); - } - - Future _findClassOrEnumDeclarationByName( - String name, { - required CompilationUnit compilationUnit, - required String targetFilePath, - required String currentDirectoryPath, - }) async { - NamedCompilationUnitMember? nodeDeclaration = - _findClassOrEnumDeclaration(name: name, unit: compilationUnit); - if (nodeDeclaration != null) { - return ClassOrEnumDeclarationMatch( - node: nodeDeclaration, - filePath: targetFilePath, - ); - } - - final List parsedFiles = []; - - for (final Directive directive in compilationUnit.directives) { - String? directiveUri; - - if (directive is ImportDirective) { - directiveUri = directive.uri.stringValue; - } - - if (directiveUri == null) { - continue; - } - - final String? dartFilePath = await findDartFileFromUri( - projectDirectoryPath: _projectDirectoryPath, - currentDirectoryPath: currentDirectoryPath, - uri: directiveUri, - ); - - if (dartFilePath == null || !path.isWithin(_projectDirectoryPath, dartFilePath)) { - continue; - } - - final File dartFile = File(dartFilePath); - if (!await dartFile.exists()) { - continue; - } - - final DateTime lastModifiedAt = await dartFile.lastModified(); - - if (!_dependencyGraph.hasDependency(targetFilePath, dartFilePath)) { - _dependencyGraph.add(targetFilePath, dartFilePath); - } - - if (!_parsedFilesRegistry.containsKey(dartFilePath) || - lastModifiedAt.isAfter(_parsedFilesRegistry[dartFilePath]!.lastModifiedAt)) { - _parsedFilesRegistry[dartFilePath] = ParsedFileData( - absolutePath: dartFilePath, - compilationUnit: dartFilePath.parse(featureSet: FeatureSet.latestLanguageVersion()).unit, - lastModifiedAt: lastModifiedAt, - ); - } - - parsedFiles.add(_parsedFilesRegistry[dartFilePath]!); - } - - for (final ParsedFileData parsedFileData in parsedFiles) { - nodeDeclaration = _findClassOrEnumDeclaration( - name: name, - unit: parsedFileData.compilationUnit, - ); - if (nodeDeclaration != null) { - return ClassOrEnumDeclarationMatch( - node: nodeDeclaration, - filePath: parsedFileData.absolutePath, - ); - } - - final ClassOrEnumDeclarationMatch? match = await _recursivelyExploreExports( - name, - currentDirectoryPath: File(parsedFileData.absolutePath).parent.absolute.path, - compilationUnit: parsedFileData.compilationUnit, - ); - if (match != null) { - return match; - } - } - - return null; - } - - Future _recursivelyExploreExports( - String name, { - required String currentDirectoryPath, - required CompilationUnit compilationUnit, - }) async { - for (final Directive directive in compilationUnit.directives) { - if (directive is! ExportDirective) { - continue; - } - - final String? exportDartFilePath = await findDartFileFromUri( - projectDirectoryPath: _projectDirectoryPath, - currentDirectoryPath: currentDirectoryPath, - uri: directive.uri.stringValue!, - ); - - if (exportDartFilePath == null) { - continue; - } - - final ParsedFileData parsedFileData = _parsedFilesRegistry[exportDartFilePath]!; - - NamedCompilationUnitMember? nodeDeclaration = - _findClassOrEnumDeclaration(name: name, unit: parsedFileData.compilationUnit); - if (nodeDeclaration != null) { - return ClassOrEnumDeclarationMatch( - node: nodeDeclaration, - filePath: parsedFileData.absolutePath, - ); - } - - final ClassOrEnumDeclarationMatch? match = await _recursivelyExploreExports( - name, - currentDirectoryPath: File(exportDartFilePath).parent.absolute.path, - compilationUnit: parsedFileData.compilationUnit, - ); - if (match != null) { - return match; - } - } - - return null; - } - - NamedCompilationUnitMember? _findClassOrEnumDeclaration({ - required String name, - required CompilationUnit unit, - }) { - for (final CompilationUnitMember declaration in unit.declarations) { - if (declaration is ClassDeclaration && declaration.name.lexeme == name) { - return declaration; - } - - if (declaration is EnumDeclaration && declaration.name.lexeme == name) { - return declaration; - } - } - return null; - } -} - -class ClassOrEnumDeclarationMatch { - /// Shorthand constructor - ClassOrEnumDeclarationMatch({ - required this.node, - required this.filePath, - }); - - final NamedCompilationUnitMember node; - final String filePath; -} diff --git a/package/lib/src/backend/core/declaration_info.dart b/package/lib/src/backend/core/declaration_info.dart deleted file mode 100644 index 5ccb8c8..0000000 --- a/package/lib/src/backend/core/declaration_info.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; - -class DeclarationInfo { - DeclarationInfo({ - required this.name, - required this.type, - required this.metadata, - required this.isNamed, - required this.isRequired, - required this.isPositional, - }); - - final String name; - final TypeAnnotation? type; - final List metadata; - final bool isNamed; - final bool isRequired; - final bool isPositional; - - bool get isRequiredNamed => isRequired && isNamed; - bool get isRequiredPositional => isRequired && isPositional; -} diff --git a/package/lib/src/backend/core/find_package_path_by_import.dart b/package/lib/src/backend/core/find_package_path_by_import.dart deleted file mode 100644 index fa99eaf..0000000 --- a/package/lib/src/backend/core/find_package_path_by_import.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:data_class_plugin/data_class_plugin.dart'; -import 'package:data_class_plugin/src/exceptions.dart'; -import 'package:data_class_plugin/src/extensions/extensions.dart'; -import 'package:path/path.dart' as path; - -part 'find_package_path_by_import.gen.dart'; - -const String _dartPrefix = 'dart:'; -const String _packagePrefix = 'package:'; - -Future findDartFileFromUri({ - required String projectDirectoryPath, - required String currentDirectoryPath, - required String uri, -}) async { - if (uri.startsWith(_dartPrefix)) { - return null; - } - - if (!uri.startsWith(_packagePrefix)) { - return path.normalize(path.join( - currentDirectoryPath, - uri.toString(), - )); - } - - final List packages = []; - - final File packageConfigFile = - File(path.join(projectDirectoryPath, '.dart_tool', 'package_config.json')); - - if (!await packageConfigFile.exists()) { - throw const DcpException.dartToolFolderNotFound(); - } - - final Map packageConfigJson = - await packageConfigFile.readAsString().then((String value) => jsonDecode(value)); - - packages.addAll([ - for (final Map packageJson in packageConfigJson['packages']) - PackageInfo.fromJson(packageJson) - ]); - - final String packageName = uri.substring(_packagePrefix.length, uri.indexOf('/')); - final PackageInfo? targetPackage = - packages.firstWhereOrNull((PackageInfo package) => package.name == packageName); - - if (targetPackage == null) { - throw DcpException.packageNotFound(packageName: packageName); - } - - return path.normalize( - path.join( - path.isRelative(targetPackage.rootUri.path) - ? projectDirectoryPath - : targetPackage.rootUri.path, - targetPackage.packageUri.path, - // uri format = package:package_name/path/to/file.dart - // we need to extract the 'path/to/file.dart' - uri.substring(1 + uri.indexOf('/')), - ), - ); -} - -@DataClass( - fromJson: true, - $toString: false, - copyWith: false, - hashAndEquals: false, -) -abstract class PackageInfo { - PackageInfo.ctor(); - - /// Default constructor - factory PackageInfo({ - required String name, - required Uri rootUri, - required Uri packageUri, - required String languageVersion, - }) = _$PackageInfoImpl; - - String get name; - - Uri get rootUri; - - Uri get packageUri; - - String get languageVersion; - - /// Creates an instance of [PackageInfo] from [json] - factory PackageInfo.fromJson(Map json) = _$PackageInfoImpl.fromJson; -} diff --git a/package/lib/src/backend/core/find_package_path_by_import.gen.dart b/package/lib/src/backend/core/find_package_path_by_import.gen.dart deleted file mode 100644 index 3477005..0000000 --- a/package/lib/src/backend/core/find_package_path_by_import.gen.dart +++ /dev/null @@ -1,50 +0,0 @@ -// AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field - -part of 'find_package_path_by_import.dart'; - -class _$PackageInfoImpl extends PackageInfo { - _$PackageInfoImpl({ - required this.name, - required this.rootUri, - required this.packageUri, - required this.languageVersion, - }) : super.ctor(); - - @override - final String name; - - @override - final Uri rootUri; - - @override - final Uri packageUri; - - @override - final String languageVersion; - - factory _$PackageInfoImpl.fromJson(Map json) { - return _$PackageInfoImpl( - name: json['name'] as String, - rootUri: jsonConverterRegistrant.find(Uri).fromJson(json['rootUri'], json, 'rootUri') as Uri, - packageUri: - jsonConverterRegistrant.find(Uri).fromJson(json['packageUri'], json, 'packageUri') as Uri, - languageVersion: json['languageVersion'] as String, - ); - } - - @override - String toString() { - String toStringOutput = 'PackageInfo{}'; - assert(() { - toStringOutput = - 'PackageInfo@<$hexIdentity>{name: $name, rootUri: $rootUri, packageUri: $packageUri, languageVersion: $languageVersion}'; - return true; - }()); - return toStringOutput; - } - - @override - Type get runtimeType => PackageInfo; -} diff --git a/package/lib/src/backend/core/generators/constructor.dart b/package/lib/src/backend/core/generators/constructor.dart index af91931..4fd6741 100644 --- a/package/lib/src/backend/core/generators/constructor.dart +++ b/package/lib/src/backend/core/generators/constructor.dart @@ -1,10 +1,6 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_object.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_type.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class ConstructorGenerator implements Generator { ConstructorGenerator({ @@ -14,7 +10,7 @@ class ConstructorGenerator implements Generator { required final String generatedClassName, final bool shouldAnnotateFieldsWithOverride = true, final String? superConstructorName, - required bool generateUnmodifiableCollections, + required final bool generateUnmodifiableCollections, }) : _codeWriter = codeWriter, _constructor = constructor, _fields = fields, @@ -45,10 +41,10 @@ class ConstructorGenerator implements Generator { _fields.where((DeclarationInfo element) => element.isNamed).toList(growable: false); for (final DeclarationInfo field in positionalFields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; - if (_generateUnmodifiableCollections && customDartType.isCollection) { - _codeWriter.write('${customDartType.fullTypeName} ${field.name},'); + if (_generateUnmodifiableCollections && dartType.isCollection) { + _codeWriter.write('${dartType.fullTypeName} ${field.name},'); unmodifiableCollectionsDeclarations.add('_${field.name} = ${field.name}'); } else { _codeWriter.write('this.${field.name},'); @@ -60,7 +56,7 @@ class ConstructorGenerator implements Generator { for (final DeclarationInfo field in namedFields) { final Annotation? defaultValueAnnotation = field.metadata .firstWhereOrNull((Annotation annotation) => annotation.isDefaultValueAnnotation); - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; Expression? defaultValueExpression; late String defaultValuePrefix; @@ -79,8 +75,8 @@ class ConstructorGenerator implements Generator { _codeWriter.write('required '); } - if (_generateUnmodifiableCollections && customDartType.isCollection) { - _codeWriter.write(customDartType.fullTypeName); + if (_generateUnmodifiableCollections && dartType.isCollection) { + _codeWriter.write(dartType.fullTypeName); } else { _codeWriter.write('this.'); } @@ -91,7 +87,7 @@ class ConstructorGenerator implements Generator { _codeWriter.write(' = $defaultValuePrefix ${defaultValueExpression.toSource()}'); } - if (customDartType.isCollection && _generateUnmodifiableCollections) { + if (dartType.isCollection && _generateUnmodifiableCollections) { unmodifiableCollectionsDeclarations.add('_${field.name} = ${field.name}'); } @@ -113,31 +109,31 @@ class ConstructorGenerator implements Generator { _codeWriter.writeln(); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; - if (_generateUnmodifiableCollections && customDartType.isCollection) { + if (_generateUnmodifiableCollections && dartType.isCollection) { _codeWriter ..writeln() ..writeln(_shouldAnnotateFieldsWithOverride ? '@override' : '') - ..write('${customDartType.fullTypeName} get ${field.name} => '); + ..write('${dartType.fullTypeName} get ${field.name} => '); - if (customDartType.isNullable) { + if (dartType.isNullable) { final String notNullableType = - customDartType.fullTypeName.substring(0, customDartType.fullTypeName.length - 1); + dartType.fullTypeName.substring(0, dartType.fullTypeName.length - 1); _codeWriter.write('_${field.name} ?? $notNullableType.unmodifiable(_${field.name}!);'); } else { - _codeWriter.writeln('${customDartType.fullTypeName}.unmodifiable(_${field.name});'); + _codeWriter.writeln('${dartType.fullTypeName}.unmodifiable(_${field.name});'); } _codeWriter - ..writeln('final ${customDartType.fullTypeName} _${field.name};') + ..writeln('final ${dartType.fullTypeName} _${field.name};') ..writeln(); continue; } _codeWriter ..writeln(_shouldAnnotateFieldsWithOverride ? '@override' : '') - ..writeln('final ${customDartType.fullTypeName} ${field.name};') + ..writeln('final ${dartType.fullTypeName} ${field.name};') ..writeln(); } diff --git a/package/lib/src/backend/core/generators/copy_with.dart b/package/lib/src/backend/core/generators/copy_with.dart index fd31074..c338602 100644 --- a/package/lib/src/backend/core/generators/copy_with.dart +++ b/package/lib/src/backend/core/generators/copy_with.dart @@ -1,16 +1,10 @@ import 'dart:async'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_object.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_type.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_finder.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/backend/core/typedefs.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/annotation_extensions.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; import 'package:path/path.dart'; +import 'package:tachyon/tachyon.dart'; const String _kVmPreferInline = "@pragma('vm:prefer-inline')"; @@ -22,9 +16,9 @@ class CopyWithGenerator implements Generator { required final String generatedClassName, required final String classTypeParametersSource, required final String classTypeParametersWithoutConstraints, - required ClassOrEnumDeclarationFinder classDeclarationFinder, - required String projectDirectoryPath, - required DataClassPluginOptions pluginOptions, + required final ClassOrEnumDeclarationFinder classDeclarationFinder, + required final String projectDirectoryPath, + required final DataClassPluginOptions pluginOptions, }) : _codeWriter = codeWriter, _className = className, _generatedClassName = generatedClassName, @@ -58,17 +52,16 @@ class CopyWithGenerator implements Generator { ..writeln(); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; final String fieldName = field.name; bool useCopyWithProxy = false; - if (!customDartType.isPrimary && - !customDartType.isList && - !customDartType.isUri && - !customDartType.isDateTime && - !customDartType.isDuration) { - final ClassOrEnumDeclarationMatch? match = - await _classDeclarationFinder(customDartType.name); + if (!dartType.isPrimitive && + !dartType.isList && + !dartType.isUri && + !dartType.isDateTime && + !dartType.isDuration) { + final ClassOrEnumDeclarationMatch? match = await _classDeclarationFinder(dartType.name); final NamedCompilationUnitMember? node = match?.node; if (match != null && node is ClassDeclaration && node.hasDataClassAnnotation) { @@ -83,14 +76,14 @@ class CopyWithGenerator implements Generator { _codeWriter ..writeln(_kVmPreferInline) ..write( - '\$${customDartType.name}CopyWithProxyChain<$_className$_classTypeParametersWithoutConstraints>') - ..write(customDartType.isNullable ? '?' : '') + '\$${dartType.name}CopyWithProxyChain<$_className$_classTypeParametersWithoutConstraints>') + ..write(dartType.isNullable ? '?' : '') ..write(' get $fieldName => ') - ..write(customDartType.isNullable ? '_value.$fieldName == null ? null : ' : '') + ..write(dartType.isNullable ? '_value.$fieldName == null ? null : ' : '') ..writeln( - '\$${customDartType.name}CopyWithProxyChain<$_className$_classTypeParametersWithoutConstraints>(_value.$fieldName') - ..write(customDartType.isNullable ? '!' : '') - ..writeln(', (${customDartType.fullTypeName} update) => this($fieldName: update));') + '\$${dartType.name}CopyWithProxyChain<$_className$_classTypeParametersWithoutConstraints>(_value.$fieldName') + ..write(dartType.isNullable ? '!' : '') + ..writeln(', (${dartType.fullTypeName} update) => this($fieldName: update));') ..writeln(); continue; } @@ -99,7 +92,7 @@ class CopyWithGenerator implements Generator { ..writeln() ..writeln(_kVmPreferInline) ..writeln( - '$_className$_classTypeParametersWithoutConstraints $fieldName(${customDartType.fullTypeName} newValue) => ') + '$_className$_classTypeParametersWithoutConstraints $fieldName(${dartType.fullTypeName} newValue) => ') ..writeln('this($fieldName: newValue);'); } @@ -111,12 +104,12 @@ class CopyWithGenerator implements Generator { if (_fields.isNotEmpty) { _codeWriter.write('{'); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; - if (customDartType.isNullable) { + if (dartType.isNullable) { _codeWriter.write('final Object? ${field.name} = const Object(),'); } else { - _codeWriter.write('final ${customDartType.fullTypeName}? ${field.name},'); + _codeWriter.write('final ${dartType.fullTypeName}? ${field.name},'); } } _codeWriter.write('}'); @@ -127,17 +120,17 @@ class CopyWithGenerator implements Generator { ..writeln('return $_generatedClassName$_classTypeParametersWithoutConstraints('); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; final String fieldName = field.name; if (field.isNamed) { _codeWriter.write('$fieldName: '); } - if (customDartType.isNullable) { + if (dartType.isNullable) { _codeWriter ..write('identical($fieldName, const Object())') - ..write(' ? _value.$fieldName : ($fieldName as ${customDartType.fullTypeName}),'); + ..write(' ? _value.$fieldName : ($fieldName as ${dartType.fullTypeName}),'); } else { _codeWriter.writeln('$fieldName ?? _value.$fieldName,'); } @@ -169,13 +162,13 @@ class CopyWithGenerator implements Generator { ..writeln(); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; final String fieldName = field.name; _codeWriter ..writeln() ..writeln(_kVmPreferInline) - ..writeln('\$Result $fieldName(${customDartType.fullTypeName} newValue) => ') + ..writeln('\$Result $fieldName(${dartType.fullTypeName} newValue) => ') ..writeln('this($fieldName: newValue);') ..writeln(); } @@ -188,12 +181,12 @@ class CopyWithGenerator implements Generator { if (_fields.isNotEmpty) { _codeWriter.write('{'); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; - if (customDartType.isNullable) { + if (dartType.isNullable) { _codeWriter.write('final Object? ${field.name} = const Object(),'); } else { - _codeWriter.write('final ${customDartType.fullTypeName}? ${field.name},'); + _codeWriter.write('final ${dartType.fullTypeName}? ${field.name},'); } } _codeWriter.write('}'); @@ -204,17 +197,17 @@ class CopyWithGenerator implements Generator { ..writeln('return _chain($_generatedClassName$_classTypeParametersWithoutConstraints('); for (final DeclarationInfo field in _fields) { - final CustomDartType customDartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; final String fieldName = field.name; if (field.isNamed) { _codeWriter.write('$fieldName: '); } - if (customDartType.isNullable) { + if (dartType.isNullable) { _codeWriter ..write('identical($fieldName, const Object())') - ..writeln(' ? _value.$fieldName : ($fieldName as ${customDartType.fullTypeName}),'); + ..writeln(' ? _value.$fieldName : ($fieldName as ${dartType.fullTypeName}),'); } else { _codeWriter.writeln('$fieldName ?? _value.$fieldName,'); } diff --git a/package/lib/src/backend/core/generators/from_json.dart b/package/lib/src/backend/core/generators/from_json.dart index 492a04e..fdf0e3f 100644 --- a/package/lib/src/backend/core/generators/from_json.dart +++ b/package/lib/src/backend/core/generators/from_json.dart @@ -1,25 +1,18 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_object.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_type.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_finder.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/backend/core/typedefs.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/json_key_name_convention.dart'; -import 'package:data_class_plugin/src/tools/logger/plugin_logger.dart'; import 'package:data_class_plugin/src/typedefs.dart'; +import 'package:tachyon/tachyon.dart'; class FromJsonGenerator implements Generator { FromJsonGenerator({ - required CodeWriter codeWriter, - required List fields, - required String generatedClassName, - required String classTypeParametersWithoutConstraints, - required JsonKeyNameConventionGetter jsonKeyNameConventionGetter, - required ClassOrEnumDeclarationFinder classDeclarationFinder, - required PluginLogger logger, + required final CodeWriter codeWriter, + required final List fields, + required final String generatedClassName, + required final String classTypeParametersWithoutConstraints, + required final JsonKeyNameConventionGetter jsonKeyNameConventionGetter, + required final ClassOrEnumDeclarationFinder classDeclarationFinder, + required final Logger logger, }) : _codeWriter = codeWriter, _fields = fields, _generatedClassName = generatedClassName, @@ -34,7 +27,7 @@ class FromJsonGenerator implements Generator { final String _classTypeParametersWithoutConstraints; final JsonKeyNameConventionGetter _jsonKeyNameConventionGetter; final ClassOrEnumDeclarationFinder _classOrEnumDeclarationFinder; - final PluginLogger _logger; + final Logger _logger; late String _currentJsonFieldName; @@ -63,7 +56,7 @@ class FromJsonGenerator implements Generator { if (node is ClassDeclaration) { for (final NamedType interface in (node.implementsClause?.interfaces ?? const [])) { - if (interface.name.name == 'JsonConverter') { + if (interface.name2.lexeme == 'JsonConverter') { customJsonConverter = className; break; } @@ -80,7 +73,7 @@ class FromJsonGenerator implements Generator { _jsonKeyNameConventionGetter(annotationValueExtractor.getEnumValue('nameConvention')); final String fieldName = field.name; - final CustomDartType dartType = field.type?.customDartType ?? CustomDartType.dynamic; + final TachyonDartType dartType = field.type?.customDartType ?? TachyonDartType.dynamic; _currentJsonFieldName = annotationValueExtractor.getString('name') ?? jsonKeyNameConvention.transform(fieldName.escapeDollarSign()); @@ -129,7 +122,7 @@ class FromJsonGenerator implements Generator { } Future _parse({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final int depthIndex, required final String parentVariableName, final Expression? defaultValue, @@ -166,7 +159,7 @@ class FromJsonGenerator implements Generator { return; } - if (!dartType.isPrimary && (dartType.isNullable || defaultValue != null)) { + if (!dartType.isPrimitive && (dartType.isNullable || defaultValue != null)) { _writeNullableCheck( variableName: parentVariableName, defaultValue: defaultValue, @@ -178,7 +171,7 @@ class FromJsonGenerator implements Generator { parentVariableName: parentVariableName, ); - if (dartType.isPrimary && defaultValue != null) { + if (dartType.isPrimitive && defaultValue != null) { if (dartType.isNullable) { _logger.warning('Declared a nullable type ${dartType.fullTypeName} with default'); } else { @@ -191,7 +184,7 @@ class FromJsonGenerator implements Generator { } Future _parsePrimary({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final String parentVariableName, }) async { if (dartType.isDynamic) { @@ -199,7 +192,7 @@ class FromJsonGenerator implements Generator { return; } - if (dartType.isPrimary) { + if (dartType.isPrimitive) { _codeWriter.write('$parentVariableName as ${dartType.fullTypeName}'); return; } @@ -208,22 +201,28 @@ class FromJsonGenerator implements Generator { await _classOrEnumDeclarationFinder(dartType.name) .then((ClassOrEnumDeclarationMatch? match) => match?.node); - if (typeDeclarationNode is ClassDeclaration && - typeDeclarationNode.members.hasFactory('fromJson') || - typeDeclarationNode is EnumDeclaration && - typeDeclarationNode.members.hasFactory('fromJson')) { - _codeWriter.write('${dartType.name}.fromJson($parentVariableName)'); + if (typeDeclarationNode is ClassDeclaration && typeDeclarationNode.hasFactory('fromJson') || + typeDeclarationNode is EnumDeclaration && typeDeclarationNode.hasFactory('fromJson')) { + _codeWriter.write('${dartType.fullTypeName}.fromJson($parentVariableName)'); return; } - _logger.warning('~ No "fromJson" factory found for type "${dartType.name}"'); + _logger.warning('~ No "fromJson" factory found for type "${dartType.fullTypeName}"'); - _codeWriter.write('jsonConverterRegistrant.find(${dartType.name})' - ".fromJson($parentVariableName, json, '$_currentJsonFieldName') as ${dartType.name}"); + if (dartType.isNullable) { + final String typeWithoutNullability = + dartType.fullTypeName.substring(0, dartType.fullTypeName.length - 1); + _codeWriter.write('jsonConverterRegistrant.find($typeWithoutNullability)' + ".fromJson($parentVariableName, json, '$_currentJsonFieldName') as $typeWithoutNullability"); + return; + } + + _codeWriter.write('jsonConverterRegistrant.find(${dartType.fullTypeName})' + ".fromJson($parentVariableName, json, '$_currentJsonFieldName') as ${dartType.fullTypeName}"); } Future _parseList({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final String parentVariableName, required final int depthIndex, }) async { @@ -244,7 +243,7 @@ class FromJsonGenerator implements Generator { } Future _parseMap({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final String parentVariableName, required final int depthIndex, }) async { diff --git a/package/lib/src/backend/core/generators/hash_and_equals.dart b/package/lib/src/backend/core/generators/hash_and_equals.dart index a2d6c29..35d2805 100644 --- a/package/lib/src/backend/core/generators/hash_and_equals.dart +++ b/package/lib/src/backend/core/generators/hash_and_equals.dart @@ -1,14 +1,11 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_type.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; +import 'package:tachyon/tachyon.dart'; class HashGenerator implements Generator { HashGenerator({ - required CodeWriter codeWriter, - required List fields, - required bool skipCollections, + required final CodeWriter codeWriter, + required final List fields, + required final bool skipCollections, }) : _codeWriter = codeWriter, _fields = fields, _skipCollections = skipCollections; @@ -70,7 +67,7 @@ class EqualsGenerator implements Generator { continue; } - final CustomDartType dartType = field.type.customDartType; + final TachyonDartType dartType = field.type.customDartType; if (dartType.isList || dartType.isMap) { _codeWriter.write(' && deepEquality(${field.name}, other.${field.name})'); continue; diff --git a/package/lib/src/backend/core/generators/to_json.dart b/package/lib/src/backend/core/generators/to_json.dart index 722bd09..748862f 100644 --- a/package/lib/src/backend/core/generators/to_json.dart +++ b/package/lib/src/backend/core/generators/to_json.dart @@ -1,34 +1,30 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_object.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_type.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_finder.dart'; -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/backend/core/typedefs.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/json_key_name_convention.dart'; -import 'package:data_class_plugin/src/tools/logger/plugin_logger.dart'; import 'package:data_class_plugin/src/typedefs.dart'; +import 'package:tachyon/tachyon.dart'; class ToJsonGenerator implements Generator { ToJsonGenerator({ - required CodeWriter codeWriter, + required final CodeWriter codeWriter, required final List fields, required final JsonKeyNameConventionGetter jsonKeyNameConventionGetter, - required ClassOrEnumDeclarationFinder classDeclarationFinder, - required PluginLogger logger, + required final ClassOrEnumDeclarationFinder classDeclarationFinder, + final String? namedKeyToFactoryEntry, + required final Logger logger, }) : _codeWriter = codeWriter, _fields = fields, _jsonKeyNameConventionGetter = jsonKeyNameConventionGetter, _classDeclarationFinder = classDeclarationFinder, + _namedKeyToFactoryEntry = namedKeyToFactoryEntry, _logger = logger; final CodeWriter _codeWriter; final List _fields; final JsonKeyNameConventionGetter _jsonKeyNameConventionGetter; final ClassOrEnumDeclarationFinder _classDeclarationFinder; - final PluginLogger _logger; + final String? _namedKeyToFactoryEntry; + final Logger _logger; @override Future execute() async { @@ -38,6 +34,10 @@ class ToJsonGenerator implements Generator { ..writeln('Map toJson() {') ..writeln('return {'); + if (_namedKeyToFactoryEntry != null) { + _codeWriter.write('$_namedKeyToFactoryEntry,'); + } + for (final DeclarationInfo field in _fields) { AnnotationValueExtractor? annotationValueExtractor; String? customJsonConverter; @@ -57,7 +57,7 @@ class ToJsonGenerator implements Generator { if (node is ClassDeclaration) { for (final NamedType interface in (node.implementsClause?.interfaces ?? const [])) { - if (interface.name.name == 'JsonConverter') { + if (interface.name2.lexeme == 'JsonConverter') { customJsonConverter = className; break; } @@ -76,7 +76,7 @@ class ToJsonGenerator implements Generator { final String fieldName = field.name; final String jsonFieldName = annotationValueExtractor.getString('name') ?? jsonKeyNameConvention.transform(fieldName.escapeDollarSign()); - final CustomDartType dartType = field.type?.customDartType ?? CustomDartType.dynamic; + final TachyonDartType dartType = field.type?.customDartType ?? TachyonDartType.dynamic; _codeWriter.write("'$jsonFieldName': "); @@ -112,7 +112,7 @@ class ToJsonGenerator implements Generator { } Future _encode({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final int depthIndex, required final String parentVariableName, final bool requiresBangOperator = false, @@ -146,10 +146,10 @@ class ToJsonGenerator implements Generator { } Future _encodePrimary({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final String parentVariableName, }) async { - if (dartType.isDynamic || dartType.isPrimary) { + if (dartType.isDynamic || dartType.isPrimitive) { _codeWriter.writeln('$parentVariableName,'); return; } @@ -181,8 +181,8 @@ class ToJsonGenerator implements Generator { .writeln('jsonConverterRegistrant.find(${dartType.name}).toJson($parentVariableName),'); } - bool _shouldSkipForCollection(final CustomDartType originalDartType) { - CustomDartType dartType = originalDartType; + bool _shouldSkipForCollection(final TachyonDartType originalDartType) { + TachyonDartType dartType = originalDartType; while (true) { if (dartType.isList) { dartType = dartType.typeArguments[0]; @@ -192,11 +192,11 @@ class ToJsonGenerator implements Generator { break; } } - return dartType.isPrimary; + return dartType.isPrimitive; } Future _encodeList({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final String parentVariableName, required final int depthIndex, required final bool requiresBangOperator, @@ -230,12 +230,12 @@ class ToJsonGenerator implements Generator { } Future _encodeMap({ - required final CustomDartType dartType, + required final TachyonDartType dartType, required final String parentVariableName, required final int depthIndex, required final bool requiresBangOperator, }) async { - if (!dartType.typeArguments[0].isPrimary) { + if (!dartType.typeArguments[0].isPrimitive) { return; } diff --git a/package/lib/src/backend/core/generators/to_string.dart b/package/lib/src/backend/core/generators/to_string.dart index 0fc98cc..3e02d87 100644 --- a/package/lib/src/backend/core/generators/to_string.dart +++ b/package/lib/src/backend/core/generators/to_string.dart @@ -1,13 +1,12 @@ -import 'package:data_class_plugin/src/backend/core/declaration_info.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class ToStringGenerator implements Generator { ToStringGenerator({ - required CodeWriter codeWriter, - required List fields, - required String className, + required final CodeWriter codeWriter, + required final List fields, + required final String className, }) : _codeWriter = codeWriter, _className = className, _fields = fields; diff --git a/package/lib/src/backend/core/generators/union_from_json.dart b/package/lib/src/backend/core/generators/union_from_json.dart index 6f539e0..d4da8aa 100644 --- a/package/lib/src/backend/core/generators/union_from_json.dart +++ b/package/lib/src/backend/core/generators/union_from_json.dart @@ -1,9 +1,7 @@ -import 'package:analyzer/dart/ast/ast.dart'; import 'package:data_class_plugin/src/annotations/constants.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_object.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class UnionFromJsonGenerator implements Generator { UnionFromJsonGenerator({ diff --git a/package/lib/src/backend/core/generators/union_when.dart b/package/lib/src/backend/core/generators/union_when.dart index a16fd10..a623860 100644 --- a/package/lib/src/backend/core/generators/union_when.dart +++ b/package/lib/src/backend/core/generators/union_when.dart @@ -1,7 +1,6 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class UnionWhenGenerator implements Generator { UnionWhenGenerator({ diff --git a/package/lib/src/backend/core/packages_dependency_graph.dart b/package/lib/src/backend/core/packages_dependency_graph.dart deleted file mode 100644 index e1f3377..0000000 --- a/package/lib/src/backend/core/packages_dependency_graph.dart +++ /dev/null @@ -1,22 +0,0 @@ -class DependencyGraph { - final Map> _dependencies = >{}; - final Map> _dependants = >{}; - - void add(String dependant, String newDependency) { - (_dependencies[dependant] ??= {}).add(newDependency); - (_dependants[newDependency] ??= {}).add(dependant); - } - - List getDependants(String dependencyName) { - return _dependants[dependencyName]?.toList(growable: false) ?? const []; - } - - bool hasDependency(String dependant, String dependencyName) { - return _dependencies[dependant]?.contains(dependencyName) ?? false; - } - - void clear() { - _dependants.clear(); - _dependencies.clear(); - } -} diff --git a/package/lib/src/backend/core/parse_file_extension.dart b/package/lib/src/backend/core/parse_file_extension.dart deleted file mode 100644 index d636e71..0000000 --- a/package/lib/src/backend/core/parse_file_extension.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:analyzer/dart/analysis/features.dart'; -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:analyzer/dart/analysis/utilities.dart'; -import 'package:analyzer/error/error.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; - -extension ParseFileX on String { - ParseStringResult parse({ - required FeatureSet featureSet, - }) { - final ParseStringResult result = parseFile( - path: this, - featureSet: featureSet, - throwIfDiagnostics: false, - ); - - if (result.errors.isNotEmpty) { - throw ParseException(result.errors); - } - - return result; - } -} - -class ParseException implements Exception { - const ParseException(this.errors); - - final List errors; - - @override - String toString() { - return errors.map((AnalysisError error) { - final StringBuffer buffer = StringBuffer()..writeln(); - - buffer - ..writeln('Severity: ${error.severity.name.capitalize().red()}') - ..write('File: ') - ..writeln(error.source.fullName.bold()) - ..write('Error: ') - ..writeln(error.message.red()); - if (error.correction != null) { - buffer - ..write('Possible solution: ') - ..writeln(error.correctionMessage!.green()); - } - - return buffer.toString(); - }).join('\n'); - } -} - -extension on String { - String capitalize() { - if (isEmpty) { - return this; - } - if (length == 1) { - return toUpperCase(); - } - return '${this[0].toUpperCase()}${substring(1)}'; - } -} diff --git a/package/lib/src/backend/core/parsed_file_data.dart b/package/lib/src/backend/core/parsed_file_data.dart deleted file mode 100644 index 38d38a5..0000000 --- a/package/lib/src/backend/core/parsed_file_data.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/data_class_plugin.dart'; - -part 'parsed_file_data.gen.dart'; - -@DataClass(copyWith: false) -abstract class ParsedFileData { - ParsedFileData.ctor(); - - /// Default constructor - factory ParsedFileData({ - required String absolutePath, - required CompilationUnit compilationUnit, - required DateTime lastModifiedAt, - }) = _$ParsedFileDataImpl; - - String get absolutePath; - CompilationUnit get compilationUnit; - DateTime get lastModifiedAt; -} diff --git a/package/lib/src/backend/core/parsed_file_data.gen.dart b/package/lib/src/backend/core/parsed_file_data.gen.dart deleted file mode 100644 index 80c522f..0000000 --- a/package/lib/src/backend/core/parsed_file_data.gen.dart +++ /dev/null @@ -1,56 +0,0 @@ -// AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field - -part of 'parsed_file_data.dart'; - -class _$ParsedFileDataImpl extends ParsedFileData { - _$ParsedFileDataImpl({ - required this.absolutePath, - required this.compilationUnit, - required this.lastModifiedAt, - }) : super.ctor(); - - @override - final String absolutePath; - - @override - final CompilationUnit compilationUnit; - - @override - final DateTime lastModifiedAt; - - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is ParsedFileData && - runtimeType == other.runtimeType && - absolutePath == other.absolutePath && - compilationUnit == other.compilationUnit && - lastModifiedAt == other.lastModifiedAt; - } - - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - absolutePath, - compilationUnit, - lastModifiedAt, - ]); - } - - @override - String toString() { - String toStringOutput = 'ParsedFileData{}'; - assert(() { - toStringOutput = - 'ParsedFileData@<$hexIdentity>{absolutePath: $absolutePath, compilationUnit: $compilationUnit, lastModifiedAt: $lastModifiedAt}'; - return true; - }()); - return toStringOutput; - } - - @override - Type get runtimeType => ParsedFileData; -} diff --git a/package/lib/src/backend/core/parsed_files_registry.dart b/package/lib/src/backend/core/parsed_files_registry.dart deleted file mode 100644 index 0967971..0000000 --- a/package/lib/src/backend/core/parsed_files_registry.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'dart:collection'; - -import 'package:data_class_plugin/src/backend/core/parsed_file_data.dart'; - -class ParsedFilesRegistry with MapMixin { - final Map _registry = {}; - - @override - Iterable get keys => _registry.keys; - - @override - ParsedFileData? operator [](Object? key) => _registry[key]; - - @override - void operator []=(String key, ParsedFileData value) => _registry[key] = value; - - @override - ParsedFileData? remove(Object? key) => _registry.remove(key); - - @override - void clear() { - _registry.clear(); - } -} diff --git a/package/lib/src/backend/core/typedefs.dart b/package/lib/src/backend/core/typedefs.dart deleted file mode 100644 index 7398e9e..0000000 --- a/package/lib/src/backend/core/typedefs.dart +++ /dev/null @@ -1,3 +0,0 @@ -import 'package:data_class_plugin/src/backend/core/declaration_finder.dart'; - -typedef ClassOrEnumDeclarationFinder = Future Function(String name); diff --git a/package/lib/src/cli.dart b/package/lib/src/cli.dart deleted file mode 100644 index ec849ee..0000000 --- a/package/lib/src/cli.dart +++ /dev/null @@ -1 +0,0 @@ -export 'cli/cli.dart'; diff --git a/package/lib/src/cli/cli.dart b/package/lib/src/cli/cli.dart deleted file mode 100644 index b3ca58b..0000000 --- a/package/lib/src/cli/cli.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/cli/commands/generate/generate_command.dart'; -import 'package:data_class_plugin/src/cli/commands/resync/resync_command.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; -import 'package:data_class_plugin/src/tools/logger/plugin_logger.dart'; - -class CliRunner extends CommandRunner { - CliRunner([IOSink? sink]) - : logger = PluginLogger(ioSink: sink), - super( - 'data_class_plugin', - 'Data Class Plugin is a tool that allows you to generate dart code on the fly.'.bold(), - ) { - logger.logHeader(PluginLogger.pluginHeader()); - logger.writeln(''); - - [ - // InstallCommand(logger: logger), - // AnalyzeCommand(logger: logger), - GenerateCommand(logger: logger), - ResyncCommand(logger: logger) - ].forEach(addCommand); - } - - final PluginLogger logger; -} diff --git a/package/lib/src/cli/commands/analyze/analyze_argument.dart b/package/lib/src/cli/commands/analyze/analyze_argument.dart deleted file mode 100644 index f479769..0000000 --- a/package/lib/src/cli/commands/analyze/analyze_argument.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:data_class_plugin/src/cli/commands/arguments.dart'; - -class AnalyzeArgument extends ArgumentOption { - const AnalyzeArgument._({ - required super.name, - super.abbr, - super.defaultsTo, - super.help, - super.mandatory, - }); - - static const AnalyzeArgument file = AnalyzeArgument._( - name: 'file', - abbr: 'f', - help: 'The file to analyze.', - mandatory: false, - defaultsTo: null, - ); - - static const AnalyzeArgument path = AnalyzeArgument._( - name: 'path', - abbr: 'p', - help: 'The path to analyze.', - mandatory: false, - defaultsTo: null, - ); - - static const AnalyzeArgument recursive = AnalyzeArgument._( - name: 'recursive', - abbr: 'r', - help: 'Analyze sub-directories recursively.', - defaultsTo: false, - ); - - static const AnalyzeArgument log = AnalyzeArgument._( - name: 'log', - abbr: 'l', - help: 'Log messages to file.', - defaultsTo: false, - ); - - static const List values = [ - file, - path, - recursive, - log, - ]; -} diff --git a/package/lib/src/cli/commands/analyze/analyze_command.dart b/package/lib/src/cli/commands/analyze/analyze_command.dart deleted file mode 100644 index 5a3863a..0000000 --- a/package/lib/src/cli/commands/analyze/analyze_command.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'dart:io'; - -import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:data_class_plugin/src/analyzer_plugin/analyzer_plugin.dart'; -import 'package:data_class_plugin/src/analyzer_plugin/web_socket_plugin_server.dart'; -import 'package:data_class_plugin/src/cli/commands/analyze/analyze_argument.dart'; -import 'package:data_class_plugin/src/cli/commands/arguments.dart'; -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/extensions/core_extensions.dart'; -import 'package:data_class_plugin/src/tools/file_tools.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; - -class AnalyzeCommand extends BaseCommand { - AnalyzeCommand({required super.logger}) { - argParser.addArgumentOptions(AnalyzeArgument.values); - } - - @override - String get name => 'analyze'; - - @override - String get description => 'Analyze files with Plugin Linter'.bold(); - - late final DataClassPlugin plugin; - - @override - Future init() async { - super.logger.writeToFile = argResults!.getValue( - AnalyzeArgument.log, - ); - - await super.init(); - } - - @override - Future execute() async { - final DateTime startedOn = DateTime.now(); - - logger.info('Running plugin analyzer'); - try { - // Initialize plugin - plugin = DataClassPlugin(PhysicalResourceProvider.INSTANCE); - - // Start plugin - plugin.start( - WebSocketPluginServer(logger: logger), - ); - - final List includedPaths = await _findIncludedPaths(); - - final AnalysisContextCollection analysis = AnalysisContextCollection( - includedPaths: includedPaths, - resourceProvider: PhysicalResourceProvider.INSTANCE, - ); - - logger.writeln(); - logger.info('Analysis context collection files: ${includedPaths.length}'); - - for (final String path in includedPaths) { - logger.writeln('🔍 Analyzing file $path'); - - try { - await plugin.analyzeFile( - analysisContext: analysis.contextFor(path), - path: path, - ); - } catch (e, st) { - logger.exception(e, st); - } - - logger.writeln(Ansi.horizontalLine(length: 100)); - } - - logger.writeln(); - logger.info( - 'Plugin linter analyzed ${includedPaths.length} files in ${startedOn.getElapsedDuration()}'); - - exitCode = 0; - } catch (e, st) { - logger.exception('Plugin analyzer failed after ${startedOn.getElapsedDuration()}'); - logger.exception(e, st); - exitCode = 1; - } - - await logger.dispose(); - } - - Future> _findIncludedPaths() async { - final List includedPaths = []; - - final String? file = argResults!.getValue(AnalyzeArgument.file); - final String? path = argResults!.getValue(AnalyzeArgument.path); - final bool recursive = argResults!.getValue(AnalyzeArgument.recursive); - - if (file != null && File(file).existsSync()) { - includedPaths.add(file); - } - - if (path != null) { - final List files = FileTools.findFiles( - matchingPattern: FileTools.dartFileNameMatcher, - path: path, - recursive: recursive, - ); - includedPaths.addAll(files); - } - - if (includedPaths.isEmpty) { - final List files = FileTools.findFiles( - matchingPattern: FileTools.dartFileNameMatcher, - path: Directory.current.path, - recursive: true, - ); - includedPaths.addAll(files); - } - - return includedPaths; - } -} diff --git a/package/lib/src/cli/commands/arguments.dart b/package/lib/src/cli/commands/arguments.dart deleted file mode 100644 index 1af1abe..0000000 --- a/package/lib/src/cli/commands/arguments.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:args/args.dart'; - -abstract class ArgumentOption { - /// Default constructor of [ArgumentOption] - const ArgumentOption({ - required this.name, - this.abbr, - this.help, - this.defaultsTo, - this.allowed, - this.mandatory = false, - }); - - final String name; - final String? abbr; - final String? help; - final dynamic defaultsTo; - final List? allowed; - final bool mandatory; - - static Map fromArguments( - final ArgResults results, - final List arguments, - ) { - return { - for (final ArgumentOption value in arguments) value: results[value.name] ?? value.defaultsTo - }; - } -} - -extension ArgParserX on ArgParser { - void addArgumentOptions(List arguments) { - for (final ArgumentOption option in arguments) { - if (option.defaultsTo.runtimeType == bool) { - addArgumentFlag(option); - } else { - addArgumentOption(option); - } - } - } - - void addArgumentOption(ArgumentOption option) { - addOption( - option.name, - abbr: option.abbr, - help: option.help, - defaultsTo: option.defaultsTo == null ? null : '${option.defaultsTo}', - mandatory: false, - allowed: option.allowed, - ); - } - - void addArgumentFlag(ArgumentOption option) { - addFlag( - option.name, - abbr: option.abbr, - help: option.help, - defaultsTo: option.defaultsTo, - ); - } -} - -extension ArgResultsX on ArgResults { - dynamic getValue(ArgumentOption option) { - return this[option.name] ?? option.defaultsTo; - } -} diff --git a/package/lib/src/cli/commands/base_command.dart b/package/lib/src/cli/commands/base_command.dart deleted file mode 100644 index e556509..0000000 --- a/package/lib/src/cli/commands/base_command.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:args/command_runner.dart'; -import 'package:data_class_plugin/src/tools/logger/plugin_logger.dart'; - -abstract class BaseCommand extends Command { - BaseCommand({required this.logger}); - - final PluginLogger logger; - - @override - String get invocation => '${runner?.executableName} $name [arguments]'; - - Future init() async { - logger.info('> Running command: $name'); - } - - Future execute(); - - @override - Future run() async { - await init(); - await execute(); - await dispose(); - } - - Future dispose() async {} -} diff --git a/package/lib/src/cli/commands/generate/build_command.dart b/package/lib/src/cli/commands/generate/build_command.dart deleted file mode 100644 index e3ab5f7..0000000 --- a/package/lib/src/cli/commands/generate/build_command.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:data_class_plugin/src/backend/code_generator.dart'; -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/cli/commands/mixins.dart'; - -class BuildCommand extends BaseCommand with UtilsCommandMixin { - BuildCommand({ - required super.logger, - required this.directory, - }) : _codeGenerator = CodeGenerator( - directory: directory, - logger: logger, - ); - - final CodeGenerator _codeGenerator; - - @override - final Directory directory; - - @override - final String name = 'build'; - - @override - final String description = 'Builds project'; - - @override - Future execute() async { - ensureHasPubspec(); - await ensureIsFileGenerationMode(); - - await _codeGenerator.indexProject(); - return await _codeGenerator.buildProject(); - } -} diff --git a/package/lib/src/cli/commands/generate/generate_command.dart b/package/lib/src/cli/commands/generate/generate_command.dart deleted file mode 100644 index b4babb2..0000000 --- a/package/lib/src/cli/commands/generate/generate_command.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:io'; - -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/cli/commands/generate/build_command.dart'; -import 'package:data_class_plugin/src/cli/commands/generate/watch_command.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; - -class GenerateCommand extends BaseCommand { - @override - String get name => 'generate'; - - @override - String get description => 'Generate code as specified by annotations'.bold(); - - GenerateCommand({ - required super.logger, - }) { - addSubcommand(BuildCommand(logger: logger, directory: Directory.current)); - addSubcommand(WatchCommand(logger: logger, directory: Directory.current)); - } - - @override - Future init() async { - await super.init(); - } - - @override - Future execute() async { - // noop - } - - @override - Future dispose() async { - await logger.dispose(); - } -} diff --git a/package/lib/src/cli/commands/generate/watch_command.dart b/package/lib/src/cli/commands/generate/watch_command.dart deleted file mode 100644 index 833cf14..0000000 --- a/package/lib/src/cli/commands/generate/watch_command.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:data_class_plugin/src/backend/code_generator.dart'; -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/cli/commands/mixins.dart'; - -class WatchCommand extends BaseCommand with UtilsCommandMixin { - WatchCommand({ - required super.logger, - required this.directory, - }) : _codeGenerator = CodeGenerator( - directory: directory, - logger: logger, - ); - - final CodeGenerator _codeGenerator; - - @override - final Directory directory; - - @override - final String name = 'watch'; - - @override - final String description = 'Watches project for files changes and rebuilds when necessary'; - - @override - Future execute() async { - ensureHasPubspec(); - await ensureIsFileGenerationMode(); - - if (!Platform.isWindows) { - ProcessSignal.sigterm.watch().listen((_) => _dispose()); - } - ProcessSignal.sigint.watch().listen((_) => _dispose()); - - await _codeGenerator.watchProject(onReady: () => logger.debug('Listening')); - } - - void _dispose() { - logger.writeln('Stopping..'); - _codeGenerator.dispose(); - exit(0); - } -} diff --git a/package/lib/src/cli/commands/install/install_argument.dart b/package/lib/src/cli/commands/install/install_argument.dart deleted file mode 100644 index c2266d3..0000000 --- a/package/lib/src/cli/commands/install/install_argument.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:data_class_plugin/src/cli/commands/arguments.dart'; - -class InstallArgument extends ArgumentOption { - const InstallArgument._({ - required super.name, - super.abbr, - super.defaultsTo, - super.help, - super.mandatory, - }); - - static const InstallArgument path = InstallArgument._( - name: 'path', - abbr: 'p', - help: 'The path where the pubspec.yaml is.', - mandatory: true, - ); - - static const InstallArgument recursive = InstallArgument._( - name: 'recursive', - abbr: 'r', - help: 'Install Data Class Plugin for all projects ' - 'found in the subdirectories of the given path.', - defaultsTo: false, - ); - - static const InstallArgument log = InstallArgument._( - name: 'log', - abbr: 'l', - help: 'Log messages to file.', - defaultsTo: false, - ); - - static const List values = [ - path, - recursive, - log, - ]; -} diff --git a/package/lib/src/cli/commands/install/install_command.dart b/package/lib/src/cli/commands/install/install_command.dart deleted file mode 100644 index e243634..0000000 --- a/package/lib/src/cli/commands/install/install_command.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'dart:io'; - -import 'package:data_class_plugin/src/cli/commands/arguments.dart'; -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/cli/commands/install/install_argument.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; - -class InstallCommand extends BaseCommand { - @override - String get name => 'install'; - - @override - String get description => 'Install Data Class Plugin'.bold(); - - InstallCommand({ - required super.logger, - }) { - argParser.addArgumentOptions(InstallArgument.values); - } - - @override - Future init() async { - logger.writeToFile = argResults!.getValue( - InstallArgument.log, - ); - - await super.init(); - } - - @override - Future execute() async { - logger.writeln('Installing Data Class Plugin'.blue()); - - final String path = argResults![InstallArgument.path.name] ?? Directory.current.path; - logger.writeln("Target path: '$path'"); - - try { - _installPubspec(path); - _installAnalysisOptions(path); - _installPluginOptions(path); - } catch (e, st) { - logger.error(e, st); - } - } - - void _installPubspec(String path) { - // TODO - } - - void _installAnalysisOptions(String path) { - // TODO - } - - void _installPluginOptions(String path) { - // TODO - } -} diff --git a/package/lib/src/cli/commands/mixins.dart b/package/lib/src/cli/commands/mixins.dart deleted file mode 100644 index 659cb2c..0000000 --- a/package/lib/src/cli/commands/mixins.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'package:data_class_plugin/src/common/utils.dart'; -import 'package:data_class_plugin/src/exceptions.dart'; -import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; -import 'package:path/path.dart' as path; - -mixin UtilsCommandMixin on Command { - Directory get directory; - - void ensureHasPubspec() { - final bool hasPubspecYaml = directory - .listSync() // - .any((FileSystemEntity entity) => - entity is File && path.basename(entity.path) == 'pubspec.yaml'); - - if (!hasPubspecYaml) { - throw const DcpException.pubspecYamlNotFound(); - } - } - - Future ensureIsFileGenerationMode() async { - final DataClassPluginOptions pluginOptions = await DataClassPluginOptions.fromFile( - getDataClassPluginOptionsFile(directory.path), - ); - if (pluginOptions.generationMode == CodeGenerationMode.inPlace) { - throw const DcpException.requiresFileGenerationMode(); - } - } -} diff --git a/package/lib/src/cli/commands/resync/resync_argument.dart b/package/lib/src/cli/commands/resync/resync_argument.dart deleted file mode 100644 index ed8c865..0000000 --- a/package/lib/src/cli/commands/resync/resync_argument.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:data_class_plugin/src/cli/commands/arguments.dart'; - -class ResyncArgument extends ArgumentOption { - const ResyncArgument._({ - required super.name, - super.abbr, - super.help, - super.mandatory, - }); - - static const ResyncArgument lineLength = ResyncArgument._( - name: 'lineLength', - abbr: 'l', - help: 'The line length used to format the code. ' - 'Uses the data_class_plugin_options.yaml generated_file_line_length property, ' - 'if no value is provided', - mandatory: true, - ); - - static const List values = [ - lineLength, - ]; -} diff --git a/package/lib/src/cli/commands/resync/resync_command.dart b/package/lib/src/cli/commands/resync/resync_command.dart deleted file mode 100644 index 8f70220..0000000 --- a/package/lib/src/cli/commands/resync/resync_command.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'dart:io' as io; - -import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:analyzer/file_system/file_system.dart'; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:analyzer_plugin/protocol/protocol_common.dart'; -import 'package:analyzer_plugin/protocol/protocol_generated.dart'; -import 'package:analyzer_plugin/utilities/assist/assist.dart'; -import 'package:dart_style/dart_style.dart'; -import 'package:data_class_plugin/src/analyzer_plugin/analyzer_plugin.dart'; -import 'package:data_class_plugin/src/analyzer_plugin/web_socket_plugin_server.dart'; -import 'package:data_class_plugin/src/backend/code_generator.dart'; -import 'package:data_class_plugin/src/cli/commands/arguments.dart'; -import 'package:data_class_plugin/src/cli/commands/base_command.dart'; -import 'package:data_class_plugin/src/cli/commands/mixins.dart'; -import 'package:data_class_plugin/src/cli/commands/resync/resync_argument.dart'; -import 'package:data_class_plugin/src/common/utils.dart'; -import 'package:data_class_plugin/src/contributors/class/class_contributors.dart'; -import 'package:data_class_plugin/src/exceptions.dart'; -import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; - -class ResyncCommand extends BaseCommand with UtilsCommandMixin { - ResyncCommand({ - required super.logger, - io.Directory? directory, - }) : directory = directory ?? io.Directory.current { - argParser.addArgumentOptions(ResyncArgument.values); - } - - @override - final io.Directory directory; - - late final CodeGenerator _codeGenerator = CodeGenerator( - directory: directory, - logger: logger, - ); - - @override - String get name => 'resync'; - - @override - String get description => 'Resync project'.bold(); - - @override - Future execute() async { - final Stopwatch stopwatch = Stopwatch()..start(); - - ensureHasPubspec(); - - final DataClassPlugin plugin = DataClassPlugin(PhysicalResourceProvider.INSTANCE); - - final DataClassPluginOptions pluginOptions = await DataClassPluginOptions.fromFile( - getDataClassPluginOptionsFile(_codeGenerator.directory.path)); - - await _codeGenerator.indexProject(); - - final List includedPaths = _codeGenerator.registeredFiles; - - plugin.start(WebSocketPluginServer(logger: logger)); - - Future generate() async { - final AnalysisContextCollection analysis = AnalysisContextCollection( - includedPaths: includedPaths, - resourceProvider: PhysicalResourceProvider.INSTANCE, - ); - - await plugin.handleAnalysisSetContextRoots( - AnalysisSetContextRootsParams([ - for (final String path in includedPaths) ContextRoot(path, []), - ]), - ); - - for (final String path in includedPaths) { - final io.File file = io.File(path); - - final AssistRequest request = await plugin.getAssistRequest( - EditGetAssistsParams(path, 0, file.lengthSync()), - ); - - final _SimpleAssistCollector collector = _SimpleAssistCollector(); - final DataClassAssistContributor dataClassContributor = DataClassAssistContributor( - path, - pluginOptions: pluginOptions, - ); - - final ResolvedUnitResult resolvedUnitResult = await analysis - .contextFor(path) - .currentSession - .getResolvedUnit(path) - .then((SomeResolvedUnitResult value) => value as ResolvedUnitResult); - - try { - await dataClassContributor.computeAssists( - _SimpleAssistRequest( - length: request.length, - offset: request.offset, - resourceProvider: request.resourceProvider, - result: resolvedUnitResult, - ), - collector, - ); - } on DcpException catch (e) { - await e.maybeWhen( - missingDataClassPluginImport: - (DcpExceptionMissingDataClassPluginImport exception) async { - logger - ..error('Resyncing can not be completed') - ..debug( - "${exception.relativeFilePath} is missing the following import => import 'package:data_class_plugin/data_class_plugin.dart';", - ) - ..info('Fix the issue listed above and re-run the command'); - stopwatch.stop(); - await _codeGenerator.dispose(); - io.exit(1); - }, - orElse: () {}, - ); - } - - String content = file.readAsStringSync(); - for (final PrioritizedSourceChange assist in collector.assists) { - for (final SourceFileEdit sourceFileEdit in assist.change.edits) { - for (final SourceEdit edit in sourceFileEdit.edits) { - content = content.replaceRange(edit.offset, edit.end, edit.replacement); - } - } - } - file.writeAsStringSync(DartFormatter( - pageWidth: pluginOptions.generatedFileLineLength, - ).format(content)); - } - - await _codeGenerator.indexProject(forceClear: true); - await _codeGenerator.buildProject(); - } - - await generate(); - - // a second generate is necessary as code generation might depend on code which needs to be generated - // example: super classes with DataClass annotation - await generate(); - - stopwatch.stop(); - logger.info('~ Resync completed in ${stopwatch.elapsedMilliseconds / 1000}s'); - io.exit(0); - } - - @override - Future dispose() async { - await _codeGenerator.dispose(); - return super.dispose(); - } -} - -class _SimpleAssistRequest extends DartAssistRequest { - _SimpleAssistRequest({ - required this.length, - required this.offset, - required this.resourceProvider, - required this.result, - }); - - @override - final int length; - - @override - final int offset; - - @override - final ResourceProvider resourceProvider; - - @override - final ResolvedUnitResult result; -} - -class _SimpleAssistCollector extends AssistCollector { - final List assists = []; - - @override - void addAssist(PrioritizedSourceChange assist) => assists.add(assist); -} diff --git a/package/lib/src/common/code_writer.dart b/package/lib/src/common/code_writer.dart deleted file mode 100644 index f4618c7..0000000 --- a/package/lib/src/common/code_writer.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; - -abstract class CodeWriter { - factory CodeWriter.stringBuffer() = _StringBufferCodeWriter; - factory CodeWriter.dartEditBuilder(DartEditBuilder builder) = _DartEditBuilderCodeWriter; - - String get content; - - void write(String string); - void writeln([String string]); -} - -class _StringBufferCodeWriter implements CodeWriter { - final StringBuffer _buffer = StringBuffer(); - - @override - void write(String string) => _buffer.write(string); - - @override - void writeln([String string = '']) => _buffer.writeln(string); - - @override - String get content => _buffer.toString(); -} - -class _DartEditBuilderCodeWriter implements CodeWriter { - _DartEditBuilderCodeWriter(this._builder); - - final DartEditBuilder _builder; - - @override - void write(String string) => _builder.write(string); - - @override - void writeln([String string = '']) => _builder.writeln(string); - - @override - String get content => _builder.toString(); -} diff --git a/package/lib/src/backend/core/generators/generator.dart b/package/lib/src/common/generator.dart similarity index 100% rename from package/lib/src/backend/core/generators/generator.dart rename to package/lib/src/common/generator.dart diff --git a/package/lib/src/contributors/available_assists.dart b/package/lib/src/contributors/available_assists.dart index ff2d881..ad62ad4 100644 --- a/package/lib/src/contributors/available_assists.dart +++ b/package/lib/src/contributors/available_assists.dart @@ -7,10 +7,10 @@ abstract class AvailableAssists { 'Generate shorthand constructor', ); - static const AssistKind dataAndUnionClass = AssistKind( + static const AssistKind dataAndUnionClasses = AssistKind( 'dataAndUnionClass', 1000, - 'Generate data/union class', + 'Generate data/union classes', ); static const AssistKind fromJson = AssistKind( diff --git a/package/lib/src/contributors/class/data_class_contributor.dart b/package/lib/src/contributors/class/data_class_contributor.dart index a45189d..5c775aa 100644 --- a/package/lib/src/contributors/class/data_class_contributor.dart +++ b/package/lib/src/contributors/class/data_class_contributor.dart @@ -7,8 +7,6 @@ import 'package:data_class_plugin/src/contributors/available_assists.dart'; import 'package:data_class_plugin/src/contributors_delegates/code_generation_delegate.dart'; import 'package:data_class_plugin/src/contributors_delegates/file_generation/file_generation_data_class_delegate.dart'; import 'package:data_class_plugin/src/contributors_delegates/file_generation/file_generation_union_delegate.dart'; -import 'package:data_class_plugin/src/contributors_delegates/in_place/in_place_data_class_delegate.dart'; -import 'package:data_class_plugin/src/contributors_delegates/in_place/in_place_union_delegate.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/mixins.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; @@ -45,7 +43,7 @@ class DataClassAssistContributor extends Object final ChangeBuilder changeBuilder = ChangeBuilder(session: session); await _generateDataClass(changeBuilder); await _generateUnion(changeBuilder); - addAssist(AvailableAssists.dataAndUnionClass, changeBuilder); + addAssist(AvailableAssists.dataAndUnionClasses, changeBuilder); } Future _generateDataClass(final ChangeBuilder changeBuilder) async { @@ -60,24 +58,14 @@ class DataClassAssistContributor extends Object return; } - final CodeGenerationDelegate delegate = - pluginOptions.generationMode == CodeGenerationMode.inPlace - ? InPlaceDataClassDelegate( - relativeFilePath: relativeFilePath, - targetFilePath: targetFilePath, - classNodes: visitor.matchedNodes, - pluginOptions: pluginOptions, - changeBuilder: changeBuilder, - ) - : FileGenerationDataClassDelegate( - relativeFilePath: relativeFilePath, - targetFilePath: targetFilePath, - changeBuilder: changeBuilder, - pluginOptions: pluginOptions, - classNodes: visitor.matchedNodes, - compilationUnit: assistRequest.result.unit, - ); - + final CodeGenerationDelegate delegate = FileGenerationDataClassDelegate( + relativeFilePath: relativeFilePath, + targetFilePath: targetFilePath, + changeBuilder: changeBuilder, + pluginOptions: pluginOptions, + classNodes: visitor.matchedNodes, + compilationUnit: assistRequest.result.unit, + ); await delegate.generate(); } @@ -93,25 +81,14 @@ class DataClassAssistContributor extends Object return; } - final CodeGenerationDelegate delegate = - pluginOptions.generationMode == CodeGenerationMode.inPlace - ? InPlaceUnionDelegate( - relativeFilePath: relativeFilePath, - targetFilePath: targetFilePath, - classNodes: visitor.matchedNodes, - pluginOptions: pluginOptions, - changeBuilder: changeBuilder, - compilationUnit: assistRequest.result.unit, - ) - : FileGenerationUnionDelegate( - relativeFilePath: relativeFilePath, - targetFilePath: targetFilePath, - changeBuilder: changeBuilder, - pluginOptions: pluginOptions, - classNodes: visitor.matchedNodes, - compilationUnit: assistRequest.result.unit, - ); - + final CodeGenerationDelegate delegate = FileGenerationUnionDelegate( + relativeFilePath: relativeFilePath, + targetFilePath: targetFilePath, + changeBuilder: changeBuilder, + pluginOptions: pluginOptions, + classNodes: visitor.matchedNodes, + compilationUnit: assistRequest.result.unit, + ); await delegate.generate(); } } diff --git a/package/lib/src/contributors/class/union_assist_contributor.dart b/package/lib/src/contributors/class/union_assist_contributor.dart index ec08b85..18876ff 100644 --- a/package/lib/src/contributors/class/union_assist_contributor.dart +++ b/package/lib/src/contributors/class/union_assist_contributor.dart @@ -6,7 +6,6 @@ import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dar import 'package:data_class_plugin/src/contributors/available_assists.dart'; import 'package:data_class_plugin/src/contributors_delegates/code_generation_delegate.dart'; import 'package:data_class_plugin/src/contributors_delegates/file_generation/file_generation_union_delegate.dart'; -import 'package:data_class_plugin/src/contributors_delegates/in_place/in_place_union_delegate.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/mixins.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; @@ -56,26 +55,16 @@ class UnionAssistContributor extends Object return; } - final CodeGenerationDelegate delegate = - pluginOptions.generationMode == CodeGenerationMode.inPlace - ? InPlaceUnionDelegate( - relativeFilePath: relativeFilePath, - targetFilePath: targetFilePath, - classNodes: visitor.matchedNodes, - pluginOptions: pluginOptions, - changeBuilder: changeBuilder, - compilationUnit: assistRequest.result.unit, - ) - : FileGenerationUnionDelegate( - relativeFilePath: relativeFilePath, - targetFilePath: targetFilePath, - changeBuilder: changeBuilder, - pluginOptions: pluginOptions, - classNodes: visitor.matchedNodes, - compilationUnit: assistRequest.result.unit, - ); + final CodeGenerationDelegate delegate = FileGenerationUnionDelegate( + relativeFilePath: relativeFilePath, + targetFilePath: targetFilePath, + changeBuilder: changeBuilder, + pluginOptions: pluginOptions, + classNodes: visitor.matchedNodes, + compilationUnit: assistRequest.result.unit, + ); await delegate.generate(); - addAssist(AvailableAssists.dataAndUnionClass, changeBuilder); + addAssist(AvailableAssists.dataAndUnionClasses, changeBuilder); } } diff --git a/package/lib/src/contributors/common/to_string_assist_contributor.dart b/package/lib/src/contributors/common/to_string_assist_contributor.dart deleted file mode 100644 index 7736797..0000000 --- a/package/lib/src/contributors/common/to_string_assist_contributor.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:analyzer/dart/analysis/session.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/source/source_range.dart'; -import 'package:analyzer_plugin/utilities/assist/assist.dart'; -import 'package:analyzer_plugin/utilities/assist/assist_contributor_mixin.dart'; -import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; -import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; -import 'package:data_class_plugin/src/contributors/available_assists.dart'; -import 'package:data_class_plugin/src/contributors/generators/to_string.dart'; -import 'package:data_class_plugin/src/extensions/extensions.dart'; -import 'package:data_class_plugin/src/mixins.dart'; - -class ToStringAssistContributor extends Object - with AssistContributorMixin, ClassAstVisitorMixin, EnumAstVisitorMixin - implements AssistContributor { - ToStringAssistContributor(this.filePath); - - final String filePath; - - @override - late final DartAssistRequest assistRequest; - - @override - late final AssistCollector collector; - - AnalysisSession get session => assistRequest.result.session; - - @override - Future computeAssists( - covariant DartAssistRequest request, - AssistCollector collector, - ) async { - assistRequest = request; - this.collector = collector; - - final ClassDeclaration? classNode = findClassDeclaration(); - if (classNode != null && classNode.members.isNotEmpty && classNode.declaredElement != null) { - await _generateToString( - node: classNode, - element: classNode.declaredElement!, - classMembers: classNode.members, - rightBracketOffset: classNode.rightBracket.offset, - ); - } - - final EnumDeclaration? enumNode = findEnumDeclaration(); - if (enumNode != null && enumNode.declaredElement != null) { - await _generateToString( - node: enumNode, - element: enumNode.declaredElement!, - classMembers: enumNode.members, - rightBracketOffset: enumNode.rightBracket.offset, - ); - } - } - - Future _generateToString({ - required final AstNode node, - required final NodeList classMembers, - required final InterfaceElement element, - required final int rightBracketOffset, - }) async { - if (element.hasUnionAnnotation || element.hasDataClassAnnotation || element.hasEnumAnnotation) { - return; - } - - final SourceRange? toStringSourceRange = classMembers.toStringSourceRange; - - final List fields = [ - ...element.dataClassFinalFields, - ...element.chainSuperClassDataClassFinalFields, - ]; - - final ChangeBuilder changeBuilder = ChangeBuilder(session: session); - await changeBuilder.addDartFileEdit( - filePath, - (DartFileEditBuilder fileEditBuilder) { - void writerToString(DartEditBuilder builder) { - late final String elementName; - if (element is EnumElement) { - elementName = '${element.name}.\$name'; - } else { - elementName = (element as ClassElement) - .thisType - .typeStringValue(enclosingImports: element.library.libraryImports); - } - - ToStringGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: elementName, - optimizedClassName: element.name, - commentClassName: element.name, - fields: fields, - ).execute(); - } - - if (toStringSourceRange != null) { - fileEditBuilder.addReplacement(toStringSourceRange, writerToString); - } else { - fileEditBuilder.addInsertion( - rightBracketOffset, - writerToString, - ); - } - - fileEditBuilder.format(SourceRange(node.offset, node.length)); - }, - ); - - addAssist(AvailableAssists.toString2, changeBuilder); - } -} diff --git a/package/lib/src/contributors/enum/enum_annotation_assist_contributor.dart b/package/lib/src/contributors/enum/enum_annotation_assist_contributor.dart index 3b95a69..850167b 100644 --- a/package/lib/src/contributors/enum/enum_annotation_assist_contributor.dart +++ b/package/lib/src/contributors/enum/enum_annotation_assist_contributor.dart @@ -1,5 +1,4 @@ import 'package:analyzer/dart/analysis/session.dart'; -import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/source/source_range.dart'; import 'package:analyzer_plugin/utilities/assist/assist.dart'; @@ -7,13 +6,13 @@ import 'package:analyzer_plugin/utilities/assist/assist_contributor_mixin.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; import 'package:data_class_plugin/src/annotations/enum_internal.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; import 'package:data_class_plugin/src/contributors/available_assists.dart'; import 'package:data_class_plugin/src/contributors/enum/enum_contributors.dart'; import 'package:data_class_plugin/src/contributors/generators/generators.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/mixins.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; +import 'package:tachyon/tachyon.dart'; class EnumAnnotationAssistContributor extends Object with AssistContributorMixin, EnumAstVisitorMixin, RelativeFilePathMixin diff --git a/package/lib/src/contributors/generators/copy_with.dart b/package/lib/src/contributors/generators/copy_with.dart index d44056e..cc7d060 100644 --- a/package/lib/src/contributors/generators/copy_with.dart +++ b/package/lib/src/contributors/generators/copy_with.dart @@ -1,7 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class CopyWithGenerator implements Generator { CopyWithGenerator({ diff --git a/package/lib/src/contributors/generators/from_json.dart b/package/lib/src/contributors/generators/from_json.dart index 6885258..faf85f2 100644 --- a/package/lib/src/contributors/generators/from_json.dart +++ b/package/lib/src/contributors/generators/from_json.dart @@ -1,12 +1,12 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:data_class_plugin/src/annotations/json_key_internal.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/contributors/class/utils.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/json_key_name_convention.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; +import 'package:tachyon/tachyon.dart'; class FromJsonGenerator implements Generator { /// Shorthand constructor @@ -198,7 +198,7 @@ class FromJsonGenerator implements Generator { }) { final String? fieldType = type.element!.name; - if (type.isDynamic) { + if (type is DynamicType) { _codeWriter ..writeln('// FIXME: variable is dynamic or contains a type that is not yet declared') ..writeln('$parentVariableName, '); diff --git a/package/lib/src/contributors/generators/hash_and_equals.dart b/package/lib/src/contributors/generators/hash_and_equals.dart index 8d47222..6cc0d82 100644 --- a/package/lib/src/contributors/generators/hash_and_equals.dart +++ b/package/lib/src/contributors/generators/hash_and_equals.dart @@ -1,6 +1,6 @@ import 'package:analyzer/dart/element/element.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; +import 'package:tachyon/tachyon.dart'; class HashGenerator implements Generator { HashGenerator({ diff --git a/package/lib/src/contributors/generators/to_json.dart b/package/lib/src/contributors/generators/to_json.dart index 79f88dc..5c1a638 100644 --- a/package/lib/src/contributors/generators/to_json.dart +++ b/package/lib/src/contributors/generators/to_json.dart @@ -1,12 +1,12 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:data_class_plugin/src/annotations/json_key_internal.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/contributors/class/utils.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; import 'package:data_class_plugin/src/json_key_name_convention.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; +import 'package:tachyon/tachyon.dart'; class ToJsonGenerator implements Generator { ToJsonGenerator({ @@ -161,7 +161,7 @@ class ToJsonGenerator implements Generator { required final DartType type, required final String parentVariableName, }) { - if (type.isDynamic || type.isPrimary) { + if (type is DynamicType || type.isPrimary) { _codeWriter.writeln('$parentVariableName,'); return; } diff --git a/package/lib/src/contributors/generators/to_string.dart b/package/lib/src/contributors/generators/to_string.dart index 7c50d89..fe51484 100644 --- a/package/lib/src/contributors/generators/to_string.dart +++ b/package/lib/src/contributors/generators/to_string.dart @@ -1,7 +1,7 @@ import 'package:analyzer/dart/element/element.dart'; -import 'package:data_class_plugin/src/backend/core/generators/generator.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; +import 'package:data_class_plugin/src/common/generator.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class ToStringGenerator implements Generator { ToStringGenerator({ diff --git a/package/lib/src/contributors_delegates/file_generation/file_generation_data_class_delegate.dart b/package/lib/src/contributors_delegates/file_generation/file_generation_data_class_delegate.dart index 7ee937f..dbd915e 100644 --- a/package/lib/src/contributors_delegates/file_generation/file_generation_data_class_delegate.dart +++ b/package/lib/src/contributors_delegates/file_generation/file_generation_data_class_delegate.dart @@ -1,14 +1,14 @@ -import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/source/source_range.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; import 'package:data_class_plugin/src/annotations/constants.dart'; import 'package:data_class_plugin/src/annotations/data_class_internal.dart'; -import 'package:data_class_plugin/src/backend/core/custom_dart_type.dart'; import 'package:data_class_plugin/src/common/utils.dart'; import 'package:data_class_plugin/src/contributors_delegates/class_generation_delegate.dart'; import 'package:data_class_plugin/src/exceptions.dart'; import 'package:data_class_plugin/src/extensions/extensions.dart'; +import 'package:tachyon/tachyon.dart'; class FileGenerationDataClassDelegate extends ClassGenerationDelegate { FileGenerationDataClassDelegate({ @@ -49,12 +49,17 @@ class FileGenerationDataClassDelegate extends ClassGenerationDelegate { field.getter!.isAbstract; }).toList(growable: false); - final List finalFieldsDeclarations = classNode.members - .where((ClassMember member) { - return member is FieldDeclaration && member.fields.isFinal; - }) - .toList(growable: false) - .cast(); + final List finalFieldsDeclarations = + classNode.members.whereType().where((FieldDeclaration field) { + if (!field.fields.isFinal || field.fields.variables.length != 1) { + return false; + } + final VariableDeclaration finalField = field.fields.variables[0]; + if (finalField.name.lexeme[0] == '_' || finalField.initializer != null) { + return false; + } + return true; + }).toList(growable: false); final Set classFieldsNames = { for (final FieldElement field in fields) field.name, @@ -342,17 +347,17 @@ class FileGenerationDataClassDelegate extends ClassGenerationDelegate { } for (final FieldDeclaration fieldDeclaration in finalFieldsDeclarations) { - final CustomDartType customDartType = fieldDeclaration.fields.type.customDartType; - if (!(customDartType.isDynamic || customDartType.isNullable)) { + final TachyonDartType dartType = fieldDeclaration.fields.type.customDartType; + if (!(dartType.isDynamic || dartType.isNullable)) { builder.write('required'); } for (final VariableDeclaration variableDeclaration in fieldDeclaration.fields.variables) { - builder.writeln(' ${customDartType.fullTypeName} ${variableDeclaration.name.lexeme},'); + builder.writeln(' ${dartType.fullTypeName} ${variableDeclaration.name.lexeme},'); } } for (final FieldElement field in [...superClassFields, ...fields]) { - if (!(field.type.isDynamic || + if (!(field.type is DynamicType || field.type.isNullable || field.getter!.hasDefaultValueAnnotation)) { builder.write('required'); diff --git a/package/lib/src/contributors_delegates/file_generation/file_generation_union_delegate.dart b/package/lib/src/contributors_delegates/file_generation/file_generation_union_delegate.dart index 452faf7..9329297 100644 --- a/package/lib/src/contributors_delegates/file_generation/file_generation_union_delegate.dart +++ b/package/lib/src/contributors_delegates/file_generation/file_generation_union_delegate.dart @@ -1,3 +1,4 @@ +import 'package:analyzer/dart/analysis/features.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/source/source_range.dart'; @@ -47,13 +48,31 @@ class FileGenerationUnionDelegate extends ClassGenerationDelegate { RedirectedConstructorsVisitor(result: {}); classNode.visitChildren(redirectedConstructorsVisitor); - if (!classElement.isAbstract) { - fileEditBuilder.addInsertion( - classNode.classKeyword.offset, - (DartEditBuilder builder) { - builder.write('abstract '); - }, - ); + if (compilationUnit.featureSet.isEnabled(Feature.sealed_class)) { + if (classNode.abstractKeyword != null) { + fileEditBuilder.addDeletion(SourceRange( + classNode.abstractKeyword!.offset, + classNode.abstractKeyword!.length, + )); + } + + if (classNode.sealedKeyword == null) { + fileEditBuilder.addInsertion( + classNode.classKeyword.offset, + (DartEditBuilder builder) { + builder.write('sealed '); + }, + ); + } + } else { + if (classNode.abstractKeyword == null) { + fileEditBuilder.addInsertion( + classNode.classKeyword.offset, + (DartEditBuilder builder) { + builder.write('abstract '); + }, + ); + } } void createDefaultConstructor(DartEditBuilder builder) { diff --git a/package/lib/src/contributors_delegates/in_place/in_place_data_class_delegate.dart b/package/lib/src/contributors_delegates/in_place/in_place_data_class_delegate.dart deleted file mode 100644 index d601844..0000000 --- a/package/lib/src/contributors_delegates/in_place/in_place_data_class_delegate.dart +++ /dev/null @@ -1,240 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:analyzer/source/source_range.dart'; -import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; -import 'package:data_class_plugin/src/annotations/data_class_internal.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; -import 'package:data_class_plugin/src/contributors/class/class_contributors.dart'; -import 'package:data_class_plugin/src/contributors/generators/generators.dart'; -import 'package:data_class_plugin/src/contributors_delegates/class_generation_delegate.dart'; -import 'package:data_class_plugin/src/extensions/extensions.dart'; - -class InPlaceDataClassDelegate extends ClassGenerationDelegate { - InPlaceDataClassDelegate({ - required super.relativeFilePath, - required super.targetFilePath, - required super.changeBuilder, - required super.pluginOptions, - required super.classNodes, - }); - - @override - Future generate() async { - await changeBuilder.addDartFileEdit(targetFilePath, (DartFileEditBuilder fileEditBuilder) { - for (final ClassDeclaration classNode in classNodes) { - final ClassElement classElement = classNode.declaredElement!; - - final DataClassInternal dataClassAnnotation = DataClassInternal.fromDartObject( - classElement.metadata.dataClassAnnotation!.computeConstantValue(), - ); - - final SourceRange? constructorSourceRange = classNode.members.defaultConstructorSourceRange; - final SourceRange? copyWithSourceRange = classNode.members.copyWithSourceRange; - final SourceRange? equalsSourceRange = classNode.members.equalsSourceRange; - final SourceRange? hashCodeSourceRange = classNode.members.hashSourceRange; - final SourceRange? toStringSourceRange = classNode.members.toStringSourceRange; - final SourceRange? fromJsonSourceRange = classNode.members.fromJsonSourceRange; - final SourceRange? toJsonSourceRange = classNode.members.toJsonSourceRange; - - final List fields = [ - ...classElement.dataClassFinalFields, - ...classElement.chainSuperClassDataClassFinalFields, - ]; - - void writerConstructor(DartEditBuilder builder) { - ShorthandConstructorAssistContributor.writeConstructor( - classElement: classElement, - builder: builder, - members: classNode.members, - ); - } - - if (constructorSourceRange != null) { - fileEditBuilder.addReplacement( - constructorSourceRange, - writerConstructor, - ); - } else { - fileEditBuilder.addInsertion( - classNode.leftBracket.offset + 1, - writerConstructor, - ); - } - - if (dataClassAnnotation.$toString ?? - pluginOptions.dataClass.effectiveToString(relativeFilePath)) { - void writerToString(DartEditBuilder builder) { - ToStringGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: classElement.thisType - .typeStringValue(enclosingImports: classElement.library.libraryImports) - .prefixGenericArgumentsWithDollarSign(), - optimizedClassName: classElement.name, - commentClassName: classElement.name, - fields: fields, - ).execute(); - } - - if (toStringSourceRange != null) { - fileEditBuilder.addReplacement( - toStringSourceRange, - writerToString, - ); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerToString, - ); - } - } else if (toStringSourceRange != null) { - fileEditBuilder.addDeletion(toStringSourceRange); - } - - if (dataClassAnnotation.hashAndEquals ?? - pluginOptions.dataClass.effectiveHashAndEquals(relativeFilePath)) { - void writerHashCode(DartEditBuilder builder) { - HashGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - fields: fields, - ).execute(); - } - - void writerEquals(DartEditBuilder builder) { - EqualsGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: classElement.thisType - .typeStringValue(enclosingImports: classElement.library.libraryImports), - fields: fields, - ).execute(); - } - - if (hashCodeSourceRange != null) { - fileEditBuilder.addReplacement(hashCodeSourceRange, writerHashCode); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerHashCode, - ); - } - - if (equalsSourceRange != null) { - fileEditBuilder.addReplacement(equalsSourceRange, writerEquals); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerEquals, - ); - } - } else { - if (hashCodeSourceRange != null) { - fileEditBuilder.addDeletion(hashCodeSourceRange); - } - - if (equalsSourceRange != null) { - fileEditBuilder.addDeletion(equalsSourceRange); - } - } - - if (dataClassAnnotation.copyWith ?? - pluginOptions.dataClass.effectiveCopyWith(relativeFilePath)) { - void writerCopyWith(DartEditBuilder builder) { - CopyWithGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: classElement.thisType - .typeStringValue(enclosingImports: classElement.library.libraryImports), - commentClassName: classElement.name, - classElement: classElement, - fields: fields, - annotateWithOverride: classElement.supertype?.classElement?.methods - .any((MethodElement method) => method.name == 'copyWith') ?? - false, - ).execute(); - } - - if (copyWithSourceRange != null) { - fileEditBuilder.addReplacement(copyWithSourceRange, writerCopyWith); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerCopyWith, - ); - } - } else if (copyWithSourceRange != null) { - fileEditBuilder.addDeletion(copyWithSourceRange); - } - - if (dataClassAnnotation.toJson ?? - pluginOptions.dataClass.effectiveToJson(relativeFilePath)) { - void writerToJson(DartEditBuilder builder) { - ToJsonGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: classElement.name, - fields: fields, - annotateWithOverride: classElement.supertype?.classElement?.methods - .any((MethodElement method) => method.name == 'toJson') ?? - false, - libraryImports: classElement.library.libraryImports, - targetFileRelativePath: relativeFilePath, - pluginOptions: pluginOptions, - checkIfShouldUseToJson: (DartType type) { - return type.element == classElement; - }, - ).execute(); - } - - if (toJsonSourceRange != null) { - fileEditBuilder.addReplacement(toJsonSourceRange, writerToJson); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerToJson, - ); - } - } else if (toJsonSourceRange != null) { - fileEditBuilder.addDeletion(toJsonSourceRange); - } - - if (dataClassAnnotation.fromJson ?? - pluginOptions.dataClass.effectiveFromJson(relativeFilePath)) { - final ConstructorElement? defaultConstructor = classElement.defaultConstructor; - - void writerFromJson(DartEditBuilder builder) { - FromJsonGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: classElement.thisType - .typeStringValue(enclosingImports: classElement.library.libraryImports), - fields: fields, - factoryClassName: classElement.name, - hasConstConstructor: defaultConstructor?.isConst ?? false, - libraryImports: classElement.library.libraryImports, - targetFileRelativePath: relativeFilePath, - pluginOptions: pluginOptions, - checkIfShouldUseFromJson: (DartType type) { - return type.element == classElement; - }, - getDefaultValueForField: (String fieldName) { - return defaultConstructor?.parameters - .firstWhereOrNull((ParameterElement param) => param.name == fieldName) - ?.defaultValueCode; - }, - ).execute(); - } - - if (fromJsonSourceRange != null) { - fileEditBuilder.addReplacement(fromJsonSourceRange, writerFromJson); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerFromJson, - ); - } - } else if (fromJsonSourceRange != null) { - fileEditBuilder.addDeletion(fromJsonSourceRange); - } - - fileEditBuilder.format(SourceRange(classNode.offset, classNode.length)); - } - }); - } -} diff --git a/package/lib/src/contributors_delegates/in_place/in_place_union_delegate.dart b/package/lib/src/contributors_delegates/in_place/in_place_union_delegate.dart deleted file mode 100644 index 6ce1b48..0000000 --- a/package/lib/src/contributors_delegates/in_place/in_place_union_delegate.dart +++ /dev/null @@ -1,561 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/dart/element/type.dart'; -import 'package:analyzer/source/source_range.dart'; -import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; -import 'package:data_class_plugin/src/annotations/constants.dart'; -import 'package:data_class_plugin/src/annotations/union_internal.dart'; -import 'package:data_class_plugin/src/common/code_writer.dart'; -import 'package:data_class_plugin/src/contributors/generators/generators.dart'; -import 'package:data_class_plugin/src/contributors_delegates/class_generation_delegate.dart'; -import 'package:data_class_plugin/src/extensions/extensions.dart'; -import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; -import 'package:data_class_plugin/src/visitors/class_visitor.dart'; -import 'package:data_class_plugin/src/visitors/redirected_constructor_visitor.dart'; - -class InPlaceUnionDelegate extends ClassGenerationDelegate { - InPlaceUnionDelegate({ - required super.relativeFilePath, - required super.targetFilePath, - required super.changeBuilder, - required super.pluginOptions, - required super.classNodes, - required this.compilationUnit, - }); - - final CompilationUnit compilationUnit; - - @override - Future generate() async { - await _generateConstructor(); - } - - Future _generateConstructor() async { - await changeBuilder.addDartFileEdit(targetFilePath, (DartFileEditBuilder fileEditBuilder) { - for (final ClassDeclaration classNode in classNodes) { - final ClassElement classElement = classNode.declaredElement!; - - final UnionInternal unionInternalAnnotation = UnionInternal.fromDartObject( - classElement.metadata.unionAnnotation!.computeConstantValue(), - ); - - final RedirectedConstructorsVisitor redirectedConstructorsVisitor = - RedirectedConstructorsVisitor(result: {}); - classNode.visitChildren(redirectedConstructorsVisitor); - - if (!classElement.isAbstract) { - fileEditBuilder.addInsertion( - classNode.classKeyword.offset, - (DartEditBuilder builder) { - builder.write('abstract '); - }, - ); - } - - _generateWhenFunction( - classElement: classElement, - classNode: classNode, - redirectedConstructors: redirectedConstructorsVisitor.result, - fileEditBuilder: fileEditBuilder, - ); - - _generateMaybeWhenFunction( - classElement: classElement, - classNode: classNode, - redirectedConstructors: redirectedConstructorsVisitor.result, - fileEditBuilder: fileEditBuilder, - ); - - _generateGenerativeConstructor( - classNode: classNode, - classElement: classElement, - fileEditBuilder: fileEditBuilder, - ); - - if (unionInternalAnnotation.fromJson ?? - pluginOptions.union.effectiveFromJson(relativeFilePath)) { - _generateFromJsonFunction( - classNode: classNode, - classElement: classElement, - fileEditBuilder: fileEditBuilder, - ); - } - - if (unionInternalAnnotation.toJson ?? - pluginOptions.union.effectiveToJson(relativeFilePath)) { - _generateToJsonFunction( - classNode: classNode, - classElement: classElement, - fileEditBuilder: fileEditBuilder, - ); - } - - _generateUnionImplementors( - classElement: classElement, - classNode: classNode, - redirectedConstructors: redirectedConstructorsVisitor.result, - fileEditBuilder: fileEditBuilder, - unionInternalAnnotation: unionInternalAnnotation, - pluginOptions: pluginOptions, - ); - - fileEditBuilder.format(SourceRange(classNode.offset, classNode.length)); - } - }); - } - - void _generateMaybeWhenFunction({ - required final ClassElement classElement, - required final Map redirectedConstructors, - required final ClassDeclaration classNode, - required final DartFileEditBuilder fileEditBuilder, - }) { - final SourceRange? whenFunctionSourceRange = - classNode.members.getSourceRangeForMethod('maybeWhen'); - - void writerMaybeWhenFunction(DartEditBuilder builder) { - _writeMaybeWhenFunction( - classElement: classElement, - builder: builder, - redirectedConstructors: redirectedConstructors, - ); - } - - if (whenFunctionSourceRange != null) { - fileEditBuilder.addReplacement( - whenFunctionSourceRange, - writerMaybeWhenFunction, - ); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerMaybeWhenFunction, - ); - } - } - - void _generateWhenFunction({ - required final ClassElement classElement, - required final Map redirectedConstructors, - required final ClassDeclaration classNode, - required final DartFileEditBuilder fileEditBuilder, - }) { - final SourceRange? mapFunctionSourceRange = classNode.members.getSourceRangeForMethod('when'); - - void writerWhenFunction(DartEditBuilder builder) { - _writeWhenFunction( - classElement: classElement, - builder: builder, - redirectedConstructors: redirectedConstructors, - ); - } - - if (mapFunctionSourceRange != null) { - fileEditBuilder.addReplacement( - mapFunctionSourceRange, - writerWhenFunction, - ); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerWhenFunction, - ); - } - } - - void _generateUnionImplementors({ - required final ClassElement classElement, - required final ClassDeclaration classNode, - required final Map redirectedConstructors, - required final DartFileEditBuilder fileEditBuilder, - required final UnionInternal unionInternalAnnotation, - required final DataClassPluginOptions pluginOptions, - }) { - for (final ConstructorElement ctor in classElement.constructors.reversed) { - if (!ctor.isFactory || ctor.name.isEmpty || ctor.name == UnionAnnotationArg.fromJson.name) { - continue; - } - - final RedirectedConstructor redirectedCtor = redirectedConstructors[ctor.name]!; - - final ClassAstVisitor classVisitor = ClassAstVisitor(matcher: (ClassDeclaration node) { - return redirectedCtor.name == node.name.lexeme; - }); - compilationUnit.visitChildren(classVisitor); - - SourceRange? sourceRange; - if (classVisitor.classNode != null) { - sourceRange = SourceRange( - classVisitor.classNode!.offset, - classVisitor.classNode!.length, - ); - } - - void writerUnionClass(DartEditBuilder builder) { - _writeUnionClasses( - classElement: classElement, - builder: builder, - constructorElement: ctor, - redirectedCtor: redirectedCtor, - unionInternalAnnotation: unionInternalAnnotation, - pluginOptions: pluginOptions, - ); - } - - if (sourceRange != null) { - fileEditBuilder.addReplacement( - sourceRange, - writerUnionClass, - ); - } else { - fileEditBuilder.addInsertion( - 2 + classNode.rightBracket.offset, - writerUnionClass, - ); - } - } - } - - void _generateGenerativeConstructor({ - required final ClassElement classElement, - required final ClassDeclaration classNode, - required final DartFileEditBuilder fileEditBuilder, - }) { - final SourceRange? sourceRange = classNode.members.getSourceRangeForConstructor('_'); - - void writerGenerativeConstructor(DartEditBuilder builder) { - _writeGenerativeConstructor( - classElement: classElement, - builder: builder, - ); - } - - if (sourceRange != null) { - fileEditBuilder.addReplacement( - sourceRange, - writerGenerativeConstructor, - ); - } else { - fileEditBuilder.addInsertion( - 1 + classNode.leftBracket.offset, - writerGenerativeConstructor, - ); - } - } - - void _generateFromJsonFunction({ - required final ClassDeclaration classNode, - required final ClassElement classElement, - required final DartFileEditBuilder fileEditBuilder, - }) { - final SourceRange? sourceRange = classNode.members.fromJsonSourceRange; - - if (sourceRange == null) { - fileEditBuilder.addInsertion( - 1 + classNode.leftBracket.offset, - (DartEditBuilder builder) => - _writeFromJsonFunction(classElement: classElement, builder: builder), - ); - } - } - - void _generateToJsonFunction({ - required final ClassDeclaration classNode, - required final ClassElement classElement, - required final DartFileEditBuilder fileEditBuilder, - }) { - final SourceRange? sourceRange = classNode.members.toJsonSourceRange; - - void writerToJsonFunction(DartEditBuilder builder) { - _writeToJsonFunction( - classElement: classElement, - builder: builder, - ); - } - - if (sourceRange != null) { - fileEditBuilder.addReplacement( - sourceRange, - writerToJsonFunction, - ); - } else { - fileEditBuilder.addInsertion( - classNode.rightBracket.offset, - writerToJsonFunction, - ); - } - } - - void _writeUnionClasses({ - required final ClassElement classElement, - required final DartEditBuilder builder, - required final ConstructorElement constructorElement, - required final RedirectedConstructor redirectedCtor, - required final UnionInternal unionInternalAnnotation, - required final DataClassPluginOptions pluginOptions, - }) { - final CodeWriter codeWriter = CodeWriter.dartEditBuilder(builder); - // Contains default values of constructor parameters - final Map defaultValues = {}; - - final List sharedFields = classElement.fields.where((FieldElement field) { - return field.getter != null && field.getter!.isGetter && field.getter!.isAbstract; - }).toList(growable: false); - - codeWriter - ..writeln('class $redirectedCtor extends ${classElement.thisType} {') - ..writeln('const ${redirectedCtor.name}('); - - if (constructorElement.parameters.isNotEmpty) { - codeWriter.write('{'); - - for (final ParameterElement param in constructorElement.parameters) { - final ElementAnnotation? defaultValueAnnotation = param.metadata.firstWhereOrNull( - (ElementAnnotation annotation) => annotation.isDefaultValueAnnotation); - - if (!param.type.isNullable && defaultValueAnnotation == null) { - codeWriter.write('required '); - } - - codeWriter.write('this.${param.name}'); - - if (defaultValueAnnotation != null) { - // toSource will provide a value like "@DefaultValue(User(username: 'test'))" - // so we extract everything between the first pair of parenthesis - final String? extractedValue = - RegExp(r'\((.*)\)').firstMatch(defaultValueAnnotation.toSource())?.group(1)?.trim(); - - if (extractedValue != null) { - codeWriter.write(' = '); - - // if the extractedValue contains a pair of parenthesis we assume - // that this is an instance declaration so we prefix with const - bool isConst = false; - if (extractedValue.contains(RegExp(r'\(.*\)'))) { - codeWriter.write('const '); - isConst = true; - } - codeWriter.write(extractedValue); - - defaultValues[param.name] = '${isConst ? 'const' : ''} $extractedValue'; - } - } - - codeWriter.writeln(','); - } - - codeWriter.write('}'); - } - - codeWriter - ..writeln('): super._();') - ..writeln(); - - for (final ParameterElement param in constructorElement.parameters) { - if (sharedFields.any((VariableElement field) => field.name == param.name)) { - codeWriter.writeln('@override'); - } - codeWriter.writeln( - 'final ${param.type.typeStringValue(enclosingImports: classElement.library.libraryImports)} ${param.name};'); - } - - if (unionInternalAnnotation.fromJson ?? - pluginOptions.union.effectiveFromJson(relativeFilePath)) { - FromJsonGenerator( - codeWriter: codeWriter, - className: '$redirectedCtor', - factoryClassName: redirectedCtor.name, - fields: constructorElement.parameters, - hasConstConstructor: constructorElement.isConst, - libraryImports: classElement.library.libraryImports, - targetFileRelativePath: relativeFilePath, - pluginOptions: pluginOptions, - checkIfShouldUseFromJson: (DartType type) { - return type.element == classElement; - }, - getDefaultValueForField: (String fieldName) => defaultValues[fieldName], - ).execute(); - } - - if (unionInternalAnnotation.toJson ?? pluginOptions.union.effectiveToJson(relativeFilePath)) { - ToJsonGenerator( - codeWriter: codeWriter, - className: redirectedCtor.name, - fields: constructorElement.parameters, - annotateWithOverride: true, - libraryImports: classElement.library.libraryImports, - targetFileRelativePath: relativeFilePath, - pluginOptions: pluginOptions, - checkIfShouldUseToJson: (DartType type) { - return type.element == classElement; - }, - ).execute(); - } - - if (unionInternalAnnotation.copyWith ?? - pluginOptions.union.effectiveCopyWith(relativeFilePath)) { - CopyWithGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: '$redirectedCtor', - commentClassName: redirectedCtor.name, - classElement: classElement, - fields: constructorElement.parameters, - annotateWithOverride: false, - ).execute(); - } - if (unionInternalAnnotation.hashAndEquals ?? - pluginOptions.union.effectiveHashAndEquals(relativeFilePath)) { - HashGenerator( - codeWriter: codeWriter, - fields: constructorElement.parameters, - ).execute(); - - EqualsGenerator( - codeWriter: codeWriter, - className: '$redirectedCtor', - fields: constructorElement.parameters, - ).execute(); - } - - if (unionInternalAnnotation.$toString ?? - pluginOptions.union.effectiveToString(relativeFilePath)) { - ToStringGenerator( - codeWriter: CodeWriter.dartEditBuilder(builder), - className: '$redirectedCtor'.prefixGenericArgumentsWithDollarSign(), - optimizedClassName: redirectedCtor.name, - commentClassName: redirectedCtor.name, - fields: constructorElement.parameters, - ).execute(); - } - - codeWriter.writeln('}'); - } - - void _writeWhenFunction({ - required final ClassElement classElement, - required final DartEditBuilder builder, - required final Map redirectedConstructors, - }) { - final List constructors = classElement.constructors - .where((ConstructorElement ctor) => ctor.isFactory) - .toList(growable: false); - - builder - ..writeln() - ..writeln('/// Executes one of the provided callbacks based on a type match') - ..writeln('R when({'); - - for (final ConstructorElement ctor in constructors) { - final RedirectedConstructor? redirectedCtor = redirectedConstructors[ctor.name]; - - if (redirectedCtor == null) { - continue; - } - - if (ctor.parameters.isNotEmpty) { - builder.writeln('required R Function($redirectedCtor value) ${ctor.name},'); - } else { - builder.writeln('required R Function() ${ctor.name},'); - } - } - - builder.writeln('}) {'); - - for (final ConstructorElement ctor in constructors) { - final RedirectedConstructor? redirectedCtor = redirectedConstructors[ctor.name]; - - if (redirectedCtor == null) { - continue; - } - - builder.writeln('if (this is $redirectedCtor) {' - 'return ${ctor.name}(' - "${ctor.parameters.isNotEmpty ? 'this as $redirectedCtor' : ''}" - ');}'); - } - - builder - ..writeln("throw UnimplementedError('Unknown instance of \$this used in when(..)');") - ..writeln('}'); - } - - void _writeMaybeWhenFunction({ - required final ClassElement classElement, - required final DartEditBuilder builder, - required final Map redirectedConstructors, - }) { - final List constructors = classElement.constructors - .where((ConstructorElement ctor) => ctor.isFactory) - .toList(growable: false); - - builder - ..writeln() - ..writeln('/// Executes one of the provided callbacks if a type is matched') - ..writeln('///') - ..writeln('/// If no match is found [orElse] is executed') - ..writeln('R maybeWhen({'); - - for (final ConstructorElement ctor in constructors) { - final RedirectedConstructor? redirectedCtor = redirectedConstructors[ctor.name]; - - if (redirectedCtor == null) { - continue; - } - - if (ctor.parameters.isNotEmpty) { - builder.writeln('R Function($redirectedCtor value)? ${ctor.name},'); - } else { - builder.writeln('R Function()? ${ctor.name},'); - } - } - - builder - ..writeln('required R Function() orElse,') - ..writeln('}) {'); - - for (final ConstructorElement ctor in constructors) { - final RedirectedConstructor? redirectedCtor = redirectedConstructors[ctor.name]; - - if (redirectedCtor == null) { - continue; - } - - builder.writeln('if (this is $redirectedCtor) {' - 'return ${ctor.name}?.call(' - "${ctor.parameters.isNotEmpty ? 'this as $redirectedCtor' : ''}" - ') ?? orElse();' - '}'); - } - - builder - ..writeln("throw UnimplementedError('Unknown instance of \$this used in maybeWhen(..)');") - ..writeln('}'); - } - - void _writeGenerativeConstructor({ - required final ClassElement classElement, - required final DartEditBuilder builder, - }) { - builder.writeln('const ${classElement.name}._();'); - } - - void _writeFromJsonFunction({ - required final ClassElement classElement, - required final DartEditBuilder builder, - }) { - builder - ..writeln('/// Creates an instance of [${classElement.name}] from [json]') - ..writeln('factory ${classElement.name}.fromJson(Map json) {') - ..writeln('throw UnimplementedError();') - ..writeln('}'); - } - - void _writeToJsonFunction({ - required final ClassElement classElement, - required final DartEditBuilder builder, - }) { - builder - ..writeln('/// Converts [${classElement.name}] to [Map] json') - ..writeln('Map toJson();'); - } -} diff --git a/package/lib/src/exceptions.gen.dart b/package/lib/src/exceptions.gen.dart index 3b56851..ecf7e73 100644 --- a/package/lib/src/exceptions.gen.dart +++ b/package/lib/src/exceptions.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'exceptions.dart'; diff --git a/package/lib/src/extensions/annotation_extensions.dart b/package/lib/src/extensions/annotation_extensions.dart index 8b06711..fd42b97 100644 --- a/package/lib/src/extensions/annotation_extensions.dart +++ b/package/lib/src/extensions/annotation_extensions.dart @@ -33,25 +33,11 @@ extension ClassDeclarationX on ClassDeclaration { Annotation? get unionAnnotation => metadata.getAnnotation(AnnotationType.union); List get annotations => metadata.annotations; - - bool hasMethod(String methodName) { - return null != - members.firstWhereOrNull((ClassMember member) { - return member is MethodDeclaration && member.name.lexeme == methodName; - }); - } } extension EnumDeclarationX on EnumDeclaration { bool get hasEnumAnnotation => enumAnnotation != null; Annotation? get enumAnnotation => metadata.getAnnotation(AnnotationType.enumeration); - - bool hasMethod(String methodName) { - return null != - members.firstWhereOrNull((ClassMember member) { - return member is MethodDeclaration && member.name.lexeme == methodName; - }); - } } extension ElementAnnotationX on ElementAnnotation { @@ -109,6 +95,11 @@ extension AnnotationNodeListX on NodeList { return annotations; } + + bool hasAnnotationWithName(String name) => any((Annotation element) => element.name.name == name); + + Annotation? getAnnotationWithName(String name) => + firstWhereOrNull((Annotation element) => element.name.name == name); } extension AnnotationX on Annotation { diff --git a/package/lib/src/extensions/core_extensions.dart b/package/lib/src/extensions/core_extensions.dart index 2ce5c02..bb019ff 100644 --- a/package/lib/src/extensions/core_extensions.dart +++ b/package/lib/src/extensions/core_extensions.dart @@ -31,9 +31,13 @@ extension IterableX on Iterable { extension FolderX on Folder { Future getPluginOptions() async { - return await DataClassPluginOptions.fromFile((io.File( - utils.getDataClassPluginOptionsPath(path), - ))); + try { + return DataClassPluginOptions.fromFile((io.File( + utils.getDataClassPluginOptionsPath(path), + ))); + } catch (_) { + return const DataClassPluginOptions(); + } } } diff --git a/package/lib/src/options/data_class_options.gen.dart b/package/lib/src/options/data_class_options.gen.dart index 9178d31..b580d63 100644 --- a/package/lib/src/options/data_class_options.gen.dart +++ b/package/lib/src/options/data_class_options.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'data_class_options.dart'; diff --git a/package/lib/src/options/data_class_plugin_options.dart b/package/lib/src/options/data_class_plugin_options.dart index 9e4335d..e21dc64 100644 --- a/package/lib/src/options/data_class_plugin_options.dart +++ b/package/lib/src/options/data_class_plugin_options.dart @@ -2,38 +2,18 @@ import 'dart:io' as io show File; import 'package:data_class_plugin/data_class_plugin.dart'; import 'package:data_class_plugin/src/options/options.dart'; -import 'package:glob/glob.dart'; import 'package:yaml/yaml.dart'; export 'options.dart'; part 'data_class_plugin_options.gen.dart'; -@Enum(fromJson: true) -enum CodeGenerationMode { - inPlace('in_place'), - file('file'); - - /// Default constructor of [CodeGenerationMode] - const CodeGenerationMode(this.name); - - final String name; - - /// Creates an instance of [CodeGenerationMode] from [json] - factory CodeGenerationMode.fromJson(String json) { - return CodeGenerationMode.values.firstWhere((CodeGenerationMode e) => e.name == json); - } -} - @DataClass() abstract class DataClassPluginOptions { const DataClassPluginOptions.ctor(); /// Default constructor const factory DataClassPluginOptions({ - CodeGenerationMode generationMode, - List allowedFilesGenerationPaths, - int generatedFileLineLength, JsonOptions json, DataClassOptions dataClass, EnumOptions $enum, @@ -44,17 +24,6 @@ abstract class DataClassPluginOptions { factory DataClassPluginOptions.fromJson(Map json) = _$DataClassPluginOptionsImpl.fromJson; - @DefaultValue(CodeGenerationMode.file) - CodeGenerationMode get generationMode; - - @JsonKey(name: 'file_generation_paths') - @_AllowedFilesGenerationPathFieldJsonConverter() - @DefaultValue([]) - List get allowedFilesGenerationPaths; - - @DefaultValue(80) - int get generatedFileLineLength; - @DefaultValue(JsonOptions()) JsonOptions get json; @@ -68,33 +37,7 @@ abstract class DataClassPluginOptions { @DefaultValue(UnionOptions()) UnionOptions get union; - static Future fromFile(io.File file) async { - try { - final YamlMap yaml = await file.readAsString().then((String value) => loadYaml(value)); - return DataClassPluginOptions.fromJson(yaml); - } catch (_) { - return const DataClassPluginOptions(); - } - } -} - -class _AllowedFilesGenerationPathFieldJsonConverter - implements JsonConverter, List?> { - const _AllowedFilesGenerationPathFieldJsonConverter(); - - @override - List fromJson(List? value, Map json, String keyName) { - if (value == null) { - return const []; - } - - return List.unmodifiable([ - for (final String path in value) Glob(path), - ]); - } - - @override - List toJson(List value) { - throw UnimplementedError(); + static DataClassPluginOptions fromFile(io.File file) { + return DataClassPluginOptions.fromJson(loadYaml(file.readAsStringSync())); } } diff --git a/package/lib/src/options/data_class_plugin_options.gen.dart b/package/lib/src/options/data_class_plugin_options.gen.dart index 63e53fa..38226aa 100644 --- a/package/lib/src/options/data_class_plugin_options.gen.dart +++ b/package/lib/src/options/data_class_plugin_options.gen.dart @@ -1,31 +1,16 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'data_class_plugin_options.dart'; class _$DataClassPluginOptionsImpl extends DataClassPluginOptions { const _$DataClassPluginOptionsImpl({ - this.generationMode = CodeGenerationMode.file, - List allowedFilesGenerationPaths = const [], - this.generatedFileLineLength = 80, this.json = const JsonOptions(), this.dataClass = const DataClassOptions(), this.$enum = const EnumOptions(), this.union = const UnionOptions(), - }) : _allowedFilesGenerationPaths = allowedFilesGenerationPaths, - super.ctor(); - - @override - final CodeGenerationMode generationMode; - - @override - List get allowedFilesGenerationPaths => - List.unmodifiable(_allowedFilesGenerationPaths); - final List _allowedFilesGenerationPaths; - - @override - final int generatedFileLineLength; + }) : super.ctor(); @override final JsonOptions json; @@ -41,12 +26,6 @@ class _$DataClassPluginOptionsImpl extends DataClassPluginOptions { factory _$DataClassPluginOptionsImpl.fromJson(Map json) { return _$DataClassPluginOptionsImpl( - generationMode: json['generation_mode'] == null - ? CodeGenerationMode.file - : CodeGenerationMode.fromJson(json['generation_mode']), - allowedFilesGenerationPaths: const _AllowedFilesGenerationPathFieldJsonConverter() - .fromJson(json['file_generation_paths'], json, 'file_generation_paths'), - generatedFileLineLength: json['generated_file_line_length'] as int? ?? 80, json: json['json'] == null ? const JsonOptions() : JsonOptions.fromJson(json['json']), dataClass: json['data_class'] == null ? const DataClassOptions() diff --git a/package/lib/src/options/enum_options.gen.dart b/package/lib/src/options/enum_options.gen.dart index 27665f0..51fae0b 100644 --- a/package/lib/src/options/enum_options.gen.dart +++ b/package/lib/src/options/enum_options.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'enum_options.dart'; diff --git a/package/lib/src/options/extensions.dart b/package/lib/src/options/extensions.dart index 1813482..f2775c8 100644 --- a/package/lib/src/options/extensions.dart +++ b/package/lib/src/options/extensions.dart @@ -45,6 +45,10 @@ extension OptionsGlobMatch on Map { return _effectiveValue('unmodifiable_collections', filePath, defaultValue); } + bool effectiveWhen({required String filePath, required bool defaultValue}) { + return _effectiveValue('when', filePath, defaultValue); + } + bool _effectiveValue( String method, String filePath, diff --git a/package/lib/src/options/json_options.gen.dart b/package/lib/src/options/json_options.gen.dart index 331d4f0..e730dbb 100644 --- a/package/lib/src/options/json_options.gen.dart +++ b/package/lib/src/options/json_options.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'json_options.dart'; diff --git a/package/lib/src/options/options_config.gen.dart b/package/lib/src/options/options_config.gen.dart index 25a75f7..c473f12 100644 --- a/package/lib/src/options/options_config.gen.dart +++ b/package/lib/src/options/options_config.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'options_config.dart'; diff --git a/package/lib/src/options/union_options.dart b/package/lib/src/options/union_options.dart index a10af4c..4f1ea5d 100644 --- a/package/lib/src/options/union_options.dart +++ b/package/lib/src/options/union_options.dart @@ -36,4 +36,7 @@ abstract class UnionOptions { bool effectiveUnmodifiableCollections(String filePath) => optionsConfig.effectiveUnmodifiableCollections(filePath: filePath, defaultValue: true); + + bool effectiveWhen(String filePath) => + optionsConfig.effectiveWhen(filePath: filePath, defaultValue: true); } diff --git a/package/lib/src/options/union_options.gen.dart b/package/lib/src/options/union_options.gen.dart index 40c6389..610ce39 100644 --- a/package/lib/src/options/union_options.gen.dart +++ b/package/lib/src/options/union_options.gen.dart @@ -1,6 +1,6 @@ // AUTO GENERATED - DO NOT MODIFY - -// ignore_for_file: library_private_types_in_public_api, unused_element, unused_field +// ignore_for_file: type=lint +// coverage:ignore-file part of 'union_options.dart'; diff --git a/package/lib/src/tools/logger/ansi.dart b/package/lib/src/tools/logger/ansi.dart deleted file mode 100644 index 6518852..0000000 --- a/package/lib/src/tools/logger/ansi.dart +++ /dev/null @@ -1,166 +0,0 @@ -// ignore_for_file: unnecessary_brace_in_string_interps - -const String escape = '\x1B'; -const String reset = '$escape[0m'; - -/// https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#color-codes -enum AnsiStyle { colored, bold, italic, underline, blinking, strikethrough } - -enum AnsiAlignment { left, right } - -enum AnsiColorType { foreground, background } - -enum AnsiColor { - black(30, 40), - red(31, 41), - green(32, 42), - yellow(33, 43), - blue(34, 44), - magenta(35, 45), - cyan(36, 46), - white(37, 47), - brightBlack(90, 100), - brightRed(91, 101), - brightGreen(92, 102), - brightYellow(93, 103), - brightBlue(94, 104), - brightMagenta(95, 105), - brightCyan(96, 106), - brightWhite(97, 107); - - /// Default constructor of [AnsiColor] - const AnsiColor( - this.foregroundCode, - this.backgroundCode, - ); - - final int foregroundCode; - final int backgroundCode; - - String get foreground => foregroundCode.toAnsiColor(); - - String get background => backgroundCode.toAnsiColor(); -} - -extension on int { - String toAnsiColor() => '$escape[${this}m'; -} - -extension AnsiText on String { - String colored(AnsiColor? color, [AnsiColorType type = AnsiColorType.foreground]) { - if (color == null) { - return this; - } - - final String colorCode = type == AnsiColorType.foreground ? color.foreground : color.background; - return '$colorCode${this}$reset'; - } - - String coloredByCode(String color) => color.isEmpty ? this : '$color${this}$reset'; - - String bold() => '$escape[1m${this}$escape[22m'; - - String italic() => '$escape[3m${this}$escape[23m'; - - String underline() => '$escape[4m${this}$escape[24m'; - - String blinking() => '$escape[5m${this}$escape[25m'; - - String strikethrough() => '$escape[9m${this}$escape[29m'; - - String pad(AnsiAlignment padding, int width) => - padding == AnsiAlignment.left ? padRight(width) : padLeft(width); - - String styled(List styles, [AnsiColor? color]) { - String text = this; - - for (final AnsiStyle style in styles) { - switch (style) { - case AnsiStyle.colored: - if (color != null) { - text = text.colored(color); - } - break; - - case AnsiStyle.bold: - text = text.bold(); - break; - - case AnsiStyle.italic: - text = text.italic(); - break; - - case AnsiStyle.underline: - text = text.underline(); - break; - - case AnsiStyle.blinking: - text = text.blinking(); - break; - - case AnsiStyle.strikethrough: - text = text.strikethrough(); - break; - } - } - - if (color != null && !styles.contains(AnsiStyle.colored)) { - text = text.colored(color); - } - - return text; - } - - String black() => colored(AnsiColor.black); - - String red() => colored(AnsiColor.red); - - String green() => colored(AnsiColor.green); - - String yellow() => colored(AnsiColor.yellow); - - String blue() => colored(AnsiColor.blue); - - String magenta() => colored(AnsiColor.magenta); - - String cyan() => colored(AnsiColor.cyan); - - String white() => colored(AnsiColor.white); - - String brightBlack() => colored(AnsiColor.brightBlack); - - String brightRed() => colored(AnsiColor.brightRed); - - String brightGreen() => colored(AnsiColor.brightGreen); - - String brightYellow() => colored(AnsiColor.brightYellow); - - String brightBlue() => colored(AnsiColor.brightBlue); - - String brightMagenta() => colored(AnsiColor.brightMagenta); - - String brightCyan() => colored(AnsiColor.brightCyan); - - String brightWhite() => colored(AnsiColor.brightWhite); -} - -enum HorizontalLineStyle { - single('─'), - bold('━'), - double('═'), - dash('-'); - - /// Default constructor of [HorizontalLineStyle] - const HorizontalLineStyle(this.value); - - final String value; -} - -class Ansi { - static String horizontalLine({ - final int length = 50, - final HorizontalLineStyle style = HorizontalLineStyle.single, - }) { - return style.value * length; - } -} diff --git a/package/lib/src/tools/logger/console_logger.dart b/package/lib/src/tools/logger/console_logger.dart deleted file mode 100644 index d7227b5..0000000 --- a/package/lib/src/tools/logger/console_logger.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'dart:io'; - -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; -import 'package:data_class_plugin/src/tools/logger/logger.dart'; -import 'package:stack_trace/stack_trace.dart'; - -class ConsoleLogger extends Logger { - ConsoleLogger(IOSink? ioSink) : _sink = ioSink ?? stdout; - - final IOSink _sink; - - @override - void write([final Object? object]) { - _sink.write(object); - } - - @override - void writeln([final Object? object]) { - _sink.writeln(object); - } - - @override - void info([final Object? object]) { - log('$object'.blue(), LogSeverity.info); - } - - @override - void debug([final Object? object]) { - log('$object'.cyan(), LogSeverity.debug); - } - - @override - void warning([final Object? object]) { - log('$object'.yellow(), LogSeverity.warning); - } - - @override - void error( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]) { - log('$error'.red(), LogSeverity.error); - - if (st != null) { - log(Ansi.horizontalLine(), LogSeverity.error); - log('Stacktrace:'.red().bold(), LogSeverity.error); - log('$st'.red(), LogSeverity.error); - log(Ansi.horizontalLine(), LogSeverity.error); - } - } - - @override - void exception( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]) { - _sink.writeln(Ansi.horizontalLine()); - _sink.writeln('An exception was thrown:'.red().bold()); - _sink.writeln(error.toString().red()); - - final StackTrace stackTrace = st ?? Trace([Trace.current(1).frames[0]]); - _sink.writeln(Ansi.horizontalLine()); - _sink.writeln('Stacktrace:'.red().bold()); - _sink.writeln('$stackTrace'.red()); - _sink.writeln(Ansi.horizontalLine()); - } - - @override - void logHeader(LogHeader header) { - final String line = Ansi.horizontalLine( - length: header.lineLength, - style: header.lineStyle, - ).bold(); - - writeln(line); - writeln( - header.title // - .padLeft((header.title.length + header.lineLength) ~/ 2) - .blue() - .bold(), - ); - - if (header.subtitle != null && header.subtitle!.isNotEmpty) { - writeln(header.subtitle!.padLeft((header.subtitle!.length + header.lineLength) ~/ 2)); - } - writeln(line); - } - - @override - Future dispose() async { - await _sink.flush(); - await _sink.close(); - } -} diff --git a/package/lib/src/tools/logger/file_logger.dart b/package/lib/src/tools/logger/file_logger.dart deleted file mode 100644 index dc9b893..0000000 --- a/package/lib/src/tools/logger/file_logger.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:io'; - -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; -import 'package:data_class_plugin/src/tools/logger/logger.dart'; -import 'package:path/path.dart'; - -class FileLogger extends Logger { - FileLogger() { - final String logFilePath = _getFilePath(); - final File logFile = File(logFilePath)..createSync(); - _sink = logFile.openWrite(); - } - - late final IOSink _sink; - - @override - void write([final Object? object]) { - _sink.write(object ?? ''); - } - - @override - void writeln([final Object? object]) { - log(object, LogSeverity.debug); - } - - @override - void info([final Object? object]) { - log(object, LogSeverity.info); - } - - @override - void debug([final Object? object]) { - log(object, LogSeverity.debug); - } - - @override - void warning([final Object? object]) { - log(object, LogSeverity.warning); - } - - @override - void error( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]) { - log(error, LogSeverity.error); - - if (st != null) { - log(Ansi.horizontalLine(), LogSeverity.error); - log('Stacktrace:', LogSeverity.error); - log(st.toString(), LogSeverity.error); - log(Ansi.horizontalLine(), LogSeverity.error); - } - } - - @override - void exception( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]) { - log(Ansi.horizontalLine(), LogSeverity.fatal); - log('An exception was thrown:', LogSeverity.fatal); - log(error, LogSeverity.fatal); - - log(Ansi.horizontalLine(), LogSeverity.fatal); - log('Stacktrace:', LogSeverity.fatal); - log(st.toString(), LogSeverity.fatal); - log(Ansi.horizontalLine(), LogSeverity.fatal); - } - - @override - Future dispose() async { - await _sink.flush(); - await _sink.close(); - } - - @override - void logHeader(LogHeader header) { - final String line = Ansi.horizontalLine( - length: header.lineLength, - style: header.lineStyle, - ); - - writeln(line); - writeln(header.title.padLeft((header.title.length + header.lineLength) ~/ 2)); - - if (header.subtitle != null && header.subtitle!.isNotEmpty) { - writeln(header.subtitle!.padLeft((header.subtitle!.length + header.lineLength) ~/ 2)); - } - writeln(line); - } - - String _getFilePath() { - final DateTime now = DateTime.now(); - - final String month = now.month.toString().padLeft(2, '0'); - final String day = now.day.toString().padLeft(2, '0'); - final String hour = now.hour.toString().padLeft(2, '0'); - final String minute = now.minute.toString().padLeft(2, '0'); - final String second = now.second.toString().padLeft(2, '0'); - - return join( - Directory.current.path, - 'logs', - '${now.year}$month${day}_$hour$minute$second.log', - ); - } -} diff --git a/package/lib/src/tools/logger/logger.dart b/package/lib/src/tools/logger/logger.dart deleted file mode 100644 index 76c804a..0000000 --- a/package/lib/src/tools/logger/logger.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; - -enum LogSeverity { debug, info, warning, error, fatal } - -abstract class Logger { - void write([final Object? object]); - void writeln([final Object? object]); - - void info([final Object? object]); - void debug([final Object? object]); - void warning([final Object? object]); - void error( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]); - - void exception( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]); - - void log(Object? object, LogSeverity? severity) { - if (object != null) { - object.toString().split('\n').forEach((String line) { - if (severity == null) { - writeln('${DateTime.now()}\t$line'); - } else { - writeln('${DateTime.now()}\t${severity.name.toUpperCase().padRight(10)}\t$line'); - } - }); - return; - } - - if (severity == null) { - writeln('${DateTime.now()}\t$object'); - } else { - writeln('${DateTime.now()}\t${severity.name.toUpperCase().padRight(10)}\t$object'); - } - } - - void logHeader(LogHeader header); - - Future dispose(); -} - -class LogHeader { - /// Shorthand constructor - LogHeader({ - required this.title, - this.subtitle, - this.lineStyle = HorizontalLineStyle.single, - this.lineLength = 50, - }); - - final String title; - final String? subtitle; - final HorizontalLineStyle lineStyle; - final int lineLength; -} diff --git a/package/lib/src/tools/logger/no_op_logger.dart b/package/lib/src/tools/logger/no_op_logger.dart deleted file mode 100644 index de8e181..0000000 --- a/package/lib/src/tools/logger/no_op_logger.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:data_class_plugin/src/tools/logger/logger.dart'; - -class NoOpLogger extends Logger { - @override - Future dispose() async {} - - @override - void error( - Object? error, [ - StackTrace? st, - bool isFatal = false, - ]) {} - - @override - void exception( - Object? error, [ - StackTrace? st, - bool isFatal = false, - ]) {} - - @override - void info([Object? object]) {} - - @override - void debug([Object? object]) {} - - @override - void logHeader(LogHeader header) {} - - @override - void warning([Object? object]) {} - - @override - void write([Object? object]) {} - - @override - void writeln([Object? object]) {} -} diff --git a/package/lib/src/tools/logger/plugin_logger.dart b/package/lib/src/tools/logger/plugin_logger.dart deleted file mode 100644 index 5eee387..0000000 --- a/package/lib/src/tools/logger/plugin_logger.dart +++ /dev/null @@ -1,249 +0,0 @@ -import 'dart:io'; - -import 'package:analyzer_plugin/channel/channel.dart'; -import 'package:analyzer_plugin/protocol/protocol_common.dart'; -import 'package:analyzer_plugin/protocol/protocol_generated.dart'; -import 'package:data_class_plugin/src/tools/logger/ansi.dart'; -import 'package:data_class_plugin/src/tools/logger/console_logger.dart'; -import 'package:data_class_plugin/src/tools/logger/file_logger.dart'; -import 'package:data_class_plugin/src/tools/logger/logger.dart'; -import 'package:stack_trace/stack_trace.dart'; - -class PluginLogger extends Logger { - PluginLogger({ - final IOSink? ioSink, - }) { - registerLogger(ConsoleLogger(ioSink)); - } - - PluginCommunicationChannel? channel; - - set writeToFile(bool value) { - if (value) { - registerLogger(FileLogger()); - } else { - unregisterLogger(FileLogger); - } - } - - final List _loggers = []; - void registerLogger(Logger logger) { - _loggers.add(logger); - } - - void unregisterLogger(Type type) { - _loggers.removeWhere((Logger l) => l.runtimeType == type); - } - - @override - void write([final Object? object]) { - for (final Logger logger in _loggers) { - logger.write(object); - } - } - - @override - void writeln([final Object? object]) { - for (final Logger logger in _loggers) { - logger.writeln(object); - } - } - - @override - void info([final Object? object]) { - for (final Logger logger in _loggers) { - logger.info(object); - } - } - - @override - void debug([final Object? object]) { - for (final Logger logger in _loggers) { - logger.debug(object); - } - } - - @override - void warning([final Object? object]) { - for (final Logger logger in _loggers) { - logger.warning(object); - } - } - - @override - void error( - final Object? error, [ - final StackTrace? st, - final bool isFatal = false, - ]) { - for (final Logger logger in _loggers) { - logger.error(error, st, isFatal); - } - } - - @override - void exception( - final Object? error, [ - final StackTrace? st, - final bool isFatal = true, - ]) { - final StackTrace stackTrace = st ?? Trace([Trace.current(1).frames[0]]); - - for (final Logger logger in _loggers) { - logger.exception(error, st, isFatal); - } - - _showErrorNotification( - 'An exception was thrown: $error', - isFatal: isFatal, - stackTrace: stackTrace, - ); - } - - void notification(final Object message) { - info(message); - - // TODO: Replace PluginErrorParams - // https://github.com/JetBrains/intellij-plugins/blob/master/Dart/resources/messages/DartBundle.properties - // - // _channel?.sendNotification( - // Notification( - // 'daemon.logMessage', - // { - // 'level': 'info', - // 'title': 'Data Class Plugin', - // 'message': message, - // }, - // ), - // ); - - _showErrorNotification( - message.toString(), - isFatal: false, - ); - } - - void _showErrorNotification( - final String error, { - final StackTrace? stackTrace, - final bool isFatal = true, - }) { - channel?.sendNotification( - PluginErrorParams( - isFatal, - error, - stackTrace.toString(), - ).toNotification(), - ); - } - - void showAnalysisHint( - final String path, - final String message, { - final String? code, - final Location? location, - final List? messages, - final String? url, - }) { - showAnalysisMessage( - path, - message, - severity: AnalysisErrorSeverity.INFO, - type: AnalysisErrorType.HINT, - messages: messages, - url: url, - code: code, - location: location, - ); - } - - void showAnalysisWarning( - final String path, - final String message, { - final String? code, - final Location? location, - final List? messages, - final String? url, - }) { - showAnalysisMessage( - path, - message, - severity: AnalysisErrorSeverity.WARNING, - type: AnalysisErrorType.STATIC_WARNING, - messages: messages, - url: url, - code: code, - location: location, - ); - } - - void showAnalysisError( - final String path, - final String message, { - final String? code, - final Location? location, - final List? messages, - final String? url, - }) { - showAnalysisMessage( - path, - message, - severity: AnalysisErrorSeverity.ERROR, - type: AnalysisErrorType.COMPILE_TIME_ERROR, - messages: messages, - url: url, - code: code, - location: location, - ); - } - - void showAnalysisMessage( - final String path, - final String message, { - required final AnalysisErrorSeverity severity, - required final AnalysisErrorType type, - final String? code, - final Location? location, - final List? messages, - final String? url, - }) { - final Location defaultLocation = location ?? Location(path, 0, 1, 1, 1); - - channel?.sendNotification( - AnalysisErrorsParams(path, [ - AnalysisError( - severity, - type, - defaultLocation, - message, - code ?? 'data_class_plugin_error', - contextMessages: messages, - url: url, - ) - ]).toNotification(), - ); - } - - @override - void logHeader(LogHeader header) { - for (final Logger logger in _loggers) { - logger.logHeader(header); - } - } - - static LogHeader pluginHeader() { - return LogHeader( - title: 'Data Class Plugin', - subtitle: 'Code generation. Same, but different.', - lineStyle: HorizontalLineStyle.double, - lineLength: 70, - ); - } - - @override - Future dispose() async { - for (final Logger logger in _loggers) { - await logger.dispose(); - } - } -} diff --git a/package/lib/src/typedefs.dart b/package/lib/src/typedefs.dart index a2a9353..a5a3b03 100644 --- a/package/lib/src/typedefs.dart +++ b/package/lib/src/typedefs.dart @@ -1,6 +1,3 @@ -import 'package:analyzer/dart/ast/ast.dart'; import 'package:data_class_plugin/src/json_key_name_convention.dart'; -typedef ClassDeclarationNodeMatcher = bool Function(ClassDeclaration node); - typedef JsonKeyNameConventionGetter = JsonKeyNameConvention Function(String? availableConvention); diff --git a/package/lib/src/visitors/class_collector_visitor.dart b/package/lib/src/visitors/class_collector_visitor.dart deleted file mode 100644 index 94ba570..0000000 --- a/package/lib/src/visitors/class_collector_visitor.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/ast/visitor.dart'; -import 'package:data_class_plugin/src/typedefs.dart'; - -class ClassCollectorAstVisitor extends GeneralizingAstVisitor { - ClassCollectorAstVisitor({ - required this.matcher, - }); - - final ClassDeclarationNodeMatcher matcher; - - final List _matchesNodes = []; - List get matchedNodes => List.unmodifiable(_matchesNodes); - - @override - void visitClassDeclaration(ClassDeclaration node) { - if (matcher(node)) { - _matchesNodes.add(node); - return; - } - node.visitChildren(this); - } -} diff --git a/package/lib/src/visitors/class_visitor.dart b/package/lib/src/visitors/class_visitor.dart deleted file mode 100644 index 4f6c5e4..0000000 --- a/package/lib/src/visitors/class_visitor.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/ast/visitor.dart'; -import 'package:data_class_plugin/src/typedefs.dart'; - -class ClassAstVisitor extends RecursiveAstVisitor { - ClassAstVisitor({ - required this.matcher, - }); - - static ClassDeclarationNodeMatcher offsetMatcher(int offset) { - return (ClassDeclaration node) { - return node.offset <= offset && offset <= node.rightBracket.offset; - }; - } - - final ClassDeclarationNodeMatcher matcher; - - ClassDeclaration? _classNode; - ClassDeclaration? get classNode => _classNode; - - @override - void visitClassDeclaration(ClassDeclaration node) { - if (matcher(node)) { - _classNode = node; - } - - if (_classNode != null) { - return; - } - - node.visitChildren(this); - } -} diff --git a/package/lib/src/visitors/visitors.dart b/package/lib/src/visitors/visitors.dart index e3e5cba..ea20ca6 100644 --- a/package/lib/src/visitors/visitors.dart +++ b/package/lib/src/visitors/visitors.dart @@ -1,4 +1,4 @@ -export 'class_collector_visitor.dart'; -export 'class_visitor.dart'; +export 'package:tachyon/tachyon.dart' show ClassAstVisitor, ClassCollectorAstVisitor; + export 'enum_visitor.dart'; export 'redirected_constructor_visitor.dart'; diff --git a/package/pubspec.lock b/package/pubspec.lock deleted file mode 100644 index 9672740..0000000 --- a/package/pubspec.lock +++ /dev/null @@ -1,397 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" - url: "https://pub.dev" - source: hosted - version: "50.0.0" - analyzer: - dependency: "direct main" - description: - name: analyzer - sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" - url: "https://pub.dev" - source: hosted - version: "5.2.0" - analyzer_plugin: - dependency: "direct main" - description: - name: analyzer_plugin - sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d - url: "https://pub.dev" - source: hosted - version: "0.11.2" - args: - dependency: "direct main" - description: - name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 - url: "https://pub.dev" - source: hosted - version: "2.3.1" - async: - dependency: transitive - description: - name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 - url: "https://pub.dev" - source: hosted - version: "2.10.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - collection: - dependency: transitive - description: - name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 - url: "https://pub.dev" - source: hosted - version: "1.17.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: d2494157c32b303f47dedee955b1479f2979c4ff66934eb7c0def44fd9e0267a - url: "https://pub.dev" - source: hosted - version: "1.6.1" - crypto: - dependency: transitive - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" - source: hosted - version: "3.0.2" - dart_style: - dependency: "direct main" - description: - name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" - url: "https://pub.dev" - source: hosted - version: "2.2.4" - file: - dependency: "direct main" - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "82715f8041a85a534a7bf64400b2ee0bb3d594ccf695d97c0bb017259657ff5d" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - glob: - dependency: "direct main" - description: - name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - 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: "0d4c73c3653ab85bf696d51a9657604c900a370549196a91f33e4c39af760852" - url: "https://pub.dev" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" - url: "https://pub.dev" - source: hosted - version: "0.6.5" - lints: - dependency: "direct dev" - description: - name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - logging: - dependency: transitive - description: - name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 - url: "https://pub.dev" - source: hosted - version: "1.1.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" - url: "https://pub.dev" - source: hosted - version: "0.12.13" - meta: - dependency: "direct main" - description: - name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" - url: "https://pub.dev" - source: hosted - version: "1.8.0" - mime: - dependency: transitive - description: - name: mime - sha256: dab22e92b41aa1255ea90ddc4bc2feaf35544fd0728e209638cad041a6e3928a - url: "https://pub.dev" - source: hosted - version: "1.0.2" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: "direct main" - description: - name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b - url: "https://pub.dev" - source: hosted - version: "1.8.2" - 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: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - rxdart: - dependency: "direct main" - description: - name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" - source: hosted - version: "0.27.7" - shelf: - dependency: transitive - description: - name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c - url: "https://pub.dev" - source: hosted - version: "1.4.0" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 - url: "https://pub.dev" - source: hosted - version: "3.0.1" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c - url: "https://pub.dev" - source: hosted - version: "1.1.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - 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: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" - url: "https://pub.dev" - source: hosted - version: "0.10.11" - source_span: - dependency: transitive - description: - name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" - source: hosted - version: "1.9.1" - stack_trace: - dependency: "direct main" - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - 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 dev" - description: - name: test - sha256: "98403d1090ac0aa9e33dfc8bf45cc2e0c1d5c58d7cb832cee1e50bf14f37961d" - url: "https://pub.dev" - source: hosted - version: "1.22.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: c9282698e2982b6c3817037554e52f99d4daba493e8028f8112a83d68ccd0b12 - url: "https://pub.dev" - source: hosted - version: "0.4.17" - test_core: - dependency: transitive - description: - name: test_core - sha256: c9e4661a5e6285b795d47ba27957ed8b6f980fc020e98b218e276e88aff02168 - url: "https://pub.dev" - source: hosted - version: "0.4.21" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 - url: "https://pub.dev" - source: hosted - version: "9.4.0" - watcher: - dependency: "direct main" - description: - name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - yaml: - dependency: "direct main" - description: - name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" - url: "https://pub.dev" - source: hosted - version: "3.1.1" -sdks: - dart: ">=2.18.0 <3.0.0" diff --git a/package/pubspec.yaml b/package/pubspec.yaml index b6dab75..f228bbd 100644 --- a/package/pubspec.yaml +++ b/package/pubspec.yaml @@ -1,5 +1,5 @@ name: data_class_plugin -version: 0.3.1 +version: 1.0.0 description: A tool that uses Dart's Analyzer to generate code on-the-fly. homepage: https://github.com/spideythewebhead/dart_data_class_plugin @@ -8,22 +8,20 @@ documentation: https://github.com/spideythewebhead/dart_data_class_plugin issue_tracker: https://github.com/spideythewebhead/dart_data_class_plugin/issues environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: analyzer: ">=4.0.0 <6.0.0" analyzer_plugin: ">=0.10.0 <1.0.0" - args: ^2.3.1 - dart_style: ^2.2.4 - meta: ^1.8.0 - yaml: ^3.1.1 - glob: ^2.1.1 - path: ^1.8.2 - file: ^6.1.4 - stack_trace: ^1.10.0 - watcher: ^1.0.2 - rxdart: ^0.27.7 + args: ^2.4.1 + dart_style: ^2.3.1 + meta: ^1.9.1 + yaml: ^3.1.2 + glob: ^2.1.2 + path: ^1.8.3 + file: ">=6.0.0 <8.0.0" + tachyon: ^0.0.5 dev_dependencies: - lints: ^2.0.1 - test: ^1.22.1 + lints: ^2.1.0 + test: ^1.24.3 diff --git a/package/tachyon_config.yaml b/package/tachyon_config.yaml new file mode 100644 index 0000000..9f8243b --- /dev/null +++ b/package/tachyon_config.yaml @@ -0,0 +1,10 @@ +file_generation_paths: + - "lib/src/options/**" + - "lib/src/backend/core/find_package_path_by_import.dart" + - "lib/src/backend/core/parsed_file_data.dart" + - "lib/src/exceptions.dart" + +generated_file_line_length: 100 + +plugins: + - data_class_plugin diff --git a/package/tachyon_plugin_config.yaml b/package/tachyon_plugin_config.yaml new file mode 100644 index 0000000..21abbf3 --- /dev/null +++ b/package/tachyon_plugin_config.yaml @@ -0,0 +1,9 @@ +name: data_class_plugin + +code_generator: + file: src/backend/code_generator.dart + className: DataClassPluginGenerator + +annotations: + - DataClass + - Union diff --git a/package/test/contributors/annotations/data_class/data_class_assist_contributor_test.dart b/package/test/contributors/annotations/data_class/data_class_assist_contributor_test.dart index b1df011..7f70522 100644 --- a/package/test/contributors/annotations/data_class/data_class_assist_contributor_test.dart +++ b/package/test/contributors/annotations/data_class/data_class_assist_contributor_test.dart @@ -21,8 +21,8 @@ final String _contributorsPath = path.join( void main() async { final List testFiles = getTestFiles(_contributorsPath); - final DataClassPluginOptions pluginOptions = await DataClassPluginOptions.fromFile( - File(path.join('test', 'data_class_plugin_options.yaml'))); + final DataClassPluginOptions pluginOptions = + DataClassPluginOptions.fromFile(File(path.join('test', 'data_class_plugin_options.yaml'))); group('DataClass annotation contributor', () { testFiles.runContributorTests( diff --git a/package/test/contributors/annotations/data_class/test_files/in_1.dart b/package/test/contributors/annotations/data_class/test_files/in_1.dart deleted file mode 100644 index 14c8b1b..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_1.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - $toString: true, - copyWith: false, - hashAndEquals: false, - fromJson: false, - toJson: false, -) -class ToStringTest {} diff --git a/package/test/contributors/annotations/data_class/test_files/in_10_from_json_snake_case.dart b/package/test/contributors/annotations/data_class/test_files/in_10_from_json_snake_case.dart deleted file mode 100644 index cbd874f..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_10_from_json_snake_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class SnakeCaseTest { - final String thisVariableWillBeSnakeCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_10_to_json_snake_case.dart b/package/test/contributors/annotations/data_class/test_files/in_10_to_json_snake_case.dart deleted file mode 100644 index 98b2f8b..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_10_to_json_snake_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class SnakeCaseTest { - final String thisVariableWillBeSnakeCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_11_super.dart b/package/test/contributors/annotations/data_class/test_files/in_11_super.dart deleted file mode 100644 index c5b1b74..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_11_super.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass() -class AdminUser extends User { - final String username; -} - -abstract class User { - /// Shorthand constructor - User({ - required this.id, - }); - - final String id; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_12_no_fields_const.dart b/package/test/contributors/annotations/data_class/test_files/in_12_no_fields_const.dart deleted file mode 100644 index 207f491..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_12_no_fields_const.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - copyWith: true, - hashAndEquals: false, - toJson: false, - $toString: false, -) -class User { - /// Shorthand constructor - const User(); -} - -// Should add '// ignore: prefer_const_constructors' in CopyWith() -// when constructor is const with no fields -// and create a 'fromJson' factory that returns a const instance diff --git a/package/test/contributors/annotations/data_class/test_files/in_13_no_fields.dart b/package/test/contributors/annotations/data_class/test_files/in_13_no_fields.dart deleted file mode 100644 index bb8ca25..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_13_no_fields.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - copyWith: true, - hashAndEquals: false, - toJson: false, - $toString: false, -) -class User { - /// Shorthand constructor - User(); -} - -// Should not add '// ignore: prefer_const_constructors' -// when constructor is const with no fields diff --git a/package/test/contributors/annotations/data_class/test_files/in_1_simple.dart b/package/test/contributors/annotations/data_class/test_files/in_1_simple.dart new file mode 100644 index 0000000..a3b0a81 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_1_simple.dart @@ -0,0 +1,8 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass() +class User { + int get id; + + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/in_2.dart b/package/test/contributors/annotations/data_class/test_files/in_2.dart deleted file mode 100644 index cf65eb5..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_2.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - copyWith: true, - $toString: false, - hashAndEquals: false, - fromJson: false, - toJson: false, -) -class CopyWithTest {} - -// Should create a [copyWith] method diff --git a/package/test/contributors/annotations/data_class/test_files/in_2_const_constructor.dart b/package/test/contributors/annotations/data_class/test_files/in_2_const_constructor.dart new file mode 100644 index 0000000..6f09ec3 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_2_const_constructor.dart @@ -0,0 +1,16 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass() +abstract class User { + User.ctor(); + + /// Default constructor + const factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/in_3.dart b/package/test/contributors/annotations/data_class/test_files/in_3.dart deleted file mode 100644 index 722cc25..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_3.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - hashAndEquals: true, - copyWith: false, - $toString: false, - fromJson: false, - toJson: false, -) -class HashAndEqualsTest {} - -// Should create a [hashCode] override method and [operator ==] override method diff --git a/package/test/contributors/annotations/data_class/test_files/in_3_from_json.dart b/package/test/contributors/annotations/data_class/test_files/in_3_from_json.dart new file mode 100644 index 0000000..1801d1e --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_3_from_json.dart @@ -0,0 +1,10 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass( + fromJson: true, +) +class User { + int get id; + + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/in_4.dart b/package/test/contributors/annotations/data_class/test_files/in_4.dart deleted file mode 100644 index 271dd21..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_4.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - hashAndEquals: false, - copyWith: false, - $toString: false, - toJson: false, -) -class FromJsonTest {} - -// Should create a [fromJson] factory constructor diff --git a/package/test/contributors/annotations/data_class/test_files/in_4_to_json.dart b/package/test/contributors/annotations/data_class/test_files/in_4_to_json.dart new file mode 100644 index 0000000..7a686b6 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_4_to_json.dart @@ -0,0 +1,10 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass( + toJson: true, +) +class User { + int get id; + + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/in_5.dart b/package/test/contributors/annotations/data_class/test_files/in_5.dart deleted file mode 100644 index d5c3385..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_5.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - hashAndEquals: false, - copyWith: false, - $toString: false, -) -class ToJsonTest {} - -// Should create a [toJson] method diff --git a/package/test/contributors/annotations/data_class/test_files/in_5_default_value.dart b/package/test/contributors/annotations/data_class/test_files/in_5_default_value.dart new file mode 100644 index 0000000..051d6fb --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_5_default_value.dart @@ -0,0 +1,11 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass() +class User { + int get id; + + String get username; + + @DefaultValue('') + String get email; +} diff --git a/package/test/contributors/annotations/data_class/test_files/in_6_convert_final_fields_to_getters.dart b/package/test/contributors/annotations/data_class/test_files/in_6_convert_final_fields_to_getters.dart new file mode 100644 index 0000000..c068870 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_6_convert_final_fields_to_getters.dart @@ -0,0 +1,10 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass() +class User { + final int id; + final String username; + + @DefaultValue('') + String get email; +} diff --git a/package/test/contributors/annotations/data_class/test_files/in_7_from_json_camel_case.dart b/package/test/contributors/annotations/data_class/test_files/in_7_from_json_camel_case.dart deleted file mode 100644 index 866074b..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_7_from_json_camel_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class CamelCaseTest { - final String thisVariableWillBeCamelCase; - final String thisvariablewillnotbecamelcase; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_7_inheritance.dart b/package/test/contributors/annotations/data_class/test_files/in_7_inheritance.dart new file mode 100644 index 0000000..3f28438 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/in_7_inheritance.dart @@ -0,0 +1,19 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@DataClass() +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; +} + +@DataClass() +class SuperUser extends User {} diff --git a/package/test/contributors/annotations/data_class/test_files/in_7_to_json_camel_case.dart b/package/test/contributors/annotations/data_class/test_files/in_7_to_json_camel_case.dart deleted file mode 100644 index 7fdf39a..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_7_to_json_camel_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class CamelCaseTest { - final String thisVariableWillBeCamelCase; - final String thisvariablewillnotbecamelcase; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_8_from_json_kebab_case.dart b/package/test/contributors/annotations/data_class/test_files/in_8_from_json_kebab_case.dart deleted file mode 100644 index 50179bb..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_8_from_json_kebab_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class KebabCaseTest { - final String thisVariableWillBeKebabCase; - final String thisvariablewillnotbekebabcase; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_8_to_json_kebab_case.dart b/package/test/contributors/annotations/data_class/test_files/in_8_to_json_kebab_case.dart deleted file mode 100644 index 6b03994..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_8_to_json_kebab_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class KebabCaseTest { - final String thisVariableWillBeKebabCase; - final String thisvariablewillnotbekebabcase; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_9_from_json_pascal_case.dart b/package/test/contributors/annotations/data_class/test_files/in_9_from_json_pascal_case.dart deleted file mode 100644 index 8ee719d..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_9_from_json_pascal_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class PascalCaseTest { - final String thisVariableWillBePascalCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/in_9_to_json_pascal_case.dart b/package/test/contributors/annotations/data_class/test_files/in_9_to_json_pascal_case.dart deleted file mode 100644 index 3053b20..0000000 --- a/package/test/contributors/annotations/data_class/test_files/in_9_to_json_pascal_case.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class PascalCaseTest { - final String thisVariableWillBePascalCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_1.dart b/package/test/contributors/annotations/data_class/test_files/out_1.dart deleted file mode 100644 index e046069..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_1.dart +++ /dev/null @@ -1,22 +0,0 @@ -@DataClass( - $toString: true, - copyWith: false, - hashAndEquals: false, - fromJson: false, - toJson: false, -) -class ToStringTest { - /// Shorthand constructor - ToStringTest(); - - /// Returns a string with the properties of [ToStringTest] - @override - String toString() { - String value = 'ToStringTest{}'; - assert(() { - value = 'ToStringTest@<$hexIdentity>{}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_10_from_json_snake_case.dart b/package/test/contributors/annotations/data_class/test_files/out_10_from_json_snake_case.dart deleted file mode 100644 index 56094c0..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_10_from_json_snake_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class SnakeCaseTest { - /// Shorthand constructor - SnakeCaseTest({ - required this.thisVariableWillBeSnakeCase, - required this.onewordvariable, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBeSnakeCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Creates an instance of [SnakeCaseTest] from [json] - factory SnakeCaseTest.fromJson(Map json) { - return SnakeCaseTest( - thisVariableWillBeSnakeCase: json['this_variable_will_be_snake_case'] as String, - onewordvariable: json['onewordvariable'] as String, - thisIsAVariable: json['this_is_a_variable'] as String, - aNumber11Variable: json['a_number_11_variable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_10_to_json_snake_case.dart b/package/test/contributors/annotations/data_class/test_files/out_10_to_json_snake_case.dart deleted file mode 100644 index 8acf661..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_10_to_json_snake_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class SnakeCaseTest { - /// Shorthand constructor - SnakeCaseTest({ - required this.thisVariableWillBeSnakeCase, - required this.onewordvariable, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBeSnakeCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Converts [SnakeCaseTest] to a [Map] json - Map toJson() { - return { - 'this_variable_will_be_snake_case': thisVariableWillBeSnakeCase, - 'onewordvariable': onewordvariable, - 'this_is_a_variable': thisIsAVariable, - 'a_number_11_variable': aNumber11Variable, - }; - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_11_super.dart b/package/test/contributors/annotations/data_class/test_files/out_11_super.dart deleted file mode 100644 index 7ec6f7c..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_11_super.dart +++ /dev/null @@ -1,53 +0,0 @@ -@DataClass() -class AdminUser extends User { - /// Shorthand constructor - AdminUser({ - required super.id, - required this.username, - }); - - final String username; - - /// Returns a string with the properties of [AdminUser] - @override - String toString() { - String value = 'AdminUser{}'; - assert(() { - value = 'AdminUser@<$hexIdentity>{username: $username, id: $id}'; - return true; - }()); - return value; - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - username, - id, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AdminUser && - runtimeType == other.runtimeType && - username == other.username && - id == other.id; - } - - /// Creates a new instance of [AdminUser] with optional new values - AdminUser copyWith({ - final String? username, - final String? id, - }) { - return AdminUser( - username: username ?? this.username, - id: id ?? this.id, - ); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_12_no_fields_const.dart b/package/test/contributors/annotations/data_class/test_files/out_12_no_fields_const.dart deleted file mode 100644 index 897c84b..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_12_no_fields_const.dart +++ /dev/null @@ -1,22 +0,0 @@ -@DataClass( - fromJson: true, - copyWith: true, - hashAndEquals: false, - toJson: false, - $toString: false, -) -class User { - /// Shorthand constructor - const User(); - - /// Creates a new instance of [User] with optional new values - User copyWith() { - // ignore: prefer_const_constructors - return User(); - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return const User(); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_13_no_fields.dart b/package/test/contributors/annotations/data_class/test_files/out_13_no_fields.dart deleted file mode 100644 index b76c50a..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_13_no_fields.dart +++ /dev/null @@ -1,21 +0,0 @@ -@DataClass( - fromJson: true, - copyWith: true, - hashAndEquals: false, - toJson: false, - $toString: false, -) -class User { - /// Shorthand constructor - User(); - - /// Creates a new instance of [User] with optional new values - User copyWith() { - return User(); - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User(); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_1_simple.dart b/package/test/contributors/annotations/data_class/test_files/out_1_simple.dart new file mode 100644 index 0000000..7e34c0e --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_1_simple.dart @@ -0,0 +1,16 @@ +part 'in_1_simple.gen.dart'; + +@DataClass() +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_2.dart b/package/test/contributors/annotations/data_class/test_files/out_2.dart deleted file mode 100644 index 6980892..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_2.dart +++ /dev/null @@ -1,16 +0,0 @@ -@DataClass( - copyWith: true, - $toString: false, - hashAndEquals: false, - fromJson: false, - toJson: false, -) -class CopyWithTest { - /// Shorthand constructor - CopyWithTest(); - - /// Creates a new instance of [CopyWithTest] with optional new values - CopyWithTest copyWith() { - return CopyWithTest(); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_2_const_constructor.dart b/package/test/contributors/annotations/data_class/test_files/out_2_const_constructor.dart new file mode 100644 index 0000000..6b89bc4 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_2_const_constructor.dart @@ -0,0 +1,16 @@ +part 'in_2_const_constructor.gen.dart'; + +@DataClass() +abstract class User { + const User.ctor(); + + /// Default constructor + const factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_3.dart b/package/test/contributors/annotations/data_class/test_files/out_3.dart deleted file mode 100644 index 090e369..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_3.dart +++ /dev/null @@ -1,26 +0,0 @@ -@DataClass( - hashAndEquals: true, - copyWith: false, - $toString: false, - fromJson: false, - toJson: false, -) -class HashAndEqualsTest { - /// Shorthand constructor - HashAndEqualsTest(); - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || other is HashAndEqualsTest && runtimeType == other.runtimeType; - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_3_from_json.dart b/package/test/contributors/annotations/data_class/test_files/out_3_from_json.dart new file mode 100644 index 0000000..03b7d13 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_3_from_json.dart @@ -0,0 +1,21 @@ +part 'in_3_from_json.gen.dart'; + +@DataClass( + fromJson: true, +) +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; + + /// Creates an instance of [User] from [json] + factory User.fromJson(Map json) = _$UserImpl.fromJson; +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_4.dart b/package/test/contributors/annotations/data_class/test_files/out_4.dart deleted file mode 100644 index 5cb8713..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_4.dart +++ /dev/null @@ -1,16 +0,0 @@ -@DataClass( - fromJson: true, - hashAndEquals: false, - copyWith: false, - $toString: false, - toJson: false, -) -class FromJsonTest { - /// Shorthand constructor - FromJsonTest(); - - /// Creates an instance of [FromJsonTest] from [json] - factory FromJsonTest.fromJson(Map json) { - return FromJsonTest(); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_4_to_json.dart b/package/test/contributors/annotations/data_class/test_files/out_4_to_json.dart new file mode 100644 index 0000000..cff9436 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_4_to_json.dart @@ -0,0 +1,21 @@ +part 'in_4_to_json.gen.dart'; + +@DataClass( + toJson: true, +) +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; + + /// Converts [User] to a [Map] json + Map toJson(); +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_5.dart b/package/test/contributors/annotations/data_class/test_files/out_5.dart deleted file mode 100644 index 04b29a4..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_5.dart +++ /dev/null @@ -1,16 +0,0 @@ -@DataClass( - toJson: true, - fromJson: false, - hashAndEquals: false, - copyWith: false, - $toString: false, -) -class ToJsonTest { - /// Shorthand constructor - ToJsonTest(); - - /// Converts [ToJsonTest] to a [Map] json - Map toJson() { - return {}; - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_5_default_value.dart b/package/test/contributors/annotations/data_class/test_files/out_5_default_value.dart new file mode 100644 index 0000000..144757d --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_5_default_value.dart @@ -0,0 +1,20 @@ +part 'in_5_default_value.gen.dart'; + +@DataClass() +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + String email, + }) = _$UserImpl; + + int get id; + + String get username; + + @DefaultValue('') + String get email; +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_6_convert_final_fields_to_getters.dart b/package/test/contributors/annotations/data_class/test_files/out_6_convert_final_fields_to_getters.dart new file mode 100644 index 0000000..34c9f20 --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_6_convert_final_fields_to_getters.dart @@ -0,0 +1,20 @@ +part 'in_6_convert_final_fields_to_getters.gen.dart'; + +@DataClass() +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + String email, + }) = _$UserImpl; + + int get id; + + String get username; + + @DefaultValue('') + String get email; +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_7_from_json_camel_case.dart b/package/test/contributors/annotations/data_class/test_files/out_7_from_json_camel_case.dart deleted file mode 100644 index be400a3..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_7_from_json_camel_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class CamelCaseTest { - /// Shorthand constructor - CamelCaseTest({ - required this.thisVariableWillBeCamelCase, - required this.thisvariablewillnotbecamelcase, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBeCamelCase; - final String thisvariablewillnotbecamelcase; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Creates an instance of [CamelCaseTest] from [json] - factory CamelCaseTest.fromJson(Map json) { - return CamelCaseTest( - thisVariableWillBeCamelCase: json['thisVariableWillBeCamelCase'] as String, - thisvariablewillnotbecamelcase: json['thisvariablewillnotbecamelcase'] as String, - thisIsAVariable: json['thisIsAVariable'] as String, - aNumber11Variable: json['aNumber11Variable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_7_inheritance.dart b/package/test/contributors/annotations/data_class/test_files/out_7_inheritance.dart new file mode 100644 index 0000000..17ba13c --- /dev/null +++ b/package/test/contributors/annotations/data_class/test_files/out_7_inheritance.dart @@ -0,0 +1,33 @@ +part 'in_7_inheritance.gen.dart'; + +@DataClass() +abstract class User { + User.ctor(); + + /// Default constructor + factory User({ + required int id, + required String username, + }) = _$UserImpl; + + int get id; + + String get username; +} + +@DataClass() +abstract class SuperUser extends User { + SuperUser.ctor() : super.ctor(); + + /// Default constructor + factory SuperUser({ + required int id, + required String username, + }) = _$SuperUserImpl; + + @override + int get id; + + @override + String get username; +} diff --git a/package/test/contributors/annotations/data_class/test_files/out_7_to_json_camel_case.dart b/package/test/contributors/annotations/data_class/test_files/out_7_to_json_camel_case.dart deleted file mode 100644 index fd04e6b..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_7_to_json_camel_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class CamelCaseTest { - /// Shorthand constructor - CamelCaseTest({ - required this.thisVariableWillBeCamelCase, - required this.thisvariablewillnotbecamelcase, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBeCamelCase; - final String thisvariablewillnotbecamelcase; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Converts [CamelCaseTest] to a [Map] json - Map toJson() { - return { - 'thisVariableWillBeCamelCase': thisVariableWillBeCamelCase, - 'thisvariablewillnotbecamelcase': thisvariablewillnotbecamelcase, - 'thisIsAVariable': thisIsAVariable, - 'aNumber11Variable': aNumber11Variable, - }; - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_8_from_json_kebab_case.dart b/package/test/contributors/annotations/data_class/test_files/out_8_from_json_kebab_case.dart deleted file mode 100644 index 85eac8f..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_8_from_json_kebab_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class KebabCaseTest { - /// Shorthand constructor - KebabCaseTest({ - required this.thisVariableWillBeKebabCase, - required this.thisvariablewillnotbekebabcase, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBeKebabCase; - final String thisvariablewillnotbekebabcase; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Creates an instance of [KebabCaseTest] from [json] - factory KebabCaseTest.fromJson(Map json) { - return KebabCaseTest( - thisVariableWillBeKebabCase: json['this-variable-will-be-kebab-case'] as String, - thisvariablewillnotbekebabcase: json['thisvariablewillnotbekebabcase'] as String, - thisIsAVariable: json['this-is-a-variable'] as String, - aNumber11Variable: json['a-number-11-variable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_8_to_json_kebab_case.dart b/package/test/contributors/annotations/data_class/test_files/out_8_to_json_kebab_case.dart deleted file mode 100644 index 0f5c873..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_8_to_json_kebab_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class KebabCaseTest { - /// Shorthand constructor - KebabCaseTest({ - required this.thisVariableWillBeKebabCase, - required this.thisvariablewillnotbekebabcase, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBeKebabCase; - final String thisvariablewillnotbekebabcase; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Converts [KebabCaseTest] to a [Map] json - Map toJson() { - return { - 'this-variable-will-be-kebab-case': thisVariableWillBeKebabCase, - 'thisvariablewillnotbekebabcase': thisvariablewillnotbekebabcase, - 'this-is-a-variable': thisIsAVariable, - 'a-number-11-variable': aNumber11Variable, - }; - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_9_from_json_pascal_case.dart b/package/test/contributors/annotations/data_class/test_files/out_9_from_json_pascal_case.dart deleted file mode 100644 index a9ff824..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_9_from_json_pascal_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - fromJson: true, - toJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class PascalCaseTest { - /// Shorthand constructor - PascalCaseTest({ - required this.thisVariableWillBePascalCase, - required this.onewordvariable, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBePascalCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Creates an instance of [PascalCaseTest] from [json] - factory PascalCaseTest.fromJson(Map json) { - return PascalCaseTest( - thisVariableWillBePascalCase: json['ThisVariableWillBePascalCase'] as String, - onewordvariable: json['Onewordvariable'] as String, - thisIsAVariable: json['ThisIsAVariable'] as String, - aNumber11Variable: json['ANumber11Variable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/data_class/test_files/out_9_to_json_pascal_case.dart b/package/test/contributors/annotations/data_class/test_files/out_9_to_json_pascal_case.dart deleted file mode 100644 index 0beb9e3..0000000 --- a/package/test/contributors/annotations/data_class/test_files/out_9_to_json_pascal_case.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - $toString: false, - hashAndEquals: false, -) -class PascalCaseTest { - /// Shorthand constructor - PascalCaseTest({ - required this.thisVariableWillBePascalCase, - required this.onewordvariable, - required this.thisIsAVariable, - required this.aNumber11Variable, - }); - - final String thisVariableWillBePascalCase; - final String onewordvariable; - final String thisIsAVariable; - final String aNumber11Variable; - - /// Converts [PascalCaseTest] to a [Map] json - Map toJson() { - return { - 'ThisVariableWillBePascalCase': thisVariableWillBePascalCase, - 'Onewordvariable': onewordvariable, - 'ThisIsAVariable': thisIsAVariable, - 'ANumber11Variable': aNumber11Variable, - }; - } -} diff --git a/package/test/contributors/annotations/json_key/json_key_annotation_test.dart b/package/test/contributors/annotations/json_key/json_key_annotation_test.dart deleted file mode 100644 index 0903a5a..0000000 --- a/package/test/contributors/annotations/json_key/json_key_annotation_test.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:io' as io; -import 'dart:io'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:data_class_plugin/src/contributors/class/class_contributors.dart'; -import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; - -import 'package:data_class_plugin/src/visitors/visitors.dart'; -import 'package:path/path.dart' as path; -import 'package:test/test.dart'; - -import '../../utils/utils.dart'; - -final String _path = path.join( - io.Directory.current.path, - 'test', - 'contributors', - 'annotations', - 'json_key', -); - -void main() async { - final List testFiles = getTestFiles(_path); - final DataClassPluginOptions pluginOptions = await DataClassPluginOptions.fromFile( - File(path.join('test', 'data_class_plugin_options.yaml'))); - - group('JsonKey Annotation', () { - testFiles.runContributorTests( - contributor: (String path) => DataClassAssistContributor(path, pluginOptions: pluginOptions), - offsetProvider: (CompilationUnit unit) { - // we need the offset to be between a class declaration - // so we find the first class node, because of the import statement - final ClassAstVisitor classVisitor = - ClassAstVisitor(matcher: (ClassDeclaration node) => true); - unit.visitChildren(classVisitor); - return classVisitor.classNode?.offset ?? -1; - }, - ); - }); -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_from_json.dart b/package/test/contributors/annotations/json_key/test_files/in_from_json.dart deleted file mode 100644 index ffba40a..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_from_json.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: false, - fromJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - }); - - final String id; - - @JsonKey(fromJson: _usernameConverter) - final String username; - - static String _usernameConverter(dynamic value, Map json, String keyName) { - return json['username'] ?? json['uname']; - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_ignore.dart b/package/test/contributors/annotations/json_key/test_files/in_ignore.dart deleted file mode 100644 index 82ae401..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_ignore.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - User({ - required this.id, - this.ignoredField, - }); - - final String id; - - @JsonKey(ignore: true) - final String? ignoredField; -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_name.dart b/package/test/contributors/annotations/json_key/test_files/in_name.dart deleted file mode 100644 index 9604cc9..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_name.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - User({ - required this.id, - }); - - @JsonKey(name: '_id') - final String id; -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_name_convention_camel.dart b/package/test/contributors/annotations/json_key/test_files/in_name_convention_camel.dart deleted file mode 100644 index fe1dee4..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_name_convention_camel.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.camelCase) - final String thisIsATestVariable; -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_name_convention_kebab.dart b/package/test/contributors/annotations/json_key/test_files/in_name_convention_kebab.dart deleted file mode 100644 index 259b642..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_name_convention_kebab.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.kebabCase) - final String thisIsATestVariable; -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_name_convention_pascal.dart b/package/test/contributors/annotations/json_key/test_files/in_name_convention_pascal.dart deleted file mode 100644 index 7b4cf2c..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_name_convention_pascal.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.pascalCase) - final String thisIsATestVariable; -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_name_convention_snake.dart b/package/test/contributors/annotations/json_key/test_files/in_name_convention_snake.dart deleted file mode 100644 index de8d999..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_name_convention_snake.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.snakeCase) - final String thisIsATestVariable; -} diff --git a/package/test/contributors/annotations/json_key/test_files/in_to_json.dart b/package/test/contributors/annotations/json_key/test_files/in_to_json.dart deleted file mode 100644 index 8788302..0000000 --- a/package/test/contributors/annotations/json_key/test_files/in_to_json.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - }); - - @JsonKey(toJson: _toIdMapper) - final String id; - final String username; - - static String _toIdMapper(dynamic id) { - return '__${id}__'; - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_from_json.dart b/package/test/contributors/annotations/json_key/test_files/out_from_json.dart deleted file mode 100644 index 2952899..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_from_json.dart +++ /dev/null @@ -1,31 +0,0 @@ -@DataClass( - toJson: false, - fromJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - }); - - final String id; - - @JsonKey(fromJson: _usernameConverter) - final String username; - - static String _usernameConverter(dynamic value, Map json, String keyName) { - return json['username'] ?? json['uname']; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - id: json['id'] as String, - username: User._usernameConverter(json['username'], json, 'username'), - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_ignore.dart b/package/test/contributors/annotations/json_key/test_files/out_ignore.dart deleted file mode 100644 index 49c3492..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_ignore.dart +++ /dev/null @@ -1,33 +0,0 @@ -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - this.ignoredField, - }); - - final String id; - - @JsonKey(ignore: true) - final String? ignoredField; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'id': id, - }; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - id: json['id'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_name.dart b/package/test/contributors/annotations/json_key/test_files/out_name.dart deleted file mode 100644 index 3bfec51..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_name.dart +++ /dev/null @@ -1,30 +0,0 @@ -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - }); - - @JsonKey(name: '_id') - final String id; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - '_id': id, - }; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - id: json['_id'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_name_convention_camel.dart b/package/test/contributors/annotations/json_key/test_files/out_name_convention_camel.dart deleted file mode 100644 index 9288faf..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_name_convention_camel.dart +++ /dev/null @@ -1,30 +0,0 @@ -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.camelCase) - final String thisIsATestVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'thisIsATestVariable': thisIsATestVariable, - }; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsATestVariable: json['thisIsATestVariable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_name_convention_kebab.dart b/package/test/contributors/annotations/json_key/test_files/out_name_convention_kebab.dart deleted file mode 100644 index a9d08d6..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_name_convention_kebab.dart +++ /dev/null @@ -1,30 +0,0 @@ -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.kebabCase) - final String thisIsATestVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'this-is-a-test-variable': thisIsATestVariable, - }; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsATestVariable: json['this-is-a-test-variable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_name_convention_pascal.dart b/package/test/contributors/annotations/json_key/test_files/out_name_convention_pascal.dart deleted file mode 100644 index 6a9a85e..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_name_convention_pascal.dart +++ /dev/null @@ -1,30 +0,0 @@ -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.pascalCase) - final String thisIsATestVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'ThisIsATestVariable': thisIsATestVariable, - }; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsATestVariable: json['ThisIsATestVariable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_name_convention_snake.dart b/package/test/contributors/annotations/json_key/test_files/out_name_convention_snake.dart deleted file mode 100644 index fc1675f..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_name_convention_snake.dart +++ /dev/null @@ -1,30 +0,0 @@ -@DataClass( - fromJson: true, - toJson: true, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.thisIsATestVariable, - }); - - @JsonKey(nameConvention: JsonKeyNameConvention.snakeCase) - final String thisIsATestVariable; - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'this_is_a_test_variable': thisIsATestVariable, - }; - } - - /// Creates an instance of [User] from [json] - factory User.fromJson(Map json) { - return User( - thisIsATestVariable: json['this_is_a_test_variable'] as String, - ); - } -} diff --git a/package/test/contributors/annotations/json_key/test_files/out_to_json.dart b/package/test/contributors/annotations/json_key/test_files/out_to_json.dart deleted file mode 100644 index 9f58196..0000000 --- a/package/test/contributors/annotations/json_key/test_files/out_to_json.dart +++ /dev/null @@ -1,30 +0,0 @@ -@DataClass( - toJson: true, - fromJson: false, - copyWith: false, - hashAndEquals: false, - $toString: false, -) -class User { - /// Shorthand constructor - User({ - required this.id, - required this.username, - }); - - @JsonKey(toJson: _toIdMapper) - final String id; - final String username; - - static String _toIdMapper(dynamic id) { - return '__${id}__'; - } - - /// Converts [User] to a [Map] json - Map toJson() { - return { - 'id': User._toIdMapper(id), - 'username': username, - }; - } -} diff --git a/package/test/contributors/annotations/union/test_files/in_1_simple.dart b/package/test/contributors/annotations/union/test_files/in_1_simple.dart new file mode 100644 index 0000000..2501a4e --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/in_1_simple.dart @@ -0,0 +1,7 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@Union() +class AsyncResult { + factory AsyncResult.data() = AsyncResultData; + factory AsyncResult.error() = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/in_2_positional_parameter.dart b/package/test/contributors/annotations/union/test_files/in_2_positional_parameter.dart new file mode 100644 index 0000000..7b65ac0 --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/in_2_positional_parameter.dart @@ -0,0 +1,7 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@Union() +class AsyncResult { + factory AsyncResult.data(int data) = AsyncResultData; + factory AsyncResult.error(Object error) = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/in_3_named_parameter.dart b/package/test/contributors/annotations/union/test_files/in_3_named_parameter.dart new file mode 100644 index 0000000..530a421 --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/in_3_named_parameter.dart @@ -0,0 +1,7 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@Union() +class AsyncResult { + factory AsyncResult.data({required int data}) = AsyncResultData; + factory AsyncResult.error({required Object error}) = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/in_4_from_json.dart b/package/test/contributors/annotations/union/test_files/in_4_from_json.dart new file mode 100644 index 0000000..6b03b3f --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/in_4_from_json.dart @@ -0,0 +1,9 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@Union( + fromJson: true, +) +class AsyncResult { + factory AsyncResult.data() = AsyncResultData; + factory AsyncResult.error() = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/in_5_to_json.dart b/package/test/contributors/annotations/union/test_files/in_5_to_json.dart new file mode 100644 index 0000000..62c1026 --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/in_5_to_json.dart @@ -0,0 +1,9 @@ +import 'package:data_class_plugin/data_class_plugin.dart'; + +@Union( + toJson: true, +) +class AsyncResult { + factory AsyncResult.data() = AsyncResultData; + factory AsyncResult.error() = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/in_data_class.dart b/package/test/contributors/annotations/union/test_files/in_data_class.dart deleted file mode 100644 index bf1b7c3..0000000 --- a/package/test/contributors/annotations/union/test_files/in_data_class.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - fromJson: false, - toJson: false, -) -class AsyncResult { - const factory AsyncResult.data({ - required T data, - }) = AsyncResultData; - - const factory AsyncResult.loading() = AsyncResultLoading; - - const factory AsyncResult.error({ - required Object error, - StackTrace? stackTrace, - }) = AsyncResultError; -} diff --git a/package/test/contributors/annotations/union/test_files/in_from_json.dart b/package/test/contributors/annotations/union/test_files/in_from_json.dart deleted file mode 100644 index f13a098..0000000 --- a/package/test/contributors/annotations/union/test_files/in_from_json.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - hashAndEquals: false, - $toString: false, - fromJson: true, - toJson: false, -) -class Response { - const factory Response.ok({ - required int data, - }) = ResponseOk; - - const factory Response.unauthorized() = ResponseUnauthorized; - - const factory Response.error({ - required Object type, - @JsonKey(ignore: true) StackTrace? stackTrace, - }) = ResponseError; -} diff --git a/package/test/contributors/annotations/union/test_files/in_from_options.dart b/package/test/contributors/annotations/union/test_files/in_from_options.dart deleted file mode 100644 index 4090244..0000000 --- a/package/test/contributors/annotations/union/test_files/in_from_options.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union() -class UnionWithDefaultValues { - const factory UnionWithDefaultValues.impl({ - @DefaultValue('') String value2, - @DefaultValue(0) int value4, - @DefaultValue(true) bool value5, - }) = Impl; -} diff --git a/package/test/contributors/annotations/union/test_files/in_shared_fields.dart b/package/test/contributors/annotations/union/test_files/in_shared_fields.dart deleted file mode 100644 index 645da21..0000000 --- a/package/test/contributors/annotations/union/test_files/in_shared_fields.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - copyWith: true, - hashAndEquals: true, - $toString: true, - fromJson: false, - toJson: false, -) -abstract class User { - const factory User.normal({ - required String id, - required String username, - String? email, - }) = UserNormal; - - const factory User.admin({ - required String id, - required String username, - String? email, - }) = UserAdmin; - - String get id; - String get username; - String? get email; -} diff --git a/package/test/contributors/annotations/union/test_files/in_to_json.dart b/package/test/contributors/annotations/union/test_files/in_to_json.dart deleted file mode 100644 index 22806b8..0000000 --- a/package/test/contributors/annotations/union/test_files/in_to_json.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -@Union( - copyWith: false, - hashAndEquals: false, - $toString: false, - fromJson: false, - toJson: true, -) -class AsyncResult { - const factory AsyncResult.data({ - required T data, - }) = AsyncResultData; - - const factory AsyncResult.loading() = AsyncResultLoading; - - const factory AsyncResult.error({ - required Object error, - StackTrace? stackTrace, - }) = AsyncResultError; -} diff --git a/package/test/contributors/annotations/union/test_files/in_union_field_value.dart b/package/test/contributors/annotations/union/test_files/in_union_field_value.dart deleted file mode 100644 index 94cb2e6..0000000 --- a/package/test/contributors/annotations/union/test_files/in_union_field_value.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:data_class_plugin/data_class_plugin.dart'; - -class User { - /// Shorthand constructor - const User({ - required this.username, - }); - - final String username; - - static const none = User(username: ''); -} - -@Union( - hashAndEquals: false, - $toString: false, - fromJson: false, - toJson: false, -) -class UnionWithDefaultValues { - const factory UnionWithDefaultValues.impl({ - @DefaultValue(User.none) User value, - @DefaultValue('') String value2, - @DefaultValue(User(username: '')) User value3, - @DefaultValue(0) int value4, - @DefaultValue(true) bool value5, - }) = Impl; -} diff --git a/package/test/contributors/annotations/union/test_files/out_1_simple.dart b/package/test/contributors/annotations/union/test_files/out_1_simple.dart new file mode 100644 index 0000000..72ae68a --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/out_1_simple.dart @@ -0,0 +1,9 @@ +part 'in_1_simple.gen.dart'; + +@Union() +sealed class AsyncResult { + const AsyncResult._(); + + factory AsyncResult.data() = AsyncResultData; + factory AsyncResult.error() = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/out_2_positional_parameter.dart b/package/test/contributors/annotations/union/test_files/out_2_positional_parameter.dart new file mode 100644 index 0000000..5ba7750 --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/out_2_positional_parameter.dart @@ -0,0 +1,9 @@ +part 'in_2_positional_parameter.gen.dart'; + +@Union() +sealed class AsyncResult { + const AsyncResult._(); + + factory AsyncResult.data(int data) = AsyncResultData; + factory AsyncResult.error(Object error) = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/out_3_named_parameter.dart b/package/test/contributors/annotations/union/test_files/out_3_named_parameter.dart new file mode 100644 index 0000000..b7a51bc --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/out_3_named_parameter.dart @@ -0,0 +1,9 @@ +part 'in_3_named_parameter.gen.dart'; + +@Union() +sealed class AsyncResult { + const AsyncResult._(); + + factory AsyncResult.data({required int data}) = AsyncResultData; + factory AsyncResult.error({required Object error}) = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/out_4_from_json.dart b/package/test/contributors/annotations/union/test_files/out_4_from_json.dart new file mode 100644 index 0000000..0f46106 --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/out_4_from_json.dart @@ -0,0 +1,14 @@ +part 'in_4_from_json.gen.dart'; + +@Union( + fromJson: true, +) +sealed class AsyncResult { + const AsyncResult._(); + + /// Creates an instance of [AsyncResult] from [json] + factory AsyncResult.fromJson(Map json) => _$AsyncResultFromJson(json); + + factory AsyncResult.data() = AsyncResultData; + factory AsyncResult.error() = AsyncResultError; +} diff --git a/package/test/contributors/annotations/union/test_files/out_5_to_json.dart b/package/test/contributors/annotations/union/test_files/out_5_to_json.dart new file mode 100644 index 0000000..bc49083 --- /dev/null +++ b/package/test/contributors/annotations/union/test_files/out_5_to_json.dart @@ -0,0 +1,14 @@ +part 'in_5_to_json.gen.dart'; + +@Union( + toJson: true, +) +sealed class AsyncResult { + const AsyncResult._(); + + factory AsyncResult.data() = AsyncResultData; + factory AsyncResult.error() = AsyncResultError; + + /// Converts [AsyncResult] to [Map] json + Map toJson(); +} diff --git a/package/test/contributors/annotations/union/test_files/out_data_class.dart b/package/test/contributors/annotations/union/test_files/out_data_class.dart deleted file mode 100644 index 942d28d..0000000 --- a/package/test/contributors/annotations/union/test_files/out_data_class.dart +++ /dev/null @@ -1,166 +0,0 @@ -@Union( - fromJson: false, - toJson: false, -) -abstract class AsyncResult { - const AsyncResult._(); - - const factory AsyncResult.data({ - required T data, - }) = AsyncResultData; - - const factory AsyncResult.loading() = AsyncResultLoading; - - const factory AsyncResult.error({ - required Object error, - StackTrace? stackTrace, - }) = AsyncResultError; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(AsyncResultData value) data, - required R Function() loading, - required R Function(AsyncResultError value) error, - }) { - if (this is AsyncResultData) { - return data(this as AsyncResultData); - } - if (this is AsyncResultLoading) { - return loading(); - } - if (this is AsyncResultError) { - return error(this as AsyncResultError); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(AsyncResultData value)? data, - R Function()? loading, - R Function(AsyncResultError value)? error, - required R Function() orElse, - }) { - if (this is AsyncResultData) { - return data?.call(this as AsyncResultData) ?? orElse(); - } - if (this is AsyncResultLoading) { - return loading?.call() ?? orElse(); - } - if (this is AsyncResultError) { - return error?.call(this as AsyncResultError) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class AsyncResultData extends AsyncResult { - const AsyncResultData({ - required this.data, - }) : super._(); - - final T data; - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - data, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AsyncResultData && runtimeType == other.runtimeType && data == other.data; - } - - /// Returns a string with the properties of [AsyncResultData] - @override - String toString() { - String value = 'AsyncResultData{}'; - assert(() { - value = 'AsyncResultData<$T>@<$hexIdentity>{data: $data}'; - return true; - }()); - return value; - } -} - -class AsyncResultLoading extends AsyncResult { - const AsyncResultLoading() : super._(); - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AsyncResultLoading && runtimeType == other.runtimeType; - } - - /// Returns a string with the properties of [AsyncResultLoading] - @override - String toString() { - String value = 'AsyncResultLoading{}'; - assert(() { - value = 'AsyncResultLoading<$T>@<$hexIdentity>{}'; - return true; - }()); - return value; - } -} - -class AsyncResultError extends AsyncResult { - const AsyncResultError({ - required this.error, - this.stackTrace, - }) : super._(); - - final Object error; - final StackTrace? stackTrace; - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - error, - stackTrace, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is AsyncResultError && - runtimeType == other.runtimeType && - error == other.error && - stackTrace == other.stackTrace; - } - - /// Returns a string with the properties of [AsyncResultError] - @override - String toString() { - String value = 'AsyncResultError{}'; - assert(() { - value = 'AsyncResultError<$T>@<$hexIdentity>{error: $error, stackTrace: $stackTrace}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/annotations/union/test_files/out_from_json.dart b/package/test/contributors/annotations/union/test_files/out_from_json.dart deleted file mode 100644 index f829ccf..0000000 --- a/package/test/contributors/annotations/union/test_files/out_from_json.dart +++ /dev/null @@ -1,105 +0,0 @@ -@Union( - hashAndEquals: false, - $toString: false, - fromJson: true, - toJson: false, -) -abstract class Response { - const Response._(); - - /// Creates an instance of [Response] from [json] - factory Response.fromJson(Map json) { - throw UnimplementedError(); - } - - const factory Response.ok({ - required int data, - }) = ResponseOk; - - const factory Response.unauthorized() = ResponseUnauthorized; - - const factory Response.error({ - required Object type, - @JsonKey(ignore: true) StackTrace? stackTrace, - }) = ResponseError; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(ResponseOk value) ok, - required R Function() unauthorized, - required R Function(ResponseError value) error, - }) { - if (this is ResponseOk) { - return ok(this as ResponseOk); - } - if (this is ResponseUnauthorized) { - return unauthorized(); - } - if (this is ResponseError) { - return error(this as ResponseError); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(ResponseOk value)? ok, - R Function()? unauthorized, - R Function(ResponseError value)? error, - required R Function() orElse, - }) { - if (this is ResponseOk) { - return ok?.call(this as ResponseOk) ?? orElse(); - } - if (this is ResponseUnauthorized) { - return unauthorized?.call() ?? orElse(); - } - if (this is ResponseError) { - return error?.call(this as ResponseError) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class ResponseOk extends Response { - const ResponseOk({ - required this.data, - }) : super._(); - - final int data; - - /// Creates an instance of [ResponseOk] from [json] - factory ResponseOk.fromJson(Map json) { - return ResponseOk( - data: json['data'] as int, - ); - } -} - -class ResponseUnauthorized extends Response { - const ResponseUnauthorized() : super._(); - - /// Creates an instance of [ResponseUnauthorized] from [json] - factory ResponseUnauthorized.fromJson(Map json) { - return const ResponseUnauthorized(); - } -} - -class ResponseError extends Response { - const ResponseError({ - required this.type, - this.stackTrace, - }) : super._(); - - final Object type; - final StackTrace? stackTrace; - - /// Creates an instance of [ResponseError] from [json] - factory ResponseError.fromJson(Map json) { - return ResponseError( - type: jsonConverterRegistrant.find(Object).fromJson(json['type'], json, 'type') as Object, - ); - } -} diff --git a/package/test/contributors/annotations/union/test_files/out_from_options.dart b/package/test/contributors/annotations/union/test_files/out_from_options.dart deleted file mode 100644 index c92233c..0000000 --- a/package/test/contributors/annotations/union/test_files/out_from_options.dart +++ /dev/null @@ -1,92 +0,0 @@ -@Union() -abstract class UnionWithDefaultValues { - const UnionWithDefaultValues._(); - - const factory UnionWithDefaultValues.impl({ - @DefaultValue('') String value2, - @DefaultValue(0) int value4, - @DefaultValue(true) bool value5, - }) = Impl; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(Impl value) impl, - }) { - if (this is Impl) { - return impl(this as Impl); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(Impl value)? impl, - required R Function() orElse, - }) { - if (this is Impl) { - return impl?.call(this as Impl) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class Impl extends UnionWithDefaultValues { - const Impl({ - this.value2 = '', - this.value4 = 0, - this.value5 = true, - }) : super._(); - - final String value2; - final int value4; - final bool value5; - - /// Creates a new instance of [Impl] with optional new values - Impl copyWith({ - final String? value2, - final int? value4, - final bool? value5, - }) { - return Impl( - value2: value2 ?? this.value2, - value4: value4 ?? this.value4, - value5: value5 ?? this.value5, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - value2, - value4, - value5, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is Impl && - runtimeType == other.runtimeType && - value2 == other.value2 && - value4 == other.value4 && - value5 == other.value5; - } - - /// Returns a string with the properties of [Impl] - @override - String toString() { - String value = 'Impl{}'; - assert(() { - value = 'Impl@<$hexIdentity>{value2: $value2, value4: $value4, value5: $value5}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/annotations/union/test_files/out_shared_fields.dart b/package/test/contributors/annotations/union/test_files/out_shared_fields.dart deleted file mode 100644 index 94f2dbe..0000000 --- a/package/test/contributors/annotations/union/test_files/out_shared_fields.dart +++ /dev/null @@ -1,181 +0,0 @@ -@Union( - copyWith: true, - hashAndEquals: true, - $toString: true, - fromJson: false, - toJson: false, -) -abstract class User { - const User._(); - - const factory User.normal({ - required String id, - required String username, - String? email, - }) = UserNormal; - - const factory User.admin({ - required String id, - required String username, - String? email, - }) = UserAdmin; - - String get id; - String get username; - String? get email; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(UserNormal value) normal, - required R Function(UserAdmin value) admin, - }) { - if (this is UserNormal) { - return normal(this as UserNormal); - } - if (this is UserAdmin) { - return admin(this as UserAdmin); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(UserNormal value)? normal, - R Function(UserAdmin value)? admin, - required R Function() orElse, - }) { - if (this is UserNormal) { - return normal?.call(this as UserNormal) ?? orElse(); - } - if (this is UserAdmin) { - return admin?.call(this as UserAdmin) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class UserNormal extends User { - const UserNormal({ - required this.id, - required this.username, - this.email, - }) : super._(); - - @override - final String id; - @override - final String username; - @override - final String? email; - - /// Creates a new instance of [UserNormal] with optional new values - UserNormal copyWith({ - final String? id, - final String? username, - final String? email, - }) { - return UserNormal( - id: id ?? this.id, - username: username ?? this.username, - email: email ?? this.email, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - id, - username, - email, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is UserNormal && - runtimeType == other.runtimeType && - id == other.id && - username == other.username && - email == other.email; - } - - /// Returns a string with the properties of [UserNormal] - @override - String toString() { - String value = 'UserNormal{}'; - assert(() { - value = 'UserNormal@<$hexIdentity>{id: $id, username: $username, email: $email}'; - return true; - }()); - return value; - } -} - -class UserAdmin extends User { - const UserAdmin({ - required this.id, - required this.username, - this.email, - }) : super._(); - - @override - final String id; - @override - final String username; - @override - final String? email; - - /// Creates a new instance of [UserAdmin] with optional new values - UserAdmin copyWith({ - final String? id, - final String? username, - final String? email, - }) { - return UserAdmin( - id: id ?? this.id, - username: username ?? this.username, - email: email ?? this.email, - ); - } - - /// Returns a hash code based on [this] properties - @override - int get hashCode { - return Object.hashAll([ - runtimeType, - id, - username, - email, - ]); - } - - /// Compares [this] with [other] on identity, class type, and properties - /// *with deep comparison on collections* - @override - bool operator ==(Object? other) { - return identical(this, other) || - other is UserAdmin && - runtimeType == other.runtimeType && - id == other.id && - username == other.username && - email == other.email; - } - - /// Returns a string with the properties of [UserAdmin] - @override - String toString() { - String value = 'UserAdmin{}'; - assert(() { - value = 'UserAdmin@<$hexIdentity>{id: $id, username: $username, email: $email}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/annotations/union/test_files/out_to_json.dart b/package/test/contributors/annotations/union/test_files/out_to_json.dart deleted file mode 100644 index d4601cc..0000000 --- a/package/test/contributors/annotations/union/test_files/out_to_json.dart +++ /dev/null @@ -1,109 +0,0 @@ -@Union( - copyWith: false, - hashAndEquals: false, - $toString: false, - fromJson: false, - toJson: true, -) -abstract class AsyncResult { - const AsyncResult._(); - - const factory AsyncResult.data({ - required T data, - }) = AsyncResultData; - - const factory AsyncResult.loading() = AsyncResultLoading; - - const factory AsyncResult.error({ - required Object error, - StackTrace? stackTrace, - }) = AsyncResultError; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(AsyncResultData value) data, - required R Function() loading, - required R Function(AsyncResultError value) error, - }) { - if (this is AsyncResultData) { - return data(this as AsyncResultData); - } - if (this is AsyncResultLoading) { - return loading(); - } - if (this is AsyncResultError) { - return error(this as AsyncResultError); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(AsyncResultData value)? data, - R Function()? loading, - R Function(AsyncResultError value)? error, - required R Function() orElse, - }) { - if (this is AsyncResultData) { - return data?.call(this as AsyncResultData) ?? orElse(); - } - if (this is AsyncResultLoading) { - return loading?.call() ?? orElse(); - } - if (this is AsyncResultError) { - return error?.call(this as AsyncResultError) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } - - /// Converts [AsyncResult] to [Map] json - Map toJson(); -} - -class AsyncResultData extends AsyncResult { - const AsyncResultData({ - required this.data, - }) : super._(); - - final T data; - - /// Converts [AsyncResultData] to a [Map] json - @override - Map toJson() { - return { - 'data': jsonConverterRegistrant.find(T).toJson(data), - }; - } -} - -class AsyncResultLoading extends AsyncResult { - const AsyncResultLoading() : super._(); - - /// Converts [AsyncResultLoading] to a [Map] json - @override - Map toJson() { - return {}; - } -} - -class AsyncResultError extends AsyncResult { - const AsyncResultError({ - required this.error, - this.stackTrace, - }) : super._(); - - final Object error; - final StackTrace? stackTrace; - - /// Converts [AsyncResultError] to a [Map] json - @override - Map toJson() { - return { - 'error': jsonConverterRegistrant.find(Object).toJson(error), - 'stackTrace': - stackTrace == null ? null : jsonConverterRegistrant.find(StackTrace).toJson(stackTrace), - }; - } -} diff --git a/package/test/contributors/annotations/union/test_files/out_union_field_value.dart b/package/test/contributors/annotations/union/test_files/out_union_field_value.dart deleted file mode 100644 index 78a6c12..0000000 --- a/package/test/contributors/annotations/union/test_files/out_union_field_value.dart +++ /dev/null @@ -1,56 +0,0 @@ -@Union( - hashAndEquals: false, - $toString: false, - fromJson: false, - toJson: false, -) -abstract class UnionWithDefaultValues { - const UnionWithDefaultValues._(); - - const factory UnionWithDefaultValues.impl({ - @DefaultValue(User.none) User value, - @DefaultValue('') String value2, - @DefaultValue(User(username: '')) User value3, - @DefaultValue(0) int value4, - @DefaultValue(true) bool value5, - }) = Impl; - - /// Executes one of the provided callbacks based on a type match - R when({ - required R Function(Impl value) impl, - }) { - if (this is Impl) { - return impl(this as Impl); - } - throw UnimplementedError('Unknown instance of $this used in when(..)'); - } - - /// Executes one of the provided callbacks if a type is matched - /// - /// If no match is found [orElse] is executed - R maybeWhen({ - R Function(Impl value)? impl, - required R Function() orElse, - }) { - if (this is Impl) { - return impl?.call(this as Impl) ?? orElse(); - } - throw UnimplementedError('Unknown instance of $this used in maybeWhen(..)'); - } -} - -class Impl extends UnionWithDefaultValues { - const Impl({ - this.value = User.none, - this.value2 = '', - this.value3 = const User(username: ''), - this.value4 = 0, - this.value5 = true, - }) : super._(); - - final User value; - final String value2; - final User value3; - final int value4; - final bool value5; -} diff --git a/package/test/contributors/annotations/union/union_annotation_test.dart b/package/test/contributors/annotations/union/union_annotation_test.dart index 7efe418..439341f 100644 --- a/package/test/contributors/annotations/union/union_annotation_test.dart +++ b/package/test/contributors/annotations/union/union_annotation_test.dart @@ -1,11 +1,9 @@ import 'dart:io' as io; -import 'dart:io'; -import 'package:analyzer/dart/ast/ast.dart'; import 'package:data_class_plugin/src/contributors/class/union_assist_contributor.dart'; import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; -import 'package:data_class_plugin/src/visitors/class_visitor.dart'; import 'package:path/path.dart' as path; +import 'package:tachyon/tachyon.dart'; import 'package:test/test.dart'; import '../../utils/utils.dart'; @@ -20,8 +18,7 @@ final String _contributorsPath = path.join( void main() async { final List testFiles = getTestFiles(_contributorsPath); - final DataClassPluginOptions pluginOptions = await DataClassPluginOptions.fromFile( - File(path.join('test', 'data_class_plugin_options.yaml'))); + final DataClassPluginOptions pluginOptions = getPluginOptions(); group('Union annotation contributor', () { testFiles.runContributorTests( diff --git a/package/test/contributors/assists/contributor_assists_test.dart b/package/test/contributors/assists/contributor_assists_test.dart index 4164cdb..0ee39d4 100644 --- a/package/test/contributors/assists/contributor_assists_test.dart +++ b/package/test/contributors/assists/contributor_assists_test.dart @@ -5,10 +5,8 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:data_class_plugin/src/analyzer_plugin/analyzer_plugin.dart'; import 'package:data_class_plugin/src/contributors/class/class_contributors.dart'; -import 'package:data_class_plugin/src/contributors/common/to_string_assist_contributor.dart'; import 'package:data_class_plugin/src/contributors/enum/enum_contributors.dart'; import 'package:data_class_plugin/src/extensions/annotation_extensions.dart'; -import 'package:data_class_plugin/src/tools/logger/plugin_logger.dart'; import 'package:data_class_plugin/src/visitors/visitors.dart'; import 'package:path/path.dart'; @@ -27,10 +25,8 @@ final String enumAnnotationPath = join(testFilesPath, 'enum_annotation.dart'); final String unionAnnotationPath = join(testFilesPath, 'union_annotation.dart'); final String dataClassAnnotationPath = join(testFilesPath, 'data_class_annotation.dart'); -class MockLogger extends PluginLogger {} - void main() async { - final DataClassPlugin plugin = DataClassPlugin(PhysicalResourceProvider.INSTANCE); + final DcpAnalyzerPlugin plugin = DcpAnalyzerPlugin(PhysicalResourceProvider.INSTANCE); final AnalysisContextCollection analysis = AnalysisContextCollection( includedPaths: [ @@ -50,7 +46,6 @@ void main() async { EnumConstructorAssistContributor, EnumToJsonAssistContributor, EnumFromJsonAssistContributor, - ToStringAssistContributor, ], filepath: enumPath, ); diff --git a/package/test/contributors/class/to_string/test_files/in_1.dart b/package/test/contributors/class/to_string/test_files/in_1.dart deleted file mode 100644 index 2f6d129..0000000 --- a/package/test/contributors/class/to_string/test_files/in_1.dart +++ /dev/null @@ -1,15 +0,0 @@ -class ToStringTest { - /// Shorthand constructor - ToStringTest({ - required this.intValue, - required this.doubleValue, - required this.stringValues, - }); - - final int intValue; - final double doubleValue; - final List stringValues; -} - -// Should create a [toString] override for [ToStringTest] -// using doubleValue and stringValues diff --git a/package/test/contributors/class/to_string/test_files/in_2.dart b/package/test/contributors/class/to_string/test_files/in_2.dart deleted file mode 100644 index 4755b53..0000000 --- a/package/test/contributors/class/to_string/test_files/in_2.dart +++ /dev/null @@ -1,13 +0,0 @@ -class ToStringTest { - /// Shorthand constructor - ToStringTest({ - required this.intValue, - }); - - final int intValue; - final String _private; - String notFinal = 'notFinal'; -} - -// Should create a [toString] override for [ToStringTest] intValue -// and ignoring _private and notFinal diff --git a/package/test/contributors/class/to_string/test_files/out_1.dart b/package/test/contributors/class/to_string/test_files/out_1.dart deleted file mode 100644 index ea5c75c..0000000 --- a/package/test/contributors/class/to_string/test_files/out_1.dart +++ /dev/null @@ -1,24 +0,0 @@ -class ToStringTest { - /// Shorthand constructor - ToStringTest({ - required this.intValue, - required this.doubleValue, - required this.stringValues, - }); - - final int intValue; - final double doubleValue; - final List stringValues; - - /// Returns a string with the properties of [ToStringTest] - @override - String toString() { - String value = 'ToStringTest{}'; - assert(() { - value = - 'ToStringTest@<$hexIdentity>{intValue: $intValue, doubleValue: $doubleValue, stringValues: $stringValues}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/class/to_string/test_files/out_2.dart b/package/test/contributors/class/to_string/test_files/out_2.dart deleted file mode 100644 index 07faa2b..0000000 --- a/package/test/contributors/class/to_string/test_files/out_2.dart +++ /dev/null @@ -1,21 +0,0 @@ -class ToStringTest { - /// Shorthand constructor - ToStringTest({ - required this.intValue, - }); - - final int intValue; - final String _private; - String notFinal = 'notFinal'; - - /// Returns a string with the properties of [ToStringTest] - @override - String toString() { - String value = 'ToStringTest{}'; - assert(() { - value = 'ToStringTest@<$hexIdentity>{intValue: $intValue}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/class/to_string/to_string_assist_contributor_test.dart b/package/test/contributors/class/to_string/to_string_assist_contributor_test.dart deleted file mode 100644 index 5304b32..0000000 --- a/package/test/contributors/class/to_string/to_string_assist_contributor_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:io' as io; - -import 'package:data_class_plugin/src/contributors/common/to_string_assist_contributor.dart'; -import 'package:path/path.dart' as path; -import 'package:test/test.dart'; - -import '../../utils/utils.dart'; - -final String _contributorsPath = path.join( - io.Directory.current.path, - 'test', - 'contributors', - 'class', - 'to_string', -); - -void main() { - final List testFiles = getTestFiles(_contributorsPath); - - group('toString contributor', () { - testFiles.runContributorTests( - contributor: (String path) => ToStringAssistContributor(path), - ); - }); -} diff --git a/package/test/contributors/enum/to_string/test_files/in_1.dart b/package/test/contributors/enum/to_string/test_files/in_1.dart deleted file mode 100644 index b2724d4..0000000 --- a/package/test/contributors/enum/to_string/test_files/in_1.dart +++ /dev/null @@ -1,12 +0,0 @@ -enum Colors { - red(), - green(), - blue(); - - /// Default constructor of [Colors] - const Colors(this.hex); - - final String hex; -} - -// Should create a [toString] override for [Colors] using the [hex] field diff --git a/package/test/contributors/enum/to_string/test_files/in_2.dart b/package/test/contributors/enum/to_string/test_files/in_2.dart deleted file mode 100644 index c2da91b..0000000 --- a/package/test/contributors/enum/to_string/test_files/in_2.dart +++ /dev/null @@ -1,15 +0,0 @@ -enum Colors { - red(), - green(), - blue(); - - /// Default constructor of [Colors] - const Colors(this.hex); - - final String hex; - final String _private; - String notFinal = 'notFinal'; -} - -// Should create a [toString] override for [Colors] using the [hex] field -// and ignoring _private and notFinal diff --git a/package/test/contributors/enum/to_string/test_files/in_3.dart b/package/test/contributors/enum/to_string/test_files/in_3.dart deleted file mode 100644 index 4646b9e..0000000 --- a/package/test/contributors/enum/to_string/test_files/in_3.dart +++ /dev/null @@ -1,7 +0,0 @@ -enum Colors { - red, - green, - blue; -} - -// Should create a [toString] override for [Colors] diff --git a/package/test/contributors/enum/to_string/test_files/out_1.dart b/package/test/contributors/enum/to_string/test_files/out_1.dart deleted file mode 100644 index e458ce1..0000000 --- a/package/test/contributors/enum/to_string/test_files/out_1.dart +++ /dev/null @@ -1,21 +0,0 @@ -enum Colors { - red(), - green(), - blue(); - - /// Default constructor of [Colors] - const Colors(this.hex); - - final String hex; - - /// Returns a string with the properties of [Colors] - @override - String toString() { - String value = 'Colors{}'; - assert(() { - value = 'Colors.$name@<$hexIdentity>{hex: $hex}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/enum/to_string/test_files/out_2.dart b/package/test/contributors/enum/to_string/test_files/out_2.dart deleted file mode 100644 index bee1278..0000000 --- a/package/test/contributors/enum/to_string/test_files/out_2.dart +++ /dev/null @@ -1,23 +0,0 @@ -enum Colors { - red(), - green(), - blue(); - - /// Default constructor of [Colors] - const Colors(this.hex); - - final String hex; - final String _private; - String notFinal = 'notFinal'; - - /// Returns a string with the properties of [Colors] - @override - String toString() { - String value = 'Colors{}'; - assert(() { - value = 'Colors.$name@<$hexIdentity>{hex: $hex}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/enum/to_string/test_files/out_3.dart b/package/test/contributors/enum/to_string/test_files/out_3.dart deleted file mode 100644 index 7343ff4..0000000 --- a/package/test/contributors/enum/to_string/test_files/out_3.dart +++ /dev/null @@ -1,16 +0,0 @@ -enum Colors { - red, - green, - blue; - - /// Returns a string with the properties of [Colors] - @override - String toString() { - String value = 'Colors{}'; - assert(() { - value = 'Colors.$name@<$hexIdentity>{}'; - return true; - }()); - return value; - } -} diff --git a/package/test/contributors/enum/to_string/to_string_contributor_test.dart b/package/test/contributors/enum/to_string/to_string_contributor_test.dart deleted file mode 100644 index 7bb9cec..0000000 --- a/package/test/contributors/enum/to_string/to_string_contributor_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:io' as io; - -import 'package:data_class_plugin/src/contributors/common/to_string_assist_contributor.dart'; -import 'package:path/path.dart' as path; -import 'package:test/test.dart'; - -import '../../utils/utils.dart'; - -final String _contributorsPath = path.join( - io.Directory.current.path, - 'test', - 'contributors', - 'enum', - 'to_string', -); - -void main() { - final List testFiles = getTestFiles(_contributorsPath); - - group('enum toString contributor', () { - testFiles.runContributorTests( - contributor: (String path) => ToStringAssistContributor(path), - ); - }); -} diff --git a/package/test/contributors/utils/utils.dart b/package/test/contributors/utils/utils.dart index 1d1aae7..265bd5f 100644 --- a/package/test/contributors/utils/utils.dart +++ b/package/test/contributors/utils/utils.dart @@ -11,9 +11,9 @@ import 'package:analyzer_plugin/protocol/protocol_generated.dart'; import 'package:analyzer_plugin/utilities/assist/assist.dart'; import 'package:data_class_plugin/src/analyzer_plugin/analyzer_plugin.dart'; import 'package:data_class_plugin/src/contributors/class/class_contributors.dart'; -import 'package:data_class_plugin/src/contributors/common/to_string_assist_contributor.dart'; import 'package:data_class_plugin/src/contributors/enum/enum_contributors.dart'; import 'package:data_class_plugin/src/extensions/string_extensions.dart'; +import 'package:data_class_plugin/src/options/data_class_plugin_options.dart'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -54,9 +54,14 @@ class AssistCollectorTest extends AssistCollector { bool get hasMultipleReplacements => assists[0].change.edits[0].edits.length > 1; } +DataClassPluginOptions getPluginOptions() { + return DataClassPluginOptions.fromFile(io.File( + path.join('test', 'data_class_plugin_options.yaml'), + )); +} + const List availableContributors = [ ShorthandConstructorAssistContributor, - ToStringAssistContributor, DataClassAssistContributor, EnumAnnotationAssistContributor, EnumConstructorAssistContributor, @@ -66,7 +71,7 @@ const List availableContributors = [ Future testContributorAssists({ required final String assistGroupName, - required final DataClassPlugin plugin, + required final DcpAnalyzerPlugin plugin, required final AnalysisContextCollection analysis, required final String filepath, required final List shouldHaveContributors, @@ -93,9 +98,9 @@ Future testContributorAssists({ .unit; }); - test('should have 7/${availableContributors.length} contributors', () { + test('should have 6/${availableContributors.length} contributors', () { expect(contributors, isNotEmpty); - expect(contributors.length, 7); + expect(contributors.length, 6); expect(contributors.length == availableContributors.length, true); }); diff --git a/package/test/options/data_class_options_test.dart b/package/test/options/data_class_options_test.dart index e9ea46d..6f2344e 100644 --- a/package/test/options/data_class_options_test.dart +++ b/package/test/options/data_class_options_test.dart @@ -35,7 +35,7 @@ data_class: default: true '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); expect(options.dataClass.optionsConfig['copy_with']?.defaultValue, equals(false)); expect(options.dataClass.optionsConfig['hash_and_equals']?.defaultValue, equals(false)); @@ -78,7 +78,7 @@ data_class: - $disabledPath '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); for (final String option in [ 'copy_with', diff --git a/package/test/options/data_class_plugin_options_test.dart b/package/test/options/data_class_plugin_options_test.dart index acae65c..7494263 100644 --- a/package/test/options/data_class_plugin_options_test.dart +++ b/package/test/options/data_class_plugin_options_test.dart @@ -6,20 +6,6 @@ import 'package:test/test.dart'; void main() { group('DataClassPluginOptions', () { - test('returns default DataClassPluginOptions() if file not found', () async { - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(File('')); - - expect(options, isNotNull); - expect(options.dataClass, isNotNull); - expect(options.dataClass.optionsConfig, isEmpty); - expect(options.union, isNotNull); - expect(options.union.optionsConfig, isEmpty); - expect(options.json, isNotNull); - expect(options.json.nameConventionGlobs, isEmpty); - expect(options.$enum, isNotNull); - expect(options.$enum.optionsConfig, isEmpty); - }); - test('returns DataClassPluginOptions from file', () async { final File optionsFile = File(join( Directory.current.path, @@ -28,7 +14,7 @@ void main() { 'mock_data_class_plugin_options.yaml', )); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(optionsFile); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(optionsFile); expect(options, isNotNull); expect(options.dataClass, isNotNull); diff --git a/package/test/options/enum_options_test.dart b/package/test/options/enum_options_test.dart index 890525e..3fc0b7a 100644 --- a/package/test/options/enum_options_test.dart +++ b/package/test/options/enum_options_test.dart @@ -29,7 +29,7 @@ enum: default: true '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); expect(options.$enum.optionsConfig['to_string']?.defaultValue, equals(true)); expect(options.$enum.optionsConfig['from_json']?.defaultValue, equals(true)); @@ -60,7 +60,7 @@ enum: - $disabledPath '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); for (final String option in [ 'to_string', diff --git a/package/test/options/json_options_test.dart b/package/test/options/json_options_test.dart index 624755f..213f9a7 100644 --- a/package/test/options/json_options_test.dart +++ b/package/test/options/json_options_test.dart @@ -20,7 +20,7 @@ json: key_name_convention: snake_case '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); expect(options.json.keyNameConvention, equals('snake_case')); }); @@ -37,7 +37,7 @@ json: - /b/c/** '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); expect(options.json.nameConventionGlobs['camel_case'], isNull); expect(options.json.nameConventionGlobs['snake_case'], hasLength(1)); expect(options.json.nameConventionGlobs['pascal_case'], hasLength(1)); diff --git a/package/test/options/union_options_test.dart b/package/test/options/union_options_test.dart index 999acdc..77d0e9c 100644 --- a/package/test/options/union_options_test.dart +++ b/package/test/options/union_options_test.dart @@ -31,7 +31,7 @@ union: default: true '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); expect(options.union.optionsConfig['data_class']?.defaultValue, equals(false)); expect(options.union.optionsConfig['from_json']?.defaultValue, equals(true)); @@ -62,7 +62,7 @@ union: - $disabledPath '''); - final DataClassPluginOptions options = await DataClassPluginOptions.fromFile(file); + final DataClassPluginOptions options = DataClassPluginOptions.fromFile(file); for (final String option in [ 'data_class', diff --git a/package/tools/analyzer_plugin/bin/plugin.dart b/package/tools/analyzer_plugin/bin/plugin.dart index 52717ae..1993677 100644 --- a/package/tools/analyzer_plugin/bin/plugin.dart +++ b/package/tools/analyzer_plugin/bin/plugin.dart @@ -1,6 +1,6 @@ import 'dart:isolate'; -import 'package:data_class_plugin/plugin.dart'; +import 'package:data_class_plugin/analyzer_plugin.dart'; void main(List args, SendPort sendPort) { start(args, sendPort); diff --git a/package/tools/analyzer_plugin/pubspec.lock b/package/tools/analyzer_plugin/pubspec.lock deleted file mode 100644 index 2e4e6f2..0000000 --- a/package/tools/analyzer_plugin/pubspec.lock +++ /dev/null @@ -1,196 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" - url: "https://pub.dev" - source: hosted - version: "50.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" - url: "https://pub.dev" - source: hosted - version: "5.2.0" - analyzer_plugin: - dependency: transitive - description: - name: analyzer_plugin - sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d - url: "https://pub.dev" - source: hosted - version: "0.11.2" - args: - dependency: transitive - description: - name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 - url: "https://pub.dev" - source: hosted - version: "2.3.1" - async: - dependency: transitive - description: - name: async - sha256: "271b8899fc99f9df4f4ed419fa14e2fff392c7b2c162fbb87b222e2e963ddc73" - url: "https://pub.dev" - source: hosted - version: "2.9.0" - collection: - dependency: transitive - description: - name: collection - sha256: ef7e3a5529178ce8f37a9d0b11cbbc8b1e025940f9cf9f76c42da6796301219d - url: "https://pub.dev" - source: hosted - version: "1.16.0" - convert: - dependency: transitive - description: - name: convert - sha256: "196284f26f69444b7f5c50692b55ec25da86d9e500451dc09333bf2e3ad69259" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - crypto: - dependency: transitive - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" - source: hosted - version: "3.0.2" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" - url: "https://pub.dev" - source: hosted - version: "2.2.4" - data_class_plugin: - dependency: "direct main" - description: - name: data_class_plugin - url: "https://pub.dev" - source: hosted - version: "0.3.1" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" - glob: - dependency: transitive - description: - name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - meta: - dependency: transitive - description: - name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" - url: "https://pub.dev" - source: hosted - version: "1.8.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b - url: "https://pub.dev" - source: hosted - version: "1.8.2" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "816c1a640e952d213ddd223b3e7aafae08cd9f8e1f6864eed304cc13b0272b07" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" - source: hosted - version: "0.27.7" - source_span: - dependency: transitive - description: - name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" - source: hosted - version: "1.9.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - watcher: - dependency: transitive - description: - name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - yaml: - dependency: transitive - description: - name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" - url: "https://pub.dev" - source: hosted - version: "3.1.1" -sdks: - dart: ">=2.18.0 <3.0.0" diff --git a/package/tools/analyzer_plugin/pubspec.yaml b/package/tools/analyzer_plugin/pubspec.yaml index 478d6c1..3b37bca 100644 --- a/package/tools/analyzer_plugin/pubspec.yaml +++ b/package/tools/analyzer_plugin/pubspec.yaml @@ -6,7 +6,7 @@ homepage: https://github.com/spideythewebhead/dart_data_class_plugin repository: https://github.com/spideythewebhead/dart_data_class_plugin environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: - data_class_plugin: 0.3.1 + data_class_plugin: 1.0.0-tachyon.dev.5