From 85f1009daa8452e4f5da8c5775d1f3749a69420d Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 18 Dec 2023 11:14:07 +0100 Subject: [PATCH] feat!: connect everything together (#25) * started implementation * wip dependency injection * fixes * more fixes * tested config provider * tested settings provider * so many changes * new commas * added a test * more tests * removed untracked file * more coverage * wip test * mock notifier override * roadblock with variables * feat: styles importer (#26) * added all kinds of styles * small fixes * remove token * removed test file * so many changessss * smaller changes * many fixes * added integration test * delete path * it generates something!!! * simplified util * feat: better token fetching (#27) * added constructors everywhere * fixing around * fixed tests * more coverage * linter love * allow coverage decrease for now * FULL COVERAGE * optimized tests in figmage package generator * removed post gen hook from package generator * post gen commands * added tests for post gen * removed top level folder from generated package * fixes * dir fix * sort alphabetically * better logging * better exception message * linter love * implemented review changes --- .github/workflows/main.yaml | 1 + .gitignore | 6 + analysis_options.yaml | 6 +- bin/figmage.dart | 4 +- coverage/lcov.info | 1716 ++++++----- dart_test.yaml | 3 - figmage.yaml | 2 - .../generation_notifier_integration_test.dart | 55 + lib/src/command_runner.dart | 59 +- lib/src/commands/forge/forge_command.dart | 142 +- lib/src/commands/reforge/reforge_command.dart | 10 +- lib/src/commands/shared/arg_names.dart | 1 + .../shared/forge_settings_providers.dart | 45 + .../commands/shared/generation_notifier.dart | 73 + lib/src/commands/update/update_command.dart | 16 +- lib/src/data/generators/generator_util.dart | 56 +- .../data/generators/padding_generator.dart | 6 +- lib/src/data/generators/spacer_generator.dart | 6 +- .../text_style_theme_extension_generator.dart | 95 +- .../value_names_theme_class_generator.dart | 10 + ...ues_by_mode_theme_extension_generator.dart | 93 +- .../dart_code_file_writer_repository.dart | 30 + .../dart_post_generation_repository.dart | 75 + .../repositories/figma_styles_repository.dart | 70 +- .../figma_variables_repository.dart | 187 +- .../repositories/yaml_config_repository.dart | 15 +- .../util/converters/color_conversion_x.dart | 16 + .../converters/string_dart_conversion_x.dart | 45 + .../converters/type_style_conversion_x.dart | 39 + lib/src/domain/models/config/config.dart | 37 +- lib/src/domain/models/config/config.g.dart | 13 +- lib/src/domain/models/design_token.dart | 13 + lib/src/domain/models/figmage_settings.dart | 9 + lib/src/domain/models/style.dart | 3 - lib/src/domain/models/style/design_style.dart | 65 + .../domain/models/text_style/text_style.dart | 47 + .../models/text_style/text_style.freezed.dart | 291 ++ .../tokens_by_file_type/tokens_by_type.dart | 25 + .../tokens_by_type.freezed.dart | 239 ++ lib/src/domain/models/variable/variable.dart | 263 +- .../models/variable/variable.freezed.dart | 2621 ----------------- .../domain/providers/config_providers.dart | 15 + .../providers/design_token_providers.dart | 124 + .../figmage_package_generator_providers.dart | 63 + .../providers/file_writer_providers.dart | 22 + .../domain/providers/generator_providers.dart | 114 + .../domain/providers/logger_providers.dart | 5 + .../providers/post_generation_providers.dart | 24 + .../providers/pub_updater_providers.dart | 5 + .../repositories/config_repository.dart | 6 + .../repositories/file_writer_repository.dart | 29 + .../post_generation_repository.dart | 27 + .../repositories/styles_repository.dart | 46 +- .../repositories/variables_repository.dart | 52 +- lib/src/domain/util/token_filter_x.dart | 35 + melos.yaml | 5 +- melos_figmage.iml | 16 - melos_figmage_workspace.iml | 12 - .../figma_variables_api/coverage/lcov.info | 468 +-- .../figma_variables_api/lib/src/client.dart | 8 +- .../test/full_coverage_test.dart | 13 + .../test/src/client_test.dart | 4 +- .../coverage/lcov.info | 26 +- .../lib/figmage_package_generator.dart | 1 + .../.gitignore | 0 .../CHANGELOG.md | 0 .../README.md | 0 .../analysis_options.yaml | 0 .../generate_bools}} | 0 .../generate_colors}} | 0 .../generate_numbers}}} | 0 .../generate_paddings}}} | 0 .../generate_radii}}} | 0 .../generate_spacers}}} | 0 .../generate_strings}}} | 0 .../generate_typography}} | 0 .../lib/{{project_name.snakeCase()}}.dart | 1 + .../pubspec.yaml | 0 .../main}}/ISSUE_TEMPLATE/bug_report.md | 29 - .../main}}/ISSUE_TEMPLATE/build.md | 14 - .../main}}/ISSUE_TEMPLATE/chore.md | 14 - .../main}}/ISSUE_TEMPLATE/ci.md | 14 - .../main}}/ISSUE_TEMPLATE/config.yml | 1 - .../main}}/ISSUE_TEMPLATE/documentation.md | 14 - .../main}}/ISSUE_TEMPLATE/feature_request.md | 18 - .../main}}/ISSUE_TEMPLATE/performance.md | 14 - .../main}}/ISSUE_TEMPLATE/refactor.md | 14 - .../main}}/ISSUE_TEMPLATE/revert.md | 16 - .../main}}/ISSUE_TEMPLATE/style.md | 14 - .../main}}/ISSUE_TEMPLATE/test.md | 14 - .../main}}/PULL_REQUEST_TEMPLATE.md | 18 - .../{{#main}}.github{{/main}}/dependabot.yaml | 11 - .../main}}/workflows/main.yaml | 41 - .../lib/src/brick/brick.yaml | 5 + .../lib/src/brick/hooks/post_gen.dart | 23 - .../lib/src/brick/hooks/pubspec.yaml | 7 - .../lib/src/figmage_package_generator.dart | 42 +- .../lib/src/token_file_type.dart | 62 + .../test/full_coverage_test.dart | 6 + .../src/figmage_package_generator_test.dart | 199 +- .../test/src/token_file_type_test.dart | 118 + pubspec.yaml | 13 +- test/full_coverage_test.dart | 50 + test/src/command_runner_test.dart | 35 +- .../commands/forge/forge_command_test.dart | 106 +- .../shared/forge_settings_providers_test.dart | 83 + .../shared/generation_notifier_test.dart | 79 + .../color_theme_extension_generator_test.dart | 105 +- ...til_test.dart => generator_util_test.dart} | 45 +- ...number_theme_extension_generator_test.dart | 34 +- ..._style_theme_extension_generator_test.dart | 254 ++ .../text_style_theme_generator_test.dart | 284 -- .../dart_post_generation_repository_test.dart | 91 + .../figma_variables_repository_test.dart | 3 +- .../yaml_config_repository_test.dart | 69 +- .../src/domain/models/config/config_test.dart | 10 + .../domain/models/style/color_style_test.dart | 14 + .../domain/models/variable/variable_test.dart | 20 + .../providers/config_providers_test.dart | 66 + .../providers/generator_providers_test.dart | 110 + test/src/domain/util/token_filter_x_test.dart | 81 + test/test_util/mock/mock_styles.dart | 19 + test/test_util/mock/mock_variables.dart | 108 + test/test_util/test_provider_listener.dart | 6 + 124 files changed, 5144 insertions(+), 4878 deletions(-) delete mode 100644 dart_test.yaml delete mode 100644 figmage.yaml create mode 100644 integration_tests/generation_notifier_integration_test.dart create mode 100644 lib/src/commands/shared/arg_names.dart create mode 100644 lib/src/commands/shared/forge_settings_providers.dart create mode 100644 lib/src/commands/shared/generation_notifier.dart create mode 100644 lib/src/data/generators/value_names_theme_class_generator.dart create mode 100644 lib/src/data/repositories/dart_code_file_writer_repository.dart create mode 100644 lib/src/data/repositories/dart_post_generation_repository.dart create mode 100644 lib/src/data/util/converters/color_conversion_x.dart create mode 100644 lib/src/data/util/converters/string_dart_conversion_x.dart create mode 100644 lib/src/data/util/converters/type_style_conversion_x.dart create mode 100644 lib/src/domain/models/design_token.dart create mode 100644 lib/src/domain/models/figmage_settings.dart delete mode 100644 lib/src/domain/models/style.dart create mode 100644 lib/src/domain/models/style/design_style.dart create mode 100644 lib/src/domain/models/text_style/text_style.dart create mode 100644 lib/src/domain/models/text_style/text_style.freezed.dart create mode 100644 lib/src/domain/models/tokens_by_file_type/tokens_by_type.dart create mode 100644 lib/src/domain/models/tokens_by_file_type/tokens_by_type.freezed.dart delete mode 100644 lib/src/domain/models/variable/variable.freezed.dart create mode 100644 lib/src/domain/providers/config_providers.dart create mode 100644 lib/src/domain/providers/design_token_providers.dart create mode 100644 lib/src/domain/providers/figmage_package_generator_providers.dart create mode 100644 lib/src/domain/providers/file_writer_providers.dart create mode 100644 lib/src/domain/providers/generator_providers.dart create mode 100644 lib/src/domain/providers/logger_providers.dart create mode 100644 lib/src/domain/providers/post_generation_providers.dart create mode 100644 lib/src/domain/providers/pub_updater_providers.dart create mode 100644 lib/src/domain/repositories/file_writer_repository.dart create mode 100644 lib/src/domain/repositories/post_generation_repository.dart create mode 100644 lib/src/domain/util/token_filter_x.dart delete mode 100644 melos_figmage.iml delete mode 100644 melos_figmage_workspace.iml create mode 100644 packages/figma_variables_api/test/full_coverage_test.dart rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/.gitignore (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/CHANGELOG.md (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/README.md (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/analysis_options.yaml (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/lib/src/{{#generate_bools}}bools.dart{{/generate_bools}} (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/lib/src/{{#generate_colors}}colors.dart{{/generate_colors}} (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}}/lib/src/{{#generate_paddings}}paddings.dart{{/generate_paddings}} => lib/src/{{#generate_numbers}}numbers.dart{{/generate_numbers}}} (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}}/lib/src/{{#generate_radii}}radii.dart{{/generate_radii}} => lib/src/{{#generate_paddings}}paddings.dart{{/generate_paddings}}} (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}}/lib/src/{{#generate_spacers}}spacers.dart{{/generate_spacers}} => lib/src/{{#generate_radii}}radii.dart{{/generate_radii}}} (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}}/lib/src/{{#generate_strings}}strings.dart{{/generate_strings}} => lib/src/{{#generate_spacers}}spacers.dart{{/generate_spacers}}} (100%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}}/lib/src/{{#generate_typography}}typography.dart{{/generate_typography}} => lib/src/{{#generate_strings}}strings.dart{{/generate_strings}}} (100%) create mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_typography}}typography.dart{{/generate_typography}} rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/lib/{{project_name.snakeCase()}}.dart (88%) rename packages/figmage_package_generator/lib/src/brick/__brick__/{{{project_name.snakeCase()}} => }/pubspec.yaml (100%) delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/bug_report.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/build.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/chore.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/ci.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/config.yml delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/documentation.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/feature_request.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/performance.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/refactor.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/revert.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/style.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/test.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/PULL_REQUEST_TEMPLATE.md delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/dependabot.yaml delete mode 100644 packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/workflows/main.yaml delete mode 100644 packages/figmage_package_generator/lib/src/brick/hooks/post_gen.dart delete mode 100644 packages/figmage_package_generator/lib/src/brick/hooks/pubspec.yaml create mode 100644 packages/figmage_package_generator/lib/src/token_file_type.dart create mode 100644 packages/figmage_package_generator/test/full_coverage_test.dart create mode 100644 packages/figmage_package_generator/test/src/token_file_type_test.dart create mode 100644 test/full_coverage_test.dart create mode 100644 test/src/commands/shared/forge_settings_providers_test.dart create mode 100644 test/src/commands/shared/generation_notifier_test.dart rename test/src/data/generators/{genarator_util_test.dart => generator_util_test.dart} (70%) create mode 100644 test/src/data/generators/text_style_theme_extension_generator_test.dart delete mode 100644 test/src/data/generators/text_style_theme_generator_test.dart create mode 100644 test/src/data/repositories/dart_post_generation_repository_test.dart create mode 100644 test/src/domain/models/style/color_style_test.dart create mode 100644 test/src/domain/models/variable/variable_test.dart create mode 100644 test/src/domain/providers/config_providers_test.dart create mode 100644 test/src/domain/providers/generator_providers_test.dart create mode 100644 test/src/domain/util/token_filter_x_test.dart create mode 100644 test/test_util/mock/mock_styles.dart create mode 100644 test/test_util/mock/mock_variables.dart create mode 100644 test/test_util/test_provider_listener.dart diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 0c405b2d..79593537 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -48,5 +48,6 @@ jobs: uses: whynotmake-it/dart-coverage-assistant@5df622b0cf8ad8eca6baba5af82d49e140f785df with: enforce_threshold: 'single' + enforce_forbidden_decrease: 'none' lower_threshold: 50 upper_threshold: 90 diff --git a/.gitignore b/.gitignore index d15a7088..cce9d428 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,9 @@ build/ pubspec.lock pubspec_overrides.yaml .idea + +# Don't skip build test in CI +dart_test.yaml + +.vscode/settings.json +.vscode/launch.json \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index 0816eb80..7e95bdb3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,5 +1,7 @@ include: package:lintervention/analysis_options.yaml analyzer: - exclude: - - 'lib/src/version.dart' \ No newline at end of file + exclude: + - "lib/src/version.dart" + language: + strict-raw-types: false diff --git a/bin/figmage.dart b/bin/figmage.dart index ab9b9942..c374feae 100644 --- a/bin/figmage.dart +++ b/bin/figmage.dart @@ -1,9 +1,11 @@ import 'dart:io'; import 'package:figmage/src/command_runner.dart'; +import 'package:riverpod/riverpod.dart'; Future main(List args) async { - await _flushThenExit(await FigmageCommandRunner().run(args)); + final container = ProviderContainer(); + await _flushThenExit(await FigmageCommandRunner(container).run(args)); } /// Flushes the stdout and stderr streams, then exits the program with the given diff --git a/coverage/lcov.info b/coverage/lcov.info index 98da0a5c..dd34a970 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -1,757 +1,1159 @@ -SF:/home/runner/work/figmage/figmage/lib/src/command_runner.dart -DA:35,2 -DA:41,1 -DA:42,2 -DA:46,1 -DA:49,2 -DA:51,2 -DA:52,2 -DA:58,2 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/command_runner.dart +DA:29,4 +DA:31,2 +DA:32,2 +DA:38,2 +DA:44,6 +DA:45,6 +DA:46,6 +DA:51,8 +DA:53,1 +DA:54,3 +DA:56,2 +DA:59,2 +DA:60,2 +DA:61,2 +DA:63,2 DA:64,2 -DA:65,2 -DA:66,2 -DA:67,2 +DA:67,1 DA:68,2 DA:69,2 -DA:72,6 -DA:73,8 -DA:76,1 -DA:77,3 -DA:86,2 -DA:89,2 -DA:90,4 -DA:91,2 -DA:93,3 -DA:94,2 -DA:97,1 -DA:98,2 -DA:99,2 -DA:100,1 -DA:101,2 -DA:102,1 -DA:103,2 -DA:106,2 -DA:107,4 -DA:108,2 -DA:109,4 -DA:110,2 -DA:114,2 -DA:117,6 -DA:118,1 -DA:119,1 -DA:123,2 -DA:124,2 -DA:125,2 -DA:126,4 -DA:127,2 -DA:128,4 -DA:131,2 -DA:132,2 -DA:133,2 -DA:134,6 -DA:135,2 -DA:136,4 -DA:137,2 -DA:138,8 -DA:145,4 -DA:146,2 -DA:147,1 -DA:149,2 -DA:153,6 -DA:154,2 -DA:163,2 -DA:165,4 -DA:166,1 -DA:168,1 -DA:169,1 -DA:170,1 -DA:172,3 -DA:173,2 -LF:68 -LH:68 -end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/repositories/figma_variables_repository.dart -DA:16,0 -DA:21,0 -DA:22,0 -DA:26,1 -DA:33,2 -DA:37,1 -DA:39,1 -DA:41,2 -DA:43,1 -DA:44,0 -DA:46,1 -DA:48,2 -DA:51,3 -DA:53,2 -DA:55,1 -DA:57,2 -DA:60,1 -DA:61,2 -DA:68,0 -DA:72,0 -DA:74,0 -DA:81,1 -DA:85,2 -DA:86,2 +DA:70,1 +DA:71,2 +DA:72,1 +DA:73,2 +DA:76,2 +DA:77,4 +DA:78,2 +DA:79,4 +DA:80,2 +DA:84,1 DA:87,3 -DA:89,2 -DA:90,1 -DA:91,1 -DA:92,4 +DA:88,1 +DA:89,1 +DA:93,1 DA:94,1 -DA:96,2 -DA:97,1 +DA:95,1 +DA:97,2 DA:98,1 -DA:99,1 -DA:100,1 -DA:101,1 -DA:102,1 +DA:99,4 +DA:103,1 DA:104,1 DA:105,1 -DA:106,1 +DA:106,3 DA:107,1 -DA:108,1 -DA:109,2 -DA:110,2 -DA:112,1 +DA:108,2 +DA:109,1 +DA:110,4 +DA:117,2 DA:118,2 DA:119,1 -DA:120,1 -DA:121,1 DA:122,1 -DA:123,1 -DA:124,1 -DA:126,1 +DA:126,3 DA:127,1 -DA:128,1 -DA:129,1 -DA:130,1 -DA:131,2 -DA:132,2 -DA:134,1 -DA:140,2 +DA:136,1 +DA:138,1 +DA:139,2 +DA:140,1 DA:141,1 -DA:142,1 DA:143,1 DA:144,1 DA:145,1 -DA:146,1 -DA:148,1 -DA:149,1 -DA:150,1 -DA:151,1 -DA:152,1 -DA:153,2 -DA:154,2 -DA:156,1 -DA:162,2 -DA:163,1 -DA:164,1 -DA:165,1 -DA:166,1 -DA:167,1 -DA:168,1 -DA:170,1 -DA:171,1 -DA:172,1 -DA:173,1 -DA:174,1 -DA:175,2 -DA:176,2 -DA:178,1 -DA:185,0 -DA:188,1 -DA:198,1 -DA:203,1 -DA:204,0 -DA:205,0 -DA:206,0 -DA:210,3 -DA:211,3 -DA:212,3 -DA:213,3 -LF:101 -LH:90 -end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/commands/reforge/reforge_command.dart -DA:9,2 +DA:147,3 +DA:148,2 +LF:62 +LH:62 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/commands/reforge/reforge_command.dart +DA:11,2 DA:12,4 +DA:22,1 +DA:26,2 +DA:29,4 +DA:31,1 +DA:35,2 +DA:36,1 +LF:8 +LH:8 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/commands/shared/forge_settings_providers.dart +DA:18,4 +DA:19,5 DA:20,1 -DA:24,2 -DA:29,1 -DA:33,2 -DA:34,1 -LF:7 -LH:7 +DA:21,2 +DA:22,1 +DA:25,2 +DA:27,4 +DA:31,1 +DA:32,1 +DA:33,1 +DA:35,2 +DA:36,1 +DA:37,0 +DA:39,1 +DA:40,1 +DA:41,1 +LF:16 +LH:15 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/commands/update/update_command.dart -DA:14,2 -DA:18,0 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/commands/shared/generation_notifier.dart +DA:15,2 +DA:16,2 DA:23,1 -DA:29,2 -DA:32,1 -DA:34,2 -DA:37,2 -DA:39,0 -DA:40,0 +DA:25,3 +DA:30,5 +DA:32,0 +DA:36,2 +DA:37,3 +DA:39,2 +DA:40,3 +DA:43,5 +DA:46,2 +DA:47,3 +DA:48,1 +DA:49,1 +LF:15 +LH:14 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/commands/update/update_command.dart +DA:17,2 +DA:21,4 +DA:23,4 +DA:25,1 +DA:31,2 +DA:34,1 +DA:36,2 +DA:39,2 DA:41,0 -DA:43,1 +DA:42,0 +DA:43,0 DA:45,1 -DA:47,0 -DA:48,0 -DA:51,3 -DA:55,2 -DA:60,0 -DA:61,0 +DA:47,1 +DA:49,0 +DA:50,0 +DA:53,3 +DA:57,2 DA:62,0 -DA:65,3 -DA:66,0 -DA:67,0 +DA:63,0 +DA:64,0 +DA:67,3 DA:68,0 -DA:71,2 -DA:73,1 -LF:25 -LH:13 +DA:69,0 +DA:70,0 +DA:73,2 +DA:75,1 +LF:26 +LH:15 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/color_theme_extension_generator.dart -DA:4,2 -DA:6,8 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/color_theme_extension_generator.dart +DA:4,1 +DA:6,4 DA:18,2 DA:23,2 LF:4 LH:4 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/values_by_mode_theme_extension_generator.dart -DA:43,4 -DA:52,4 -DA:53,8 -DA:91,4 -DA:93,8 -DA:94,8 -DA:95,4 -DA:96,4 -DA:97,12 -DA:101,16 -DA:102,8 -DA:103,4 -DA:106,4 -DA:107,4 -DA:108,4 -DA:110,4 -DA:112,4 -DA:114,4 -DA:115,4 -DA:117,4 -DA:119,4 -DA:122,4 -DA:123,4 -DA:124,8 -DA:125,4 -DA:128,4 -DA:136,8 -DA:137,4 -DA:139,8 -DA:142,4 -DA:146,4 -DA:149,4 -DA:151,4 -DA:152,4 -DA:153,4 -DA:154,8 -DA:155,8 -DA:156,4 -DA:157,4 -DA:158,4 -DA:159,12 -DA:160,4 -DA:161,4 -DA:162,4 -DA:163,8 -DA:169,4 -DA:177,4 -DA:178,8 -DA:179,8 -DA:180,4 -DA:181,4 -DA:182,4 -DA:183,4 -DA:185,4 -DA:195,4 -DA:196,4 -DA:197,4 -DA:198,4 -DA:199,8 -DA:200,4 -DA:201,12 -DA:208,4 -DA:216,1 -DA:217,1 -DA:219,3 -DA:220,3 -DA:223,4 -DA:224,4 -DA:225,4 -DA:226,8 -DA:227,4 -DA:232,4 -DA:233,8 -DA:234,12 -DA:235,8 -DA:236,4 -DA:241,12 -DA:242,4 -DA:247,4 -DA:258,4 -DA:264,4 -DA:265,4 -DA:266,12 -DA:267,4 -DA:268,8 -DA:269,12 -DA:270,4 -DA:271,4 -DA:272,4 -DA:273,8 -DA:274,4 -DA:275,4 -DA:276,4 -DA:279,4 -DA:280,4 -DA:281,4 -DA:282,8 -DA:285,12 -DA:286,8 -DA:287,4 -DA:288,4 -DA:289,4 -DA:290,4 -DA:296,4 -DA:297,4 -DA:302,4 -DA:307,4 -DA:308,8 -DA:309,4 -DA:310,4 -DA:311,8 -DA:312,4 -DA:314,4 -DA:315,9 -DA:316,1 -DA:321,4 -DA:326,4 -DA:327,4 -DA:328,12 -DA:329,4 -DA:330,8 -DA:331,4 -DA:332,4 -DA:333,8 -DA:334,4 -DA:335,8 -DA:336,4 -DA:340,8 -DA:341,12 -DA:342,4 -DA:343,4 -DA:344,4 -DA:348,4 -DA:351,4 -DA:352,8 -DA:353,20 -DA:358,4 -DA:362,4 -DA:363,4 -DA:364,4 -DA:365,4 -DA:366,4 -DA:367,4 -DA:368,4 -DA:373,4 -DA:374,4 -DA:375,4 -DA:376,4 -DA:377,8 -DA:378,4 -DA:379,4 -DA:380,4 -DA:381,4 -DA:382,4 -DA:383,4 -DA:384,4 -DA:385,4 -DA:392,4 -DA:398,4 -DA:399,1 -DA:402,3 -DA:406,0 -DA:409,3 -DA:414,3 -DA:415,3 -DA:423,4 -DA:431,4 -LF:167 -LH:166 -end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/generator_util.dart -DA:2,5 -DA:3,5 -DA:4,15 -DA:5,10 -DA:6,10 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/generator_util.dart +DA:4,5 +DA:5,5 +DA:6,15 DA:7,10 -DA:17,7 -DA:20,35 -DA:21,28 -DA:22,1 -DA:29,14 -DA:30,14 -DA:31,10 -DA:38,14 -DA:42,7 -DA:43,14 -DA:44,7 -DA:45,1 -DA:51,14 -DA:56,7 -DA:57,28 -DA:61,7 -DA:62,28 -DA:67,21 -DA:70,7 -DA:71,22 -LF:26 -LH:26 +DA:8,10 +DA:9,10 +DA:19,6 +DA:21,18 +DA:25,1 +DA:26,4 +DA:30,6 +DA:31,24 +LF:12 +LH:12 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/domain/models/variable/alias_or/alias_or.dart -DA:21,4 -DA:35,4 -DA:36,3 -DA:37,4 -LF:4 -LH:4 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/number_theme_extension_generator.dart +DA:10,2 +DA:14,2 +LF:2 +LH:2 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/repositories/yaml_config_repository.dart -DA:15,1 -DA:17,1 -DA:21,1 -DA:26,1 -DA:30,4 -DA:32,1 -DA:36,1 -DA:38,1 -DA:39,1 -DA:42,3 -DA:44,1 -DA:45,2 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/padding_generator.dart +DA:12,2 +DA:18,4 +DA:43,1 +DA:45,3 +DA:46,3 +DA:47,3 +DA:49,1 +DA:51,1 DA:56,1 -DA:57,2 -DA:58,1 DA:59,1 DA:62,1 DA:63,1 -DA:64,1 +DA:64,2 DA:65,1 -DA:66,1 -LF:21 -LH:21 -end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/domain/models/config/config.dart -DA:28,4 -DA:43,4 -DA:86,2 -DA:87,16 -DA:92,4 -DA:93,12 +DA:76,2 +DA:77,1 +DA:79,2 +DA:82,1 +DA:87,1 +DA:89,1 +DA:92,2 +DA:93,1 +DA:94,1 +DA:95,1 DA:96,2 -DA:98,2 -DA:99,2 -DA:100,2 -DA:101,2 -DA:102,2 -DA:103,2 +DA:97,2 +DA:98,1 +DA:99,1 +DA:100,1 +DA:101,3 +DA:102,1 +DA:103,1 DA:104,2 -DA:105,2 -DA:106,2 -DA:107,2 -DA:108,2 -DA:109,2 -DA:110,2 -DA:121,7 -DA:127,2 -DA:128,2 -DA:137,2 -DA:139,2 -DA:140,6 -LF:26 -LH:26 +DA:110,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:119,2 +DA:120,1 +DA:125,3 +DA:126,2 +DA:127,1 +DA:132,2 +DA:133,1 +DA:138,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:142,2 +DA:143,1 +DA:144,1 +DA:145,1 +DA:146,1 +DA:152,1 +DA:156,1 +DA:157,1 +DA:158,1 +DA:159,1 +DA:160,1 +DA:164,1 +DA:169,1 +DA:170,1 +DA:171,1 +DA:172,1 +DA:173,1 +DA:174,1 +DA:176,7 +DA:178,1 +DA:179,1 +DA:180,1 +DA:181,1 +DA:182,2 +DA:193,1 +DA:200,4 +DA:201,4 +DA:202,4 +DA:203,4 +DA:204,2 +DA:205,2 +DA:206,2 +DA:208,2 +DA:209,2 +DA:210,2 +DA:212,2 +DA:213,2 +DA:214,2 +DA:215,2 +DA:216,2 +DA:220,1 +DA:222,1 +DA:225,1 +LF:91 +LH:91 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/domain/models/config/config.g.dart -DA:9,4 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/spacer_generator.dart DA:12,2 -DA:13,2 -DA:14,4 -DA:15,4 -DA:17,4 DA:18,4 -DA:19,2 -DA:21,2 -DA:23,2 -DA:24,2 -DA:26,2 -DA:28,2 -DA:29,2 -DA:31,2 -DA:33,2 -DA:34,2 -DA:36,2 -DA:38,2 -DA:39,2 -DA:41,2 -DA:43,2 -DA:44,2 -DA:46,2 -DA:48,2 -DA:49,2 -DA:51,2 -DA:53,2 -DA:60,2 -DA:61,1 +DA:43,1 +DA:45,3 +DA:46,3 +DA:47,3 +DA:49,1 +DA:51,1 +DA:56,1 +DA:59,1 DA:62,1 DA:63,1 -DA:64,1 -DA:65,2 -DA:66,2 -DA:67,2 -DA:68,2 -DA:69,2 -DA:70,2 -DA:71,2 -DA:74,4 -DA:77,2 -DA:78,2 -DA:79,4 -DA:80,2 -DA:82,2 -DA:83,4 -DA:90,1 -DA:91,1 -DA:92,1 -DA:93,2 -LF:51 -LH:51 +DA:64,2 +DA:65,1 +DA:76,2 +DA:77,1 +DA:79,2 +DA:82,1 +DA:87,1 +DA:89,1 +DA:92,2 +DA:93,1 +DA:94,1 +DA:95,1 +DA:96,2 +DA:97,2 +DA:98,1 +DA:99,1 +DA:100,1 +DA:101,3 +DA:102,1 +DA:103,1 +DA:104,2 +DA:110,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:119,2 +DA:120,1 +DA:125,3 +DA:126,2 +DA:127,1 +DA:132,2 +DA:133,1 +DA:138,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:142,2 +DA:143,1 +DA:144,1 +DA:145,1 +DA:146,1 +DA:152,1 +DA:156,1 +DA:157,1 +DA:158,1 +DA:159,1 +DA:160,1 +DA:164,1 +DA:168,1 +DA:169,1 +DA:170,1 +DA:171,1 +DA:172,1 +DA:173,1 +DA:174,2 +DA:175,1 +DA:176,1 +DA:177,2 +DA:183,1 +DA:184,1 +DA:185,1 +DA:186,1 +DA:187,2 +DA:188,1 +DA:189,1 +DA:190,2 +DA:199,1 +DA:205,4 +DA:206,4 +DA:208,2 +DA:209,1 +DA:211,1 +LF:84 +LH:84 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/text_style_theme_extension_generator.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/text_style_theme_extension_generator.dart DA:6,1 -DA:7,1 +DA:8,1 DA:9,1 +DA:10,2 +DA:11,2 +DA:12,4 +DA:13,2 +DA:14,1 DA:15,1 -DA:18,1 -DA:22,2 -DA:24,5 +DA:16,1 +DA:19,2 +DA:20,2 +DA:21,2 +DA:22,1 +DA:23,1 +DA:24,1 DA:25,1 -DA:26,2 -DA:27,2 -DA:38,2 -DA:43,2 -DA:50,1 -DA:52,1 -DA:53,2 -DA:54,1 -DA:55,2 -DA:56,0 -DA:67,1 -DA:72,1 +DA:26,0 +DA:60,2 +DA:65,2 LF:20 LH:19 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/padding_generator.dart -DA:11,1 -DA:17,2 -DA:41,1 -DA:43,3 -DA:44,3 -DA:45,3 -DA:47,1 -DA:49,1 -DA:54,1 -DA:57,1 -DA:60,1 -DA:61,1 -DA:62,2 -DA:63,1 -DA:74,2 -DA:75,1 -DA:77,2 -DA:80,1 -DA:85,1 -DA:87,1 -DA:90,2 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/generators/values_by_mode_theme_extension_generator.dart +DA:43,4 +DA:52,4 +DA:53,8 +DA:91,3 +DA:93,6 +DA:94,6 +DA:96,3 +DA:97,3 +DA:99,3 +DA:100,9 +DA:104,6 +DA:105,3 +DA:108,3 +DA:109,3 +DA:110,3 +DA:113,3 +DA:115,3 +DA:118,3 +DA:119,3 +DA:120,6 +DA:121,3 +DA:131,6 +DA:132,3 +DA:134,6 +DA:137,3 +DA:141,3 +DA:144,3 +DA:146,3 +DA:147,3 +DA:148,3 +DA:149,6 +DA:150,6 +DA:151,3 +DA:152,3 +DA:153,3 +DA:154,9 +DA:155,3 +DA:156,3 +DA:157,3 +DA:158,6 +DA:164,3 +DA:172,1 +DA:173,1 +DA:175,2 +DA:176,2 +DA:179,12 +DA:180,3 +DA:181,3 +DA:182,3 +DA:183,6 +DA:184,3 +DA:189,3 +DA:190,6 +DA:191,9 +DA:192,9 +DA:193,6 +DA:194,3 +DA:199,9 +DA:200,3 +DA:205,3 +DA:216,3 +DA:222,3 +DA:223,3 +DA:224,9 +DA:225,3 +DA:226,6 +DA:227,9 +DA:228,3 +DA:229,3 +DA:230,3 +DA:231,6 +DA:232,3 +DA:233,3 +DA:234,3 +DA:237,3 +DA:238,3 +DA:239,3 +DA:240,6 +DA:243,9 +DA:244,6 +DA:245,3 +DA:246,3 +DA:247,3 +DA:248,3 +DA:254,3 +DA:255,3 +DA:260,3 +DA:265,3 +DA:266,6 +DA:267,3 +DA:268,3 +DA:269,6 +DA:270,3 +DA:272,3 +DA:273,6 +DA:274,1 +DA:279,3 +DA:284,3 +DA:285,3 +DA:286,9 +DA:287,3 +DA:288,6 +DA:289,3 +DA:290,3 +DA:291,6 +DA:292,3 +DA:293,6 +DA:294,3 +DA:298,6 +DA:299,9 +DA:300,3 +DA:301,3 +DA:302,3 +DA:306,3 +DA:309,3 +DA:310,6 +DA:311,15 +DA:316,3 +DA:320,3 +DA:321,3 +DA:322,3 +DA:323,3 +DA:324,3 +DA:325,3 +DA:326,3 +DA:331,3 +DA:332,3 +DA:333,3 +DA:334,3 +DA:335,6 +DA:336,3 +DA:337,3 +DA:338,3 +DA:339,3 +DA:340,3 +DA:341,3 +DA:342,3 +DA:343,3 +DA:350,3 +DA:353,3 +DA:354,6 +DA:355,3 +DA:356,3 +DA:357,3 +DA:358,3 +DA:359,3 +DA:360,3 +DA:361,3 +DA:363,6 +DA:364,3 +DA:365,9 +DA:366,3 +DA:367,3 +DA:368,3 +DA:369,3 +DA:371,3 +DA:372,9 +DA:380,3 +DA:386,3 +DA:387,1 +DA:390,2 +DA:394,0 +DA:397,2 +DA:401,0 +DA:402,2 +DA:404,2 +DA:412,3 +DA:420,3 +LF:168 +LH:166 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/repositories/dart_code_file_writer_repository.dart +DA:7,0 +DA:13,0 +DA:14,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:22,0 +LF:7 +LH:0 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/repositories/figma_styles_repository.dart +DA:12,1 +DA:17,1 +DA:20,1 +DA:21,1 +DA:22,1 +DA:25,0 +DA:27,0 +DA:28,0 +DA:33,0 +DA:35,0 +DA:36,0 +DA:39,0 +DA:40,0 +DA:42,0 +DA:44,0 +DA:45,0 +DA:47,0 +DA:51,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:64,0 +DA:69,1 +DA:71,2 +DA:72,0 +LF:30 +LH:7 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/repositories/figma_variables_repository.dart +DA:16,0 +DA:21,0 +DA:22,0 +DA:26,1 +DA:33,2 +DA:37,1 +DA:39,1 +DA:41,2 +DA:43,1 +DA:44,0 +DA:46,1 +DA:48,2 +DA:51,3 +DA:53,2 +DA:55,1 +DA:57,2 +DA:60,1 +DA:61,2 +DA:68,0 +DA:72,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:80,0 +DA:83,0 DA:91,1 -DA:92,1 -DA:93,1 -DA:94,2 DA:95,2 -DA:96,1 -DA:97,1 -DA:98,1 -DA:99,3 -DA:100,1 +DA:96,2 +DA:98,3 +DA:100,2 DA:101,1 -DA:102,2 -DA:108,1 -DA:114,1 +DA:102,1 +DA:103,4 +DA:105,1 +DA:107,1 +DA:108,2 +DA:109,1 +DA:110,1 +DA:111,1 +DA:112,1 +DA:113,1 DA:115,1 DA:116,1 -DA:117,2 +DA:117,1 DA:118,1 -DA:123,3 -DA:124,2 -DA:125,1 -DA:130,2 +DA:119,1 +DA:120,2 +DA:121,2 +DA:123,1 +DA:128,2 +DA:129,1 +DA:130,1 DA:131,1 +DA:132,1 +DA:133,1 +DA:135,1 DA:136,1 DA:137,1 DA:138,1 DA:139,1 DA:140,2 -DA:141,1 -DA:142,1 +DA:141,2 DA:143,1 -DA:144,1 +DA:148,2 +DA:149,1 DA:150,1 -DA:154,1 +DA:151,1 +DA:152,1 +DA:153,1 DA:155,1 DA:156,1 DA:157,1 DA:158,1 -DA:162,1 -DA:167,1 -DA:168,1 +DA:159,1 +DA:160,2 +DA:161,2 +DA:163,1 +DA:168,2 DA:169,1 DA:170,1 DA:171,1 DA:172,1 -DA:174,7 +DA:173,1 +DA:175,1 DA:176,1 DA:177,1 DA:178,1 DA:179,1 DA:180,2 -DA:191,1 -DA:198,4 -DA:199,4 -DA:200,4 -DA:201,4 -DA:202,2 -DA:203,2 -DA:204,2 -DA:206,2 -DA:207,2 -DA:208,2 -DA:210,2 -DA:211,2 -DA:212,2 -DA:213,2 -DA:214,2 -DA:218,1 -DA:220,1 -DA:223,1 -LF:91 -LH:91 +DA:181,2 +DA:183,1 +DA:188,0 +DA:189,0 +DA:193,2 +DA:203,1 +DA:208,1 +DA:209,0 +DA:210,0 +DA:211,0 +DA:215,3 +DA:216,3 +DA:217,3 +DA:218,3 +LF:104 +LH:87 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/number_theme_extension_generator.dart -DA:10,1 -DA:14,1 -LF:2 -LH:2 +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/repositories/yaml_config_repository.dart +DA:17,1 +DA:21,4 +DA:23,1 +DA:28,1 +DA:32,4 +DA:34,2 +DA:35,2 +DA:39,1 +DA:43,1 +DA:45,0 +DA:46,0 +DA:49,3 +DA:51,1 +DA:52,2 +DA:63,1 +DA:64,2 +DA:65,0 +DA:66,0 +DA:69,1 +DA:70,1 +DA:71,1 +DA:72,1 +DA:73,1 +LF:23 +LH:19 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/util/converters/color_conversion_x.dart +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:14,0 +LF:8 +LH:0 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/util/converters/string_dart_conversion_x.dart +DA:5,6 +DA:6,24 +DA:10,6 +DA:11,24 +DA:16,18 +DA:19,6 +DA:20,19 +DA:24,6 +DA:26,30 +DA:27,24 +DA:28,1 +DA:35,12 +DA:36,12 +DA:37,9 +LF:14 +LH:14 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/data/util/converters/type_style_conversion_x.dart +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:20,0 +DA:22,0 +DA:24,0 +DA:25,0 +DA:32,0 +DA:37,0 +LF:13 +LH:0 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/config/config.dart +DA:29,26 +DA:45,4 +DA:92,2 +DA:93,18 +DA:98,4 +DA:99,12 +DA:104,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:120,2 +DA:122,4 +DA:123,4 +DA:124,4 +DA:125,4 +DA:126,4 +DA:127,4 +DA:128,4 +DA:129,4 +DA:130,4 +DA:131,4 +DA:132,4 +DA:133,4 +DA:134,4 +DA:135,4 +DA:146,40 +DA:152,2 +DA:153,2 +DA:162,2 +DA:164,4 +DA:165,12 +LF:37 +LH:27 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/config/config.g.dart +DA:9,4 +DA:12,2 +DA:13,2 +DA:14,2 +DA:15,2 +DA:16,4 +DA:18,4 +DA:19,4 +DA:20,2 +DA:22,2 +DA:24,2 +DA:25,2 +DA:27,2 +DA:29,2 +DA:30,2 +DA:32,2 +DA:34,2 +DA:35,2 +DA:37,2 +DA:39,2 +DA:40,2 +DA:42,2 +DA:44,1 +DA:45,2 +DA:47,2 +DA:49,2 +DA:50,2 +DA:52,2 +DA:54,2 +DA:55,2 +DA:57,2 +DA:59,2 +DA:66,2 +DA:67,1 +DA:68,1 +DA:69,1 +DA:70,1 +DA:71,2 +DA:72,2 +DA:73,2 +DA:74,2 +DA:75,2 +DA:76,2 +DA:77,2 +DA:78,2 +DA:81,4 +DA:84,2 +DA:85,2 +DA:86,4 +DA:87,2 +DA:89,2 +DA:90,4 +DA:97,1 +DA:98,1 +DA:99,1 +DA:100,2 +LF:56 +LH:56 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/style/design_style.dart +DA:13,2 +DA:25,0 +DA:26,0 +DA:31,1 +DA:32,1 +DA:33,2 +DA:36,0 +DA:37,0 +DA:39,0 +DA:48,2 +DA:60,1 +LF:11 +LH:6 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/text_style/text_style.dart +DA:46,2 +LF:1 +LH:1 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/tokens_by_file_type/tokens_by_file_type.dart +DA:22,2 +LF:1 +LH:1 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/variable/alias_or/alias_or.dart +DA:21,8 +DA:35,8 +DA:36,3 +DA:37,8 +LF:4 +LH:4 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/models/variable/variable.dart +DA:30,6 +DA:82,2 +DA:83,2 +DA:84,3 +DA:85,6 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:93,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:104,0 +DA:113,4 +DA:138,4 +DA:163,4 +DA:188,5 +LF:24 +LH:9 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/config_providers.dart +DA:11,4 +DA:12,5 +DA:13,2 +DA:14,2 +LF:4 +LH:4 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/design_token_providers.dart +DA:14,4 +DA:15,2 +DA:16,1 +DA:18,4 +DA:20,4 +DA:23,4 +DA:25,5 +DA:27,2 +DA:28,1 +DA:29,0 +DA:31,0 +DA:36,1 +DA:38,1 +DA:39,2 +DA:41,1 +DA:42,2 +DA:44,1 +DA:45,2 +DA:47,1 +DA:48,2 +DA:50,1 +DA:51,2 +DA:59,2 +DA:60,1 +DA:61,1 +DA:62,2 +DA:63,2 +DA:64,1 +DA:66,1 +DA:71,1 +DA:72,0 +DA:73,0 +DA:76,0 +DA:79,3 +DA:83,0 +DA:92,2 +DA:93,1 +DA:94,1 +DA:95,2 +DA:96,2 +DA:97,1 +DA:99,1 +DA:104,0 +DA:105,0 +DA:106,0 +DA:109,0 +DA:112,0 +DA:116,2 +LF:48 +LH:37 end_of_record -SF:/home/runner/work/figmage/figmage/lib/src/data/generators/spacer_generator.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/figmage_package_generator_providers.dart +DA:10,2 DA:11,1 -DA:17,2 +DA:15,4 +DA:16,2 +DA:17,0 +DA:19,0 +DA:20,0 +DA:22,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:48,0 +DA:49,0 +DA:52,0 +LF:22 +LH:4 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/file_writer_providers.dart +DA:8,2 +DA:9,1 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:15,0 +DA:16,0 +DA:19,0 +LF:9 +LH:2 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/generator_providers.dart +DA:22,6 +DA:24,2 +DA:25,4 +DA:27,8 +DA:28,8 +DA:30,2 +DA:31,2 +DA:32,2 +DA:35,2 +DA:36,4 +DA:39,2 +DA:40,4 DA:41,1 -DA:43,3 +DA:43,1 DA:44,3 -DA:45,3 +DA:46,1 DA:47,1 -DA:49,1 +DA:48,2 +DA:51,1 +DA:52,3 DA:54,1 -DA:57,1 +DA:55,1 +DA:57,2 DA:60,1 -DA:61,1 -DA:62,2 DA:63,1 -DA:74,2 +DA:64,1 +DA:65,2 +DA:68,1 +DA:71,1 +DA:72,1 +DA:73,1 +DA:74,1 DA:75,1 DA:77,2 DA:80,1 +DA:83,1 +DA:84,1 DA:85,1 +DA:86,1 DA:87,1 -DA:90,2 +DA:89,2 DA:91,1 DA:92,1 DA:93,1 -DA:94,2 -DA:95,2 -DA:96,1 -DA:97,1 -DA:98,1 -DA:99,3 -DA:100,1 +DA:98,2 +DA:99,2 +DA:100,2 DA:101,1 -DA:102,2 -DA:108,1 -DA:114,1 -DA:115,1 -DA:116,1 -DA:117,2 -DA:118,1 -DA:123,3 -DA:124,2 -DA:125,1 -DA:130,2 -DA:131,1 -DA:136,1 -DA:137,1 -DA:138,1 -DA:139,1 -DA:140,2 -DA:141,1 -DA:142,1 -DA:143,1 -DA:144,1 -DA:150,1 -DA:154,1 -DA:155,1 -DA:156,1 -DA:157,1 -DA:158,1 -DA:162,1 -DA:166,1 -DA:167,1 -DA:168,1 -DA:169,1 -DA:170,1 -DA:171,1 -DA:172,2 -DA:173,1 -DA:174,1 -DA:175,2 -DA:181,1 -DA:182,1 -DA:183,1 -DA:184,1 -DA:185,2 -DA:186,1 -DA:187,1 -DA:188,2 -DA:197,1 -DA:203,4 -DA:204,4 -DA:206,2 -DA:207,1 -DA:209,1 -LF:84 -LH:84 +DA:103,2 +DA:104,4 +DA:111,2 +DA:112,2 +LF:52 +LH:52 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/logger_providers.dart +DA:5,15 +LF:1 +LH:1 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/providers/pub_updater_providers.dart +DA:5,3 +LF:1 +LH:1 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/repositories/config_repository.dart +DA:9,4 +DA:10,2 +LF:2 +LH:2 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/repositories/file_writer_repository.dart +DA:7,0 +DA:8,0 +LF:2 +LH:0 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/repositories/styles_repository.dart +DA:6,2 +DA:7,3 +DA:26,18 +DA:37,18 +DA:39,0 +DA:50,0 +LF:6 +LH:4 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/repositories/variables_repository.dart +DA:10,4 +DA:11,2 +DA:71,0 +DA:82,0 +DA:98,0 +LF:5 +LH:2 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/lib/src/domain/util/token_filter_x.dart +DA:8,4 +DA:9,1 +DA:10,2 +DA:11,4 +DA:17,2 +DA:18,10 +DA:19,2 +DA:20,2 +DA:21,4 +DA:22,2 +DA:23,4 +DA:24,8 +DA:25,4 +DA:26,0 +LF:14 +LH:13 end_of_record diff --git a/dart_test.yaml b/dart_test.yaml deleted file mode 100644 index 2f46c7e9..00000000 --- a/dart_test.yaml +++ /dev/null @@ -1,3 +0,0 @@ -tags: - version-verify: - skip: "Should only be run during pull request. Verifies if version file is updated." \ No newline at end of file diff --git a/figmage.yaml b/figmage.yaml deleted file mode 100644 index 57882aa3..00000000 --- a/figmage.yaml +++ /dev/null @@ -1,2 +0,0 @@ -fileId: V84OhDZ1M2o0bo48HdXdHP -colors: true \ No newline at end of file diff --git a/integration_tests/generation_notifier_integration_test.dart b/integration_tests/generation_notifier_integration_test.dart new file mode 100644 index 00000000..ea70dc52 --- /dev/null +++ b/integration_tests/generation_notifier_integration_test.dart @@ -0,0 +1,55 @@ +import 'dart:io'; + +import 'package:figmage/src/command_runner.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:test/test.dart'; + +void main() { + group("GenerationNotifier", () { + late ProviderContainer container; + late String? token; + late String? fileId; + + late Directory testDirectory; + setUp(() { + testDirectory = Directory("${Directory.current.path}/test_generated"); + container = ProviderContainer(); + token = Platform.environment['FIGMA_TOKEN']; + fileId = Platform.environment['FIGMA_FILE_ID']; + }); + + tearDown(() { + container.dispose(); + try { + testDirectory.deleteSync(recursive: true); + } catch (_) {} + }); + + group('can generate variables from test file', () { + test( + 'should generate variables', + timeout: const Timeout(Duration(minutes: 1)), + () async { + final runner = FigmageCommandRunner(container); + await runner.run([ + 'forge', + '--token', + token!, + '--fileId', + fileId!, + '--path', + testDirectory.path, + ]); + + final files = [ + File("${testDirectory.path}/figmage_package/lib/src/colors.dart"), + File( + "${testDirectory.path}/figmage_package/lib/src/typography.dart", + ), + ]; + expect(files.every((f) => f.existsSync()), true); + }, + ); + }); + }); +} diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart index fb2c8b9d..b425ca4e 100644 --- a/lib/src/command_runner.dart +++ b/lib/src/command_runner.dart @@ -2,17 +2,11 @@ import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:cli_completion/cli_completion.dart'; import 'package:figmage/src/commands/commands.dart'; -import 'package:figmage/src/data/repositories/figma_variables_repository.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/providers/pub_updater_providers.dart'; import 'package:figmage/src/version.dart'; -import 'package:figmage_package_generator/figmage_package_generator.dart'; import 'package:mason_logger/mason_logger.dart'; -import 'package:pub_updater/pub_updater.dart'; - -///A typedef for a function that can be used to append strings to a file -typedef AppendCodeEntriesToFile = void Function( - List entries, - String filePath, -); +import 'package:riverpod/riverpod.dart'; /// The name of the executable. const executableName = 'figmage'; @@ -32,21 +26,7 @@ const description = 'A CLI tool for generating Figma styles for Flutter'; /// {@endtemplate} class FigmageCommandRunner extends CompletionCommandRunner { /// {@macro figmage_command_runner} - FigmageCommandRunner({ - Logger? logger, - PubUpdater? pubUpdater, - FigmagePackageGenerator? figmagePackageGenerator, - FigmaVariablesRepository? figmaVariablesRepository, - AppendCodeEntriesToFile? appendCodeEntriesToFile, - }) : _logger = logger ?? Logger(), - _pubUpdater = pubUpdater ?? PubUpdater(), - _figmagePackageGenerator = - figmagePackageGenerator ?? const FigmagePackageGenerator(), - _figmaVariablesRepository = - figmaVariablesRepository ?? FigmaVariablesRepository(), - _appendCodeEntriesToFile = - appendCodeEntriesToFile ?? appendToFileIfExisting, - super(executableName, description) { + FigmageCommandRunner(this._container) : super(executableName, description) { // Add root options and flags argParser ..addFlag( @@ -61,27 +41,17 @@ class FigmageCommandRunner extends CompletionCommandRunner { ); // Add sub commands - addCommand( - ForgeCommand( - logger: _logger, - figmagePackageGenerator: _figmagePackageGenerator, - figmaVariablesRepository: _figmaVariablesRepository, - appendCodeEntriesToFile: _appendCodeEntriesToFile, - ), - ); - addCommand(ReforgeCommand(logger: _logger)); - addCommand(UpdateCommand(logger: _logger, pubUpdater: _pubUpdater)); + addCommand(ForgeCommand(_container)); + addCommand(ReforgeCommand(_container)); + addCommand(UpdateCommand(_container)); } - @override - void printUsage() => _logger.info(usage); + final ProviderContainer _container; - final Logger _logger; - final PubUpdater _pubUpdater; - final FigmagePackageGenerator _figmagePackageGenerator; - final FigmaVariablesRepository _figmaVariablesRepository; + Logger get _logger => _container.read(loggerProvider); - final AppendCodeEntriesToFile _appendCodeEntriesToFile; + @override + void printUsage() => _logger.info(usage); @override Future run(Iterable args) async { @@ -123,11 +93,13 @@ class FigmageCommandRunner extends CompletionCommandRunner { _logger ..detail('Argument information:') ..detail(' Top level options:'); + for (final option in topLevelResults.options) { if (topLevelResults.wasParsed(option)) { _logger.detail(' - $option: ${topLevelResults[option]}'); } } + if (topLevelResults.command != null) { final commandResult = topLevelResults.command!; _logger @@ -146,6 +118,7 @@ class FigmageCommandRunner extends CompletionCommandRunner { _logger.info(packageVersion); exitCode = ExitCode.success.code; } else { + // Run the actual command exitCode = await super.runCommand(topLevelResults); } @@ -162,7 +135,9 @@ class FigmageCommandRunner extends CompletionCommandRunner { /// user. Future _checkForUpdates() async { try { - final latestVersion = await _pubUpdater.getLatestVersion(packageName); + final latestVersion = await _container + .read(pubUpdaterProvider) + .getLatestVersion(packageName); final isUpToDate = packageVersion == latestVersion; if (!isUpToDate) { _logger diff --git a/lib/src/commands/forge/forge_command.dart b/lib/src/commands/forge/forge_command.dart index 53a56c21..6c62d855 100644 --- a/lib/src/commands/forge/forge_command.dart +++ b/lib/src/commands/forge/forge_command.dart @@ -1,38 +1,30 @@ // coverage:ignore-file // TODO(Jesper): when implemented add test -import 'dart:io'; - import 'package:args/command_runner.dart'; -import 'package:figmage/src/command_runner.dart'; -import 'package:figmage/src/data/generators/color_theme_extension_generator.dart'; -import 'package:figmage/src/data/repositories/figma_variables_repository.dart'; -import 'package:figmage/src/domain/models/variable/variable.dart'; -import 'package:figmage_package_generator/figmage_package_generator.dart'; -import 'package:mason_logger/mason_logger.dart'; -import 'package:path/path.dart' as path; -import 'package:yaml/yaml.dart'; +import 'package:figmage/src/commands/shared/generation_notifier.dart'; +import 'package:riverpod/riverpod.dart'; /// {@template forge_command} /// -/// `figmage forge` -/// A [Command] to exemplify a sub command +/// `figmage forge --token --fileId ` +/// The command that forges a new package from the figma file. /// {@endtemplate} class ForgeCommand extends Command { /// {@macro forge_command} - ForgeCommand({ - required Logger logger, - required FigmagePackageGenerator figmagePackageGenerator, - required FigmaVariablesRepository figmaVariablesRepository, - required AppendCodeEntriesToFile appendCodeEntriesToFile, - }) : _logger = logger, - _figmaVariablesRepository = figmaVariablesRepository, - _figmagePackageGenerator = figmagePackageGenerator, - _appendCodeEntriesToFile = appendCodeEntriesToFile { + ForgeCommand(this._container) { argParser + ..addOption( + "path", + defaultsTo: ".", + help: ''' + The ouptut path for the generated package. Defaults to the current directory. + ''', + ) ..addOption( "token", abbr: "t", help: "Your figma API token", + mandatory: true, ) ..addOption( "fileId", @@ -41,113 +33,19 @@ class ForgeCommand extends Command { ); } - @override - String get description => - 'This command forges a new package from your figma file.'; + final ProviderContainer _container; @override String get name => 'forge'; - final Logger _logger; - final FigmagePackageGenerator _figmagePackageGenerator; - final FigmaVariablesRepository _figmaVariablesRepository; - final AppendCodeEntriesToFile _appendCodeEntriesToFile; + @override + String get description => + 'This command forges a new package from your figma file.'; @override Future run() async { - final maybeConfig = await readFigmageConfig(_logger); - final token = argResults?['token'] as String?; - final fileId = (argResults?['fileId'] ?? maybeConfig?['fileId']) as String?; - - if (token == null || fileId == null) { - _logger.err('Both token and fileId are required.'); - return ExitCode.usage.code; - } - - final targetDir = Directory.current; - final process = _logger.progress("Generating package"); - await _figmagePackageGenerator.generate( - projectName: "figmage_example", - dir: targetDir, - description: "A test ", - ); - process.complete("Successfully generated package!"); - - //VARIABLES - final variables = await _figmaVariablesRepository.getVariables( - fileId: fileId, - token: token, - ); - - if (maybeConfig == null || maybeConfig['colors'] == true) { - //Generate colors from variables - final collectionColorMaps = _figmaVariablesRepository - .createValueModeMap(variables: variables); - final colorGenerators = collectionColorMaps.entries.map((entry) { - return ColorThemeExtensionGenerator( - className: entry.key, - valuesByNameByMode: entry.value, - ); - }).toList(); - final colorExtensions = await Future.wait( - colorGenerators.map( - (g) => Future.value( - g.generate(), - ), - ), - ); - - _appendCodeEntriesToFile( - colorExtensions, - '${Directory.current.path}/figmage_example/lib/src/tokens/colors.dart', - ); - } - - return ExitCode.success.code; - } -} - -// ignore: public_member_api_docs -Future readFigmageConfig(Logger logger) async { - final projectRoot = Directory.current; - final figmageConfigPath = path.join(projectRoot.path, 'figmage.yaml'); - - final figmageConfigFile = File(figmageConfigPath); - - // ignore: avoid_slow_async_io - if (await figmageConfigFile.exists()) { - try { - final yamlString = await figmageConfigFile.readAsString(); - final yamlMap = loadYaml(yamlString); - return yamlMap as YamlMap?; - } catch (e, _) { - logger - ..warn('Errors occurred while parsing the YAML file:') - ..err(e.toString()); - } + final exitCode = + await _container.read(generationStateProvider(argResults!).future); + return exitCode.code; } - return null; -} - -// ignore: public_member_api_docs -void appendToFileIfExisting(List entries, String filePath) { - final file = File(filePath); - - // Create the file if it doesn't exist - if (!file.existsSync()) { - throw StateError( - 'Tried to add code to a file that did not exist: $filePath', - ); - } - - // Open the file in append mode - final sink = file.openWrite(mode: FileMode.append); - - // Append each entry to the file, separated by a line break - for (final entry in entries) { - sink.write('$entry\n'); - } - - // Close the file - sink.close(); } diff --git a/lib/src/commands/reforge/reforge_command.dart b/lib/src/commands/reforge/reforge_command.dart index 4615b437..24c6ac84 100644 --- a/lib/src/commands/reforge/reforge_command.dart +++ b/lib/src/commands/reforge/reforge_command.dart @@ -1,14 +1,14 @@ import 'package:args/command_runner.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; import 'package:mason_logger/mason_logger.dart'; +import 'package:riverpod/riverpod.dart'; /// {@template reforge_command} /// A [Command] that updates an existing package. /// {@endtemplate} class ReforgeCommand extends Command { /// {@macro reforge_command} - ReforgeCommand({ - required Logger logger, - }) : _logger = logger { + ReforgeCommand(this._container) { argParser.addOption( "token", abbr: "t", @@ -17,6 +17,8 @@ class ReforgeCommand extends Command { ); } + final ProviderContainer _container; + @override String get description => 'This command reforges an existing package from your figma file.'; @@ -24,7 +26,7 @@ class ReforgeCommand extends Command { @override String get name => 'reforge'; - final Logger _logger; + Logger get _logger => _container.read(loggerProvider); @override Future run() async { diff --git a/lib/src/commands/shared/arg_names.dart b/lib/src/commands/shared/arg_names.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lib/src/commands/shared/arg_names.dart @@ -0,0 +1 @@ + diff --git a/lib/src/commands/shared/forge_settings_providers.dart b/lib/src/commands/shared/forge_settings_providers.dart new file mode 100644 index 00000000..74febc81 --- /dev/null +++ b/lib/src/commands/shared/forge_settings_providers.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/providers/config_providers.dart'; +import 'package:path/path.dart'; +import 'package:riverpod/riverpod.dart'; + +/// The arguments for the [settingsProvider] famil. +typedef SettingsProviderArgs = ({ + ArgResults argResults, +}); + +/// Tries to parse the shared settings that are needed for the `forge` and +/// `reforge` commands. +/// +/// Throws an error if any aren't present. +final settingsProvider = FutureProvider.autoDispose + .family((ref, args) async { + final dir = switch (args.argResults['path']) { + final String dir => Directory(dir), + _ => Directory.current, + }; + + final configPath = join(dir.path, 'figmage.yaml'); + + final config = await ref.watch(configProvider(configPath).future); + final argResults = args.argResults; + + return ( + token: switch (argResults['token']) { + final String token => token, + _ => throw ArgumentError.notNull('token'), + }, + fileId: switch (argResults['fileId'] ?? config.fileId) { + final String fileId => fileId, + _ => throw ArgumentError.notNull('fileId'), + }, + path: switch (argResults['path']) { + final String path => path, + _ => throw ArgumentError.notNull('path'), + }, + config: config, + ); +}); diff --git a/lib/src/commands/shared/generation_notifier.dart b/lib/src/commands/shared/generation_notifier.dart new file mode 100644 index 00000000..9497df4d --- /dev/null +++ b/lib/src/commands/shared/generation_notifier.dart @@ -0,0 +1,73 @@ +import 'dart:async'; + +import 'package:args/args.dart'; +import 'package:figmage/src/commands/shared/forge_settings_providers.dart'; +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/providers/design_token_providers.dart'; +import 'package:figmage/src/domain/providers/figmage_package_generator_providers.dart'; +import 'package:figmage/src/domain/providers/file_writer_providers.dart'; +import 'package:figmage/src/domain/providers/generator_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/providers/post_generation_providers.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Provides the [GenerationNotifier] state +final generationStateProvider = AsyncNotifierProvider.autoDispose + .family( + GenerationNotifier.new, +); + +/// The notifier for the forge command +class GenerationNotifier + extends AutoDisposeFamilyAsyncNotifier { + @override + Future build(ArgResults arg) async { + final logger = ref.watch(loggerProvider); + + final FigmageSettings settings; + + try { + settings = await ref.watch(settingsProvider((argResults: arg)).future); + } catch (e) { + logger.err("Not all settings are present ($e)"); + rethrow; + } + + try { + await ref.watch( + filteredTokensProvider(settings).future, + ); + } catch (e) { + logger + ..err("Neither styles nor variables could be obtained from file " + "${settings.fileId}") + ..info("Make sure the file's library is published."); + rethrow; + } + + final generatedFiles = await ref.watch( + generatedPackageProvider(settings).future, + ); + + final generatorsByFiles = + await ref.watch(generatorsProvider(settings).future); + final codeByFiles = { + for (final MapEntry(key: file, value: generator) + in generatorsByFiles.entries) + file: generator.generate(), + }; + // write the files + await ref.watch( + fileWriterProvider(codeByFiles).future, + ); + + try { + await ref.watch(postGenerationTasksProvider(generatedFiles).future); + } catch (e) { + logger.warn("Failed to run post generation tasks: $e"); + } + + return ExitCode.success; + } +} diff --git a/lib/src/commands/update/update_command.dart b/lib/src/commands/update/update_command.dart index bb85f270..3f6135b0 100644 --- a/lib/src/commands/update/update_command.dart +++ b/lib/src/commands/update/update_command.dart @@ -2,23 +2,25 @@ import 'dart:io'; import 'package:args/command_runner.dart'; import 'package:figmage/src/command_runner.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/providers/pub_updater_providers.dart'; import 'package:figmage/src/version.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:pub_updater/pub_updater.dart'; +import 'package:riverpod/riverpod.dart'; /// {@template update_command} /// A command which updates the CLI. /// {@endtemplate} class UpdateCommand extends Command { /// {@macro update_command} - UpdateCommand({ - required Logger logger, - PubUpdater? pubUpdater, - }) : _logger = logger, - _pubUpdater = pubUpdater ?? PubUpdater(); + UpdateCommand(this._container); - final Logger _logger; - final PubUpdater _pubUpdater; + final ProviderContainer _container; + + Logger get _logger => _container.read(loggerProvider); + + PubUpdater get _pubUpdater => _container.read(pubUpdaterProvider); @override String get description => 'Update the CLI.'; diff --git a/lib/src/data/generators/generator_util.dart b/lib/src/data/generators/generator_util.dart index 1a5656e0..18cc8c54 100644 --- a/lib/src/data/generators/generator_util.dart +++ b/lib/src/data/generators/generator_util.dart @@ -1,3 +1,5 @@ +import 'package:figmage/src/data/util/converters/string_dart_conversion_x.dart'; + /// Makes sure that all maps in the list have the same keys. bool ensureSameKeys(List> maps) { if (maps.isEmpty) return true; @@ -16,57 +18,15 @@ bool ensureSameKeys(List> maps) { /// For example, `Number/NumberWith2Aliases` becomes `numberWith2Aliases`. String convertToValidVariableName(String variableName) { // Remove leading and trailing whitespace - final pathSegments = - variableName.split("/").map((s) => s.removeInvalidCharacters()).toList(); - if (pathSegments.every((s) => s.isEmpty) || pathSegments.isEmpty) { - throw ArgumentError.value( - variableName, - 'variableName', - 'The variable name does not contain any valid characters.', - ); - } - final camelCasePath = switch (pathSegments) { - [final first, ...final rest] => [ - first.toCamelCase().trim(), - ...rest.map((e) => e.toTitleCase().trim()), - ], - // coverage:ignore-start - _ => throw StateError('Invalid path segments: $pathSegments'), - // coverage:ignore-end - }; + return variableName.asCamelCasePath.join().removeLeadingNumbers(); +} - return camelCasePath.join().removeLeadingNumbers(); +/// Converts a given [variableName] to a dart top-level constant name. +String convertToValidConstantName(String variableName) { + return "k${variableName.asCamelCasePath.join().toTitleCase()}"; } /// Converts a given class name to a valid dart class name. String convertToValidClassName(String className) { - final filtered = className.trim().removeInvalidCharacters(); - if (filtered.isEmpty) { - throw ArgumentError.value( - className, - 'className', - 'The class name does not contain any valid characters.', - ); - } - return filtered.toTitleCase().removeLeadingNumbers(); -} - -extension on String { - /// Converts a string to title case. - String toTitleCase() { - return this[0].toUpperCase() + substring(1); - } - - /// Converts a string to camel case. - String toCamelCase() { - return this[0].toLowerCase() + substring(1); - } - - /// Removes all invalid characters from a string, which includes all - /// non-alphanumeric characters and underscores. - String removeInvalidCharacters() => replaceAll(RegExp('[^a-zA-Z0-9]'), ''); - - /// Removes all leading numbers from a string. - String removeLeadingNumbers() => - RegExp('[0-9]').hasMatch(this[0]) ? '\$$this' : this; + return className.asCamelCasePath.join().toTitleCase().removeLeadingNumbers(); } diff --git a/lib/src/data/generators/padding_generator.dart b/lib/src/data/generators/padding_generator.dart index ae305109..2e33a380 100644 --- a/lib/src/data/generators/padding_generator.dart +++ b/lib/src/data/generators/padding_generator.dart @@ -1,12 +1,13 @@ import 'package:code_builder/code_builder.dart'; import 'package:dart_style/dart_style.dart'; import 'package:figmage/src/data/generators/generator_util.dart'; +import 'package:figmage/src/data/generators/value_names_theme_class_generator.dart'; import 'package:figmage/src/domain/generators/theme_class_generator.dart'; /// {@template padding_generator} /// A generator for a padding class. /// {@endtemplate} -class PaddingGenerator implements ThemeClassGenerator { +class PaddingGenerator implements ValueNamesThemeClassGenerator { /// {@macro padding_generator_template} PaddingGenerator({ required this.className, @@ -28,7 +29,8 @@ class PaddingGenerator implements ThemeClassGenerator { final Reference numberReference; /// The names of the values - final List valueNames; + @override + final Iterable valueNames; final _dartfmt = DartFormatter(); diff --git a/lib/src/data/generators/spacer_generator.dart b/lib/src/data/generators/spacer_generator.dart index 82a80596..d53e9248 100644 --- a/lib/src/data/generators/spacer_generator.dart +++ b/lib/src/data/generators/spacer_generator.dart @@ -1,12 +1,13 @@ import 'package:code_builder/code_builder.dart'; import 'package:dart_style/dart_style.dart'; import 'package:figmage/src/data/generators/generator_util.dart'; +import 'package:figmage/src/data/generators/value_names_theme_class_generator.dart'; import 'package:figmage/src/domain/generators/theme_class_generator.dart'; ///{@template space_generator} ///A generator for a spacer class. ///{@endtemplate} -class SpacerGenerator implements ThemeClassGenerator { +class SpacerGenerator implements ValueNamesThemeClassGenerator { ///{@macro space_generator_template} SpacerGenerator({ required this.className, @@ -28,7 +29,8 @@ class SpacerGenerator implements ThemeClassGenerator { final Reference numberReference; ///The names of the values - final List valueNames; + @override + final Iterable valueNames; final _dartfmt = DartFormatter(); diff --git a/lib/src/data/generators/text_style_theme_extension_generator.dart b/lib/src/data/generators/text_style_theme_extension_generator.dart index 847ad288..e62ce945 100644 --- a/lib/src/data/generators/text_style_theme_extension_generator.dart +++ b/lib/src/data/generators/text_style_theme_extension_generator.dart @@ -1,68 +1,61 @@ import 'package:code_builder/code_builder.dart'; -import 'package:figma/figma.dart'; import 'package:figmage/src/data/generators/values_by_mode_theme_extension_generator.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; // TODO(Jesper): fix all this -ConstructorArguments _textStyleFromFigmaTypeStyle(TypeStyle typeStyle) { - final textStyleExpressions = _getTextStyleExpressions(typeStyle: typeStyle); +ConstructorArguments _textStyleConstructorArguments(TextStyle textStyle) { return ( positionalArguments: [], - namedArguments: textStyleExpressions, + namedArguments: { + 'fontFamily': literal(textStyle.fontFamily), + 'fontSize': literal(textStyle.fontSize), + 'fontWeight': refer('FontWeight').property('w${textStyle.fontWeight}'), + 'fontStyle': refer('FontStyle').property( + switch (textStyle.fontStyle) { + FontStyle.italic => 'italic', + FontStyle.normal => 'normal', + }, + ), + 'letterSpacing': literal(textStyle.letterSpacing), + 'height': literal(textStyle.height), + 'decoration': refer('TextDecoration').property( + switch (textStyle.decoration) { + TextDecoration.none => 'none', + TextDecoration.lineThrough => 'lineThrough', + TextDecoration.underline => 'underline', + TextDecoration.overline => 'overline', + }, + ), + //'inherit': + //'color': Maybe from fills? API is weird + //'backgroundColor': + //'wordSpacing': + //'textBaseline': + //'leadingDistribution': + //'locale': + //'foreground': + //'background': + //'shadows': + //'fontFeatures': + //'fontVariations': + //'decorationColor': + //'decorationStyle': + //'decorationThickness': + //'debugLabel': + //'fontFamilyFallback': + //'package': + //'overflow': + }, typeArguments: const [] ); } -Map _getTextStyleExpressions({ - required TypeStyle typeStyle, -}) { - return { - //'inherit': - //'color': Maybe from fills? API is weird - //'backgroundColor': - 'fontSize': literal(typeStyle.fontSize), - 'fontWeight': - refer('FontWeight').property('w${typeStyle.fontWeight?.toInt()}'), - 'fontStyle': refer('FontStyle') - .property(typeStyle.italic ?? false ? 'italic' : 'normal'), - 'letterSpacing': literal(typeStyle.letterSpacing), - //'wordSpacing': - //'textBaseline': - //'height': - //'leadingDistribution': - //'locale': - //'foreground': - //'background': - //'shadows': - //'fontFeatures': - //'fontVariations': - 'decoration': _getTextDecoration(typeStyle.textDecoration), - //'decorationColor': - //'decorationStyle': - //'decorationThickness': - //'debugLabel': - 'fontFamily': literal(typeStyle.fontFamily), - //'fontFamilyFallback': - //'package': - //'overflow': - }; -} - -Expression _getTextDecoration(TextDecoration? decoration) { - return switch (decoration) { - TextDecoration.strikeThrough => - refer('TextDecoration', 'dart:ui').property('lineThrough'), - TextDecoration.underline => - refer('TextDecoration', 'dart:ui').property('underline'), - null => refer('TextDecoration').property('none'), - }; -} - /// {@template text_style_theme_extension_generator} /// A [ValuesByModeThemeExtensionGenerator] for text style themes from Figma's /// TypeStyle. /// {@endtemplate} class TextStyleThemeExtensionGenerator - extends ValuesByModeThemeExtensionGenerator { + extends ValuesByModeThemeExtensionGenerator { /// {@macro text_style_theme_extension_generator} TextStyleThemeExtensionGenerator({ required super.className, @@ -71,6 +64,6 @@ class TextStyleThemeExtensionGenerator super.buildContextExtensionNullable = false, }) : super( extensionSymbol: 'TextStyle', - valueToConstructorArguments: _textStyleFromFigmaTypeStyle, + valueToConstructorArguments: _textStyleConstructorArguments, ); } diff --git a/lib/src/data/generators/value_names_theme_class_generator.dart b/lib/src/data/generators/value_names_theme_class_generator.dart new file mode 100644 index 00000000..70857fe0 --- /dev/null +++ b/lib/src/data/generators/value_names_theme_class_generator.dart @@ -0,0 +1,10 @@ +import 'package:figmage/src/domain/generators/theme_class_generator.dart'; + +/// {@template value_names_theme_class_generator} +/// A generator for a theme class which has a list of values as fields. +/// {@endtemplate} +abstract interface class ValueNamesThemeClassGenerator + implements ThemeClassGenerator { + /// The names of the values to generate fields for + Iterable get valueNames; +} diff --git a/lib/src/data/generators/values_by_mode_theme_extension_generator.dart b/lib/src/data/generators/values_by_mode_theme_extension_generator.dart index fe2080e4..9df5f3e3 100644 --- a/lib/src/data/generators/values_by_mode_theme_extension_generator.dart +++ b/lib/src/data/generators/values_by_mode_theme_extension_generator.dart @@ -92,28 +92,24 @@ abstract class ValuesByModeThemeExtensionGenerator String generate() { final validValueMaps = valuesByNameByMode.map( (key, value) => MapEntry( - convertToValidVariableName(key), + switch (key) { + "" => "", + _ => convertToValidVariableName(key), + }, value.map( (key, value) => MapEntry(convertToValidVariableName(key), value), ), ), ); - final namesList = validValueMaps.values.first.keys.toList(); final validClassName = convertToValidClassName(className); final $class = _getClass( - namesList: namesList, + valueMaps: validValueMaps, className: validClassName, extensionSymbol: extensionSymbol, extensionSymbolUrl: extensionSymbolUrl, lerpReference: lerpReference, ); - final modeConstants = _getExtensionModesFields( - className: validClassName, - extensionSymbol: extensionSymbol, - valueMaps: validValueMaps, - extensionSymbolUrl: extensionSymbolUrl, - valueToConstructorArguments: valueToConstructorArguments, - ); + final buildContextExtension = _getBuildContextExtension( className: validClassName, nullable: buildContextExtensionNullable, @@ -125,7 +121,6 @@ abstract class ValuesByModeThemeExtensionGenerator [ $class, buildContextExtension, - ...modeConstants, ], ), ); @@ -166,48 +161,9 @@ abstract class ValuesByModeThemeExtensionGenerator ); } - List _getExtensionModesFields({ - required String className, - required Map> valueMaps, - required String extensionSymbol, - required String? extensionSymbolUrl, - required ConstructorArguments Function(T value)? - valueToConstructorArguments, - }) { - final result = []; - valueMaps.forEach((modeName, values) { - final assignment = refer(className).newInstance( - [], - values.map( - (name, value) { - return MapEntry( - name, - _getValueExpression( - extensionSymbol, - extensionSymbolUrl, - value, - valueToConstructorArguments, - ), - ); - }, - ), - ); - result.add( - Field( - (b) => b - ..modifier = FieldModifier.constant - ..type = refer(className) - ..name = '$modeName$className' - ..assignment = assignment.code, - ), - ); - }); - return result; - } - Class _getClass({ required String className, - required List namesList, + required Map> valueMaps, required String extensionSymbol, required String? extensionSymbolUrl, required Reference? lerpReference, @@ -220,6 +176,7 @@ abstract class ValuesByModeThemeExtensionGenerator '$extensionSymbol?', extensionSymbolUrl, ); + final namesList = valueMaps.values.first.keys.toList(); return Class( (c) => c ..name = className @@ -232,6 +189,7 @@ abstract class ValuesByModeThemeExtensionGenerator ..extend = refer('ThemeExtension<$className>', 'package:flutter/material.dart') ..constructors.add(_getConstructor(nameList: namesList)) + ..constructors.addAll(_getNamedConstructors(valueMaps: valueMaps)) ..fields.addAll( _getClassFields( nameList: namesList, @@ -389,6 +347,36 @@ abstract class ValuesByModeThemeExtensionGenerator ); } + List _getNamedConstructors({ + required Map> valueMaps, + }) { + return [ + for (final MapEntry(key: modeName, value: valuesByName) + in valueMaps.entries) + Constructor( + (constructor) => constructor + ..constant = true + ..name = switch (modeName) { + "" => "standard", + _ => convertToValidVariableName(modeName), + } + ..initializers.addAll( + [ + for (final MapEntry(key: name, :value) in valuesByName.entries) + Code( + '$name = ${_getValueExpression( + extensionSymbol, + extensionSymbolUrl, + value, + valueToConstructorArguments, + ).accept(_emitter)}', + ), + ], + ), + ), + ]; + } + Expression _getValueExpression( String extensionSymbol, String? extensionSymbolUrl, @@ -412,7 +400,8 @@ abstract class ValuesByModeThemeExtensionGenerator ); final (:positionalArguments, :namedArguments, :typeArguments) = valueToConstructorArguments!(value); - return symbolReference.newInstance( + + return symbolReference.constInstance( positionalArguments, namedArguments, typeArguments, diff --git a/lib/src/data/repositories/dart_code_file_writer_repository.dart b/lib/src/data/repositories/dart_code_file_writer_repository.dart new file mode 100644 index 00000000..662f2e66 --- /dev/null +++ b/lib/src/data/repositories/dart_code_file_writer_repository.dart @@ -0,0 +1,30 @@ +import 'dart:io'; + +import 'package:figmage/src/domain/repositories/file_writer_repository.dart'; + +/// A [FileWriterRepository] for writing Dart code to files. +class DartCodeFileWriterRepository implements FileWriterRepository { + @override + Iterable writeFiles({ + required Map codeByFiles, + bool append = false, + bool createIfNotExists = true, + }) sync* { + for (final MapEntry(key: file, value: code) in codeByFiles.entries) { + final exists = file.existsSync(); + + if (exists == false && createIfNotExists) { + file.createSync(recursive: true); + } else if (exists == false && createIfNotExists == false) { + continue; + } + try { + file.writeAsStringSync( + code, + mode: append ? FileMode.append : FileMode.write, + ); + yield file; + } catch (_) {} + } + } +} diff --git a/lib/src/data/repositories/dart_post_generation_repository.dart b/lib/src/data/repositories/dart_post_generation_repository.dart new file mode 100644 index 00000000..dc356f73 --- /dev/null +++ b/lib/src/data/repositories/dart_post_generation_repository.dart @@ -0,0 +1,75 @@ +import 'dart:io'; + +import 'package:collection/collection.dart'; +import 'package:figmage/src/domain/repositories/post_generation_repository.dart'; +import 'package:mason_logger/mason_logger.dart'; + +/// A function that runs a process, like [Process.run]. +typedef ProcessRunner = Future Function( + String command, + List args, { + String? workingDirectory, +}); + +/// {@template dart_post_generation_repository} +/// A post generation repository that runs maintenance tasks on the generated +/// code. +/// +/// This repository finds the pubspec.yaml in generated files and runs the +/// following tasks on the directory containing the pubspec.yaml: +/// - `dart pub get` +/// - `dart format` +/// - `dart fix --apply` +/// {@endtemplate} +class DartPostGenerationRepository implements PostGenerationRepository { + /// {@macro dart_post_generation_repository} + /// + /// Allows to override the [processRunner] for testing purposes, defaults + /// to [Process.run]. + const DartPostGenerationRepository({ + ProcessRunner? processRunner, + }) : _processRunner = processRunner ?? Process.run; + + final ProcessRunner _processRunner; + + @override + Future> runMaintenanceTasks( + Iterable files, { + Progress? progress, + }) async { + final pubspecYaml = files + .firstWhereOrNull((element) => element.path.endsWith('pubspec.yaml')); + + if (pubspecYaml == null) { + progress?.fail("No pubspec.yaml found in generated files"); + return files; + } + + final directory = pubspecYaml.parent; + + try { + progress?.update("Running pub get in ${directory.path}"); + await _processRunner( + 'dart', + ['pub', 'get'], + workingDirectory: directory.path, + ); + progress?.update("Running dart format in ${directory.path}"); + await _processRunner( + 'dart', + ['format'], + workingDirectory: directory.path, + ); + progress?.update("Running dart fix in ${directory.path}"); + await _processRunner( + 'dart', + ['fix', '--apply'], + workingDirectory: directory.path, + ); + } catch (_) { + rethrow; + } + + return files; + } +} diff --git a/lib/src/data/repositories/figma_styles_repository.dart b/lib/src/data/repositories/figma_styles_repository.dart index 00534f52..3cbbfa42 100644 --- a/lib/src/data/repositories/figma_styles_repository.dart +++ b/lib/src/data/repositories/figma_styles_repository.dart @@ -1,4 +1,8 @@ -import 'package:figmage/src/domain/models/style.dart'; +import 'package:collection/collection.dart'; +import 'package:figma/figma.dart'; +import 'package:figmage/src/data/util/converters/color_conversion_x.dart'; +import 'package:figmage/src/data/util/converters/type_style_conversion_x.dart'; +import 'package:figmage/src/domain/models/style/design_style.dart'; import 'package:figmage/src/domain/repositories/styles_repository.dart'; /// {@template figma_styles_repository} @@ -6,10 +10,66 @@ import 'package:figmage/src/domain/repositories/styles_repository.dart'; /// {@endtemplate} class FigmaStylesRepository implements StylesRepository { @override - // TODO(timcreatedit): implement getStyles - Future> getStyles({ + Future>> getStyles({ required String fileId, required String token, - }) async => - []; + }) async { + final client = FigmaClient(token); + final StylesResponse stylesResponse; + try { + stylesResponse = await client.getFileStyles(fileId); + } on FigmaException catch (e) { + _throwError(e); + } + + final styles = stylesResponse.meta?.styles ?? []; + + if (styles.isEmpty) { + return []; + } + + final NodesResponse nodesResponse; + try { + nodesResponse = await client.getFileNodes( + fileId, + FigmaQuery( + ids: styles.map((e) => e.nodeId).whereNotNull().toList(), + ), + ); + } on FigmaException catch (e) { + _throwError(e); + } + final styleNodes = nodesResponse.nodes?.values.map((e) => e.document) ?? []; + + return [ + for (final node in styleNodes) + if (node != null) + if (_transformNode(node) case final style?) style, + ]; + } + + DesignStyle? _transformNode(Node node) { + return switch (node) { + Text( + :final id, + :final name?, + :final style?, + ) => + TextDesignStyle(id: id, name: name, value: style.toTextStyle()), + Rectangle( + :final id, + :final name?, + fills: [Paint(:final color?), ...], + ) => + ColorDesignStyle(id: id, name: name, value: color.toValue()), + _ => null, + } as DesignStyle?; + } + + Never _throwError(FigmaException e) { + throw switch (e) { + FigmaException(code: 403) => const UnauthorizedStylesException(), + _ => throw UnknownStylesException(e.message), + }; + } } diff --git a/lib/src/data/repositories/figma_variables_repository.dart b/lib/src/data/repositories/figma_variables_repository.dart index 4ee5a83c..8be26568 100644 --- a/lib/src/data/repositories/figma_variables_repository.dart +++ b/lib/src/data/repositories/figma_variables_repository.dart @@ -7,14 +7,14 @@ import 'package:freezed_annotation/freezed_annotation.dart'; /// Visible for testing @visibleForTesting typedef VariablesData = ({ - Map variables, + Map> variables, Map variableCollections }); /// The implementation of [VariablesRepository] for Figma. class FigmaVariablesRepository implements VariablesRepository { @override - Future> getVariables({ + Future>> getVariables({ required String fileId, required String token, }) async { @@ -25,8 +25,8 @@ class FigmaVariablesRepository implements VariablesRepository { @override VariableValuesByIdByModeByCollection - createValueModeMap({ - required List variables, + createValueModeMap>({ + required List> variables, bool useNames = true, }) { assert( @@ -70,8 +70,18 @@ class FigmaVariablesRepository implements VariablesRepository { required String token, }) async { final client = FigmaClient(token); - // ignore: unnecessary_await_in_return - return await client.getLocalVariables(fileId); + try { + // ignore: unnecessary_await_in_return + return await client.getLocalVariables(fileId); + } on FigmaException catch (e) { + if (e.code == 403) { + throw UnauthorizedVariablesException(e.message); + } else { + throw UnknownVariablesException(e.message); + } + } catch (e) { + throw UnknownVariablesException(e.toString()); + } } /// Converts a list of DTO variables into model variables. @@ -79,11 +89,12 @@ class FigmaVariablesRepository implements VariablesRepository { /// Given a [VariablesResponseDto], this method processes the variables within /// it, maps them to model variables, and returns a list of variables. @visibleForTesting - List fromDtoToModel( + List> fromDtoToModel( VariablesResponseDto variablesResponse, ) { final variableCollections = variablesResponse.meta.variableCollections; final dtoVariables = variablesResponse.meta.variables; + final variables = dtoVariables.values.map((dtoVariable) { final variableCollection = variableCollections[dtoVariable.variableCollectionId]; @@ -93,99 +104,93 @@ class FigmaVariablesRepository implements VariablesRepository { }; final collectionName = variableCollection.name; - if (dtoVariable.resolvedType == kResolvedTypeString) { - final variable = StringVariable( - id: dtoVariable.id, - name: dtoVariable.name, - remote: dtoVariable.remote, - key: dtoVariable.key, - variableCollectionId: dtoVariable.variableCollectionId, - variableCollectionName: collectionName, - resolvedType: dtoVariable.resolvedType, - description: dtoVariable.description, - hiddenFromPublishing: dtoVariable.hiddenFromPublishing, - scopes: dtoVariable.scopes, - codeSyntax: dtoVariable.codeSyntax, - valuesByMode: dtoVariable.valuesByMode.map( - (key, value) => MapEntry( - key, - _resolveAlias(value: value, dtoVariables: dtoVariables), + return switch (dtoVariable.resolvedType) { + kResolvedTypeString => StringVariable( + id: dtoVariable.id, + name: dtoVariable.name, + remote: dtoVariable.remote, + key: dtoVariable.key, + variableCollectionId: dtoVariable.variableCollectionId, + variableCollectionName: collectionName, + resolvedType: dtoVariable.resolvedType, + description: dtoVariable.description, + hiddenFromPublishing: dtoVariable.hiddenFromPublishing, + scopes: dtoVariable.scopes, + codeSyntax: dtoVariable.codeSyntax, + valuesByMode: dtoVariable.valuesByMode.map( + (key, value) => MapEntry( + key, + _resolveAlias(value: value, dtoVariables: dtoVariables), + ), ), + collectionModeNames: collectionModeNames, ), - collectionModeNames: collectionModeNames, - ); - return variable; - } else if (dtoVariable.resolvedType == kResolvedTypeBoolean) { - final variable = BooleanVariable( - id: dtoVariable.id, - name: dtoVariable.name, - remote: dtoVariable.remote, - key: dtoVariable.key, - variableCollectionId: dtoVariable.variableCollectionId, - variableCollectionName: collectionName, - resolvedType: dtoVariable.resolvedType, - description: dtoVariable.description, - hiddenFromPublishing: dtoVariable.hiddenFromPublishing, - scopes: dtoVariable.scopes, - codeSyntax: dtoVariable.codeSyntax, - valuesByMode: dtoVariable.valuesByMode.map( - (key, value) => MapEntry( - key, - _resolveAlias(value: value, dtoVariables: dtoVariables), + kResolvedTypeBoolean => BoolVariable( + id: dtoVariable.id, + name: dtoVariable.name, + remote: dtoVariable.remote, + key: dtoVariable.key, + variableCollectionId: dtoVariable.variableCollectionId, + variableCollectionName: collectionName, + resolvedType: dtoVariable.resolvedType, + description: dtoVariable.description, + hiddenFromPublishing: dtoVariable.hiddenFromPublishing, + scopes: dtoVariable.scopes, + codeSyntax: dtoVariable.codeSyntax, + valuesByMode: dtoVariable.valuesByMode.map( + (key, value) => MapEntry( + key, + _resolveAlias(value: value, dtoVariables: dtoVariables), + ), ), + collectionModeNames: collectionModeNames, ), - collectionModeNames: collectionModeNames, - ); - return variable; - } else if (dtoVariable.resolvedType == kResolvedTypeColor) { - final variable = ColorVariable( - id: dtoVariable.id, - name: dtoVariable.name, - remote: dtoVariable.remote, - key: dtoVariable.key, - variableCollectionId: dtoVariable.variableCollectionId, - variableCollectionName: collectionName, - resolvedType: dtoVariable.resolvedType, - description: dtoVariable.description, - hiddenFromPublishing: dtoVariable.hiddenFromPublishing, - scopes: dtoVariable.scopes, - codeSyntax: dtoVariable.codeSyntax, - valuesByMode: dtoVariable.valuesByMode.map( - (key, value) => MapEntry( - key, - _resolveAlias(value: value, dtoVariables: dtoVariables), + kResolvedTypeColor => ColorVariable( + id: dtoVariable.id, + name: dtoVariable.name, + remote: dtoVariable.remote, + key: dtoVariable.key, + variableCollectionId: dtoVariable.variableCollectionId, + variableCollectionName: collectionName, + resolvedType: dtoVariable.resolvedType, + description: dtoVariable.description, + hiddenFromPublishing: dtoVariable.hiddenFromPublishing, + scopes: dtoVariable.scopes, + codeSyntax: dtoVariable.codeSyntax, + valuesByMode: dtoVariable.valuesByMode.map( + (key, value) => MapEntry( + key, + _resolveAlias(value: value, dtoVariables: dtoVariables), + ), ), + collectionModeNames: collectionModeNames, ), - collectionModeNames: collectionModeNames, - ); - return variable; - } else if (dtoVariable.resolvedType == kResolvedTypeNumber) { - final variable = FloatVariable( - id: dtoVariable.id, - name: dtoVariable.name, - remote: dtoVariable.remote, - key: dtoVariable.key, - variableCollectionId: dtoVariable.variableCollectionId, - variableCollectionName: collectionName, - resolvedType: dtoVariable.resolvedType, - description: dtoVariable.description, - hiddenFromPublishing: dtoVariable.hiddenFromPublishing, - scopes: dtoVariable.scopes, - codeSyntax: dtoVariable.codeSyntax, - valuesByMode: dtoVariable.valuesByMode.map( - (key, value) => MapEntry( - key, - _resolveAlias(value: value, dtoVariables: dtoVariables), + kResolvedTypeNumber => FloatVariable( + id: dtoVariable.id, + name: dtoVariable.name, + remote: dtoVariable.remote, + key: dtoVariable.key, + variableCollectionId: dtoVariable.variableCollectionId, + variableCollectionName: collectionName, + resolvedType: dtoVariable.resolvedType, + description: dtoVariable.description, + hiddenFromPublishing: dtoVariable.hiddenFromPublishing, + scopes: dtoVariable.scopes, + codeSyntax: dtoVariable.codeSyntax, + valuesByMode: dtoVariable.valuesByMode.map( + (key, value) => MapEntry( + key, + _resolveAlias(value: value, dtoVariables: dtoVariables), + ), ), + collectionModeNames: collectionModeNames, ), - collectionModeNames: collectionModeNames, - ); - return variable; - } else { - throw TypeError(); - } + _ => throw UnsupportedError( + "The variable type ${dtoVariable.resolvedType} is not supported", + ), + }; }); - return variables.toList(); + return variables.cast>().toList(); } /// A helper function for resolving alias values within Figma variables. diff --git a/lib/src/data/repositories/yaml_config_repository.dart b/lib/src/data/repositories/yaml_config_repository.dart index f3da0b1c..3686e2be 100644 --- a/lib/src/data/repositories/yaml_config_repository.dart +++ b/lib/src/data/repositories/yaml_config_repository.dart @@ -2,8 +2,10 @@ import 'dart:async'; import 'dart:io'; import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; import 'package:figmage/src/domain/repositories/config_repository.dart'; import 'package:mason_logger/mason_logger.dart'; +import 'package:riverpod/riverpod.dart'; import 'package:yaml/yaml.dart'; /// {@template yaml_config_repository} @@ -12,11 +14,11 @@ import 'package:yaml/yaml.dart'; /// {@endtemplate} class YamlConfigRepository implements ConfigRepository { /// {@macro yaml_config_repository} - YamlConfigRepository({ - Logger? logger, - }) : _logger = logger ?? Logger(); + YamlConfigRepository(this._ref); - final Logger _logger; + final Ref _ref; + + Logger get _logger => _ref.read(loggerProvider); @override FutureOr readConfigFromFile({ @@ -29,6 +31,11 @@ class YamlConfigRepository implements ConfigRepository { _logger.info('Reading config from ${configFile.path}'); + if (configFile.existsSync() == false) { + _logger.info('Config file not found, using default config.'); + return const Config(); + } + final yamlMap = await _readYamlFile(configFile); final Config config; diff --git a/lib/src/data/util/converters/color_conversion_x.dart b/lib/src/data/util/converters/color_conversion_x.dart new file mode 100644 index 00000000..3c718068 --- /dev/null +++ b/lib/src/data/util/converters/color_conversion_x.dart @@ -0,0 +1,16 @@ +import 'package:figma/figma.dart'; + +/// Extension methods for converting [Color]s. +extension ColorConversionX on Color { + /// Converts a figma [Color] to a 32 bit integer. + int toValue() { + if ((r, g, b, a) case (final r?, final g?, final b?, final a?)) { + final red = (r * 255).round(); + final green = (g * 255).round(); + final blue = (b * 255).round(); + final alpha = (a * 255).round(); + return (alpha << 24) | (red << 16) | (green << 8) | blue; + } + throw Exception('Color is not valid'); + } +} diff --git a/lib/src/data/util/converters/string_dart_conversion_x.dart b/lib/src/data/util/converters/string_dart_conversion_x.dart new file mode 100644 index 00000000..8720e4f7 --- /dev/null +++ b/lib/src/data/util/converters/string_dart_conversion_x.dart @@ -0,0 +1,45 @@ +/// An extension on [String] that provides methods for converting a string to +/// valid dart code. +extension StringDartConversionX on String { + /// Converts a string to title case. + String toTitleCase() { + return this[0].toUpperCase() + substring(1); + } + + /// Converts a string to camel case. + String toCamelCase() { + return this[0].toLowerCase() + substring(1); + } + + /// Removes all invalid characters from a string, which includes all + /// non-alphanumeric characters and underscores. + String removeInvalidCharacters() => replaceAll(RegExp('[^a-zA-Z0-9]'), ''); + + /// Removes all leading numbers from a string. + String removeLeadingNumbers() => + RegExp('[0-9]').hasMatch(this[0]) ? '\$$this' : this; + + /// Converts a string that is a path into a camelCase path containing it's + /// segments. + List get asCamelCasePath { + final pathSegments = + split("/").map((s) => s.removeInvalidCharacters()).toList(); + if (pathSegments.every((s) => s.isEmpty) || pathSegments.isEmpty) { + throw ArgumentError.value( + this, + 'name path', + 'The name path does not contain any valid characters.', + ); + } + return switch (pathSegments) { + [final first, ...final rest] => [ + first.toCamelCase().trim(), + ...rest.map((e) => e.toTitleCase().trim()), + ], + // coverage:ignore-start + // This is never going to happen, because pathSegments is never empty. + _ => throw StateError('Invalid path segments: $pathSegments'), + // coverage:ignore-end + }; + } +} diff --git a/lib/src/data/util/converters/type_style_conversion_x.dart b/lib/src/data/util/converters/type_style_conversion_x.dart new file mode 100644 index 00000000..549207d1 --- /dev/null +++ b/lib/src/data/util/converters/type_style_conversion_x.dart @@ -0,0 +1,39 @@ +import 'package:figma/figma.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; +import 'package:meta/meta.dart'; + +/// An extension providing the method to for converting a [TypeStyle] to a +/// [TextStyle]. +extension TypeStyleConversionX on TypeStyle { + /// Converts a [TypeStyle] to a [TextStyle]. + TextStyle toTextStyle() => TextStyle( + fontFamily: fontFamily!, + fontSize: fontSize!.toDouble(), + fontWeight: convertFontWeight(fontWeight ?? 400), + fontStyle: italic ?? false ? FontStyle.italic : FontStyle.normal, + letterSpacing: letterSpacing?.toDouble() ?? 0, + height: convertLineHeight(lineHeightPx, fontSize), + ); + + /// Makes sure that the font weight is between 100 and 900 in increments of + /// 100. + @visibleForTesting + int convertFontWeight(num weight) { + final incremented = (weight / 100).round() * 100; + return switch (incremented) { + > 900 => 900, + < 100 => 100, + _ => incremented, + }; + } + + /// Converts the line height to the way Flutter expects it, relative to the + /// font size. + @visibleForTesting + double convertLineHeight(num? lineHeight, num? fontSize) { + if (lineHeight == null || fontSize == null) { + return 1; + } + return lineHeight / fontSize; + } +} diff --git a/lib/src/domain/models/config/config.dart b/lib/src/domain/models/config/config.dart index df8864c7..7a0f9c7d 100644 --- a/lib/src/domain/models/config/config.dart +++ b/lib/src/domain/models/config/config.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:figmage_package_generator/figmage_package_generator.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'config.g.dart'; @@ -26,14 +27,15 @@ part 'config.g.dart'; class Config with EquatableMixin { /// {@macro config} const Config({ - required this.fileId, - required this.packageName, + this.packageName = "figmage_package", + this.fileId, this.packageDescription = '', this.packageDir = '.', this.colors = const GenerationSettings(), this.typography = const GenerationSettings(), this.strings = const GenerationSettings(), this.bools = const GenerationSettings(), + this.numbers = const GenerationSettings(), this.spacers = const GenerationSettings(generate: false), this.paddings = const GenerationSettings(generate: false), this.radii = const GenerationSettings(generate: false), @@ -42,12 +44,12 @@ class Config with EquatableMixin { /// Initializes a [Config] from a json map. factory Config.fromMap(Map json) => _$ConfigFromJson(json); - /// figma file ID. - final String fileId; - /// The name of the generated dart package, e.g. figmage_example. final String packageName; + /// figma file ID. + final String? fileId; + /// The description of the generated dart package. final String packageDescription; @@ -73,6 +75,10 @@ class Config with EquatableMixin { /// all paths. final GenerationSettings bools; + /// Number generation settings, defaults to not generating number tokens from + /// all paths. + final GenerationSettings numbers; + /// Spacers generation settings, defaults to not generating spacers. final GenerationSettings spacers; @@ -84,7 +90,7 @@ class Config with EquatableMixin { /// All generation settings. List get allGenerationSettings => - [colors, typography, strings, bools, spacers, paddings, radii]; + [colors, typography, strings, bools, numbers, spacers, paddings, radii]; /// Whether any setting defines at least one `from` but has `generate: false`. /// @@ -92,6 +98,24 @@ class Config with EquatableMixin { bool get suspiciousFromDefined => allGenerationSettings .any((element) => element.from.isNotEmpty && element.generate == false); + /// Gets the specific [GenerationSettings] for a [TokenFileType]. + /// + /// Returns null if the type is not supported. + GenerationSettings? getForTokenType(TokenFileType? type) { + // TODO(tim): support all types + return switch (type) { + TokenFileType.color => colors, + TokenFileType.numbers => numbers, + TokenFileType.spacers => numbers, + TokenFileType.paddings => numbers, + TokenFileType.typography => null, + TokenFileType.radii => null, + TokenFileType.strings => null, + TokenFileType.bools => null, + null => null, + }; + } + /// Converts a [Config] to a map. Map toJson() => _$ConfigToJson(this); @@ -105,6 +129,7 @@ class Config with EquatableMixin { typography, strings, bools, + numbers, spacers, paddings, radii, diff --git a/lib/src/domain/models/config/config.g.dart b/lib/src/domain/models/config/config.g.dart index 23adcd9d..952d4b09 100644 --- a/lib/src/domain/models/config/config.g.dart +++ b/lib/src/domain/models/config/config.g.dart @@ -11,8 +11,9 @@ Config _$ConfigFromJson(Map json) => $checkedCreate( json, ($checkedConvert) { final val = Config( - fileId: $checkedConvert('fileId', (v) => v as String), - packageName: $checkedConvert('packageName', (v) => v as String), + packageName: $checkedConvert( + 'packageName', (v) => v as String? ?? "figmage_package"), + fileId: $checkedConvert('fileId', (v) => v as String?), packageDescription: $checkedConvert('packageDescription', (v) => v as String? ?? ''), packageDir: $checkedConvert('outputPath', (v) => v as String? ?? '.'), @@ -36,6 +37,11 @@ Config _$ConfigFromJson(Map json) => $checkedCreate( (v) => v == null ? const GenerationSettings() : GenerationSettings.fromJson(v as Map)), + numbers: $checkedConvert( + 'numbers', + (v) => v == null + ? const GenerationSettings() + : GenerationSettings.fromJson(v as Map)), spacers: $checkedConvert( 'spacers', (v) => v == null @@ -58,14 +64,15 @@ Config _$ConfigFromJson(Map json) => $checkedCreate( ); Map _$ConfigToJson(Config instance) => { - 'fileId': instance.fileId, 'packageName': instance.packageName, + 'fileId': instance.fileId, 'packageDescription': instance.packageDescription, 'outputPath': instance.packageDir, 'colors': instance.colors.toJson(), 'typography': instance.typography.toJson(), 'strings': instance.strings.toJson(), 'bools': instance.bools.toJson(), + 'numbers': instance.numbers.toJson(), 'spacers': instance.spacers.toJson(), 'paddings': instance.paddings.toJson(), 'radii': instance.radii.toJson(), diff --git a/lib/src/domain/models/design_token.dart b/lib/src/domain/models/design_token.dart new file mode 100644 index 00000000..3beb0360 --- /dev/null +++ b/lib/src/domain/models/design_token.dart @@ -0,0 +1,13 @@ +import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; + +/// A superclass for all design tokens (styles and variables). +abstract interface class DesignToken { + /// The name of this token, usually the last segment in the full name. + String get name; + + /// The full name of the token, including all collections. + String get fullName; + + /// The values of the token by mode. + Map> get valuesByMode; +} diff --git a/lib/src/domain/models/figmage_settings.dart b/lib/src/domain/models/figmage_settings.dart new file mode 100644 index 00000000..b42f5eef --- /dev/null +++ b/lib/src/domain/models/figmage_settings.dart @@ -0,0 +1,9 @@ +import 'package:figmage/src/domain/models/config/config.dart'; + +/// All settings that are used for the `forge` and `reforge` commands. +typedef FigmageSettings = ({ + String token, + String fileId, + String path, + Config config, +}); diff --git a/lib/src/domain/models/style.dart b/lib/src/domain/models/style.dart deleted file mode 100644 index 96c10fc1..00000000 --- a/lib/src/domain/models/style.dart +++ /dev/null @@ -1,3 +0,0 @@ -/// Represents a style. -// TODO(JsprBllnbm): See if this makes sense -class Style {} diff --git a/lib/src/domain/models/style/design_style.dart b/lib/src/domain/models/style/design_style.dart new file mode 100644 index 00000000..639b81b9 --- /dev/null +++ b/lib/src/domain/models/style/design_style.dart @@ -0,0 +1,65 @@ +import 'package:equatable/equatable.dart'; +import 'package:figmage/src/domain/models/design_token.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; +import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; +import 'package:meta/meta.dart'; + +/// {@template design_style} +/// A superlass for all design styles +/// {@endtemplate} +@immutable +sealed class DesignStyle with EquatableMixin implements DesignToken { + /// {@macro design_style} + const DesignStyle({ + required this.id, + required this.name, + required this.value, + }); + + /// The id of this DesignStyle. + final String id; + + @override + final String name; + + @override + String get fullName => name; + + /// The value of this DesignStyle. + final T value; + + @override + Map> get valuesByMode => { + "": AliasOr.data(data: value), + }; + + @override + List get props => [id, name, value]; + + @override + bool? get stringify => true; +} + +/// {@template color_style} +/// A style for colors. +/// {@endtemplate} +class ColorDesignStyle extends DesignStyle { + /// {@macro color_style} + const ColorDesignStyle({ + required super.id, + required super.name, + required super.value, + }); +} + +/// {@template text_style} +/// A style for typography. +/// {@endtemplate} +class TextDesignStyle extends DesignStyle { + /// {@macro text_style} + const TextDesignStyle({ + required super.id, + required super.name, + required super.value, + }); +} diff --git a/lib/src/domain/models/text_style/text_style.dart b/lib/src/domain/models/text_style/text_style.dart new file mode 100644 index 00000000..27dce513 --- /dev/null +++ b/lib/src/domain/models/text_style/text_style.dart @@ -0,0 +1,47 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'text_style.freezed.dart'; + +/// The applied text decoration +enum TextDecoration { + /// No decoration + none, + + /// A strike through decoration + lineThrough, + + /// An underline decoration + underline, + + /// An overline decoration + overline +} + +/// Whether to slant the glyphs in the font +enum FontStyle { + /// Use the upright glyphs + normal, + + /// Use glyphs designed for slanting + italic, +} + +/// {@template text_style} +/// Represents a Flutter `TextStyle`. +/// {@endtemplate} +@freezed +sealed class TextStyle with _$TextStyle { + /// {@macro text_style} + const factory TextStyle({ + required String fontFamily, + required double fontSize, + @Default(400) int fontWeight, + @Default(TextDecoration.none) TextDecoration decoration, + @Default(FontStyle.normal) FontStyle fontStyle, + @Default(1.0) double letterSpacing, + @Default(1.0) double wordSpacing, + @Default(1.0) double height, + }) = _TextStyle; + + const TextStyle._(); +} diff --git a/lib/src/domain/models/text_style/text_style.freezed.dart b/lib/src/domain/models/text_style/text_style.freezed.dart new file mode 100644 index 00000000..2a0fca35 --- /dev/null +++ b/lib/src/domain/models/text_style/text_style.freezed.dart @@ -0,0 +1,291 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'text_style.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$TextStyle { + String get fontFamily => throw _privateConstructorUsedError; + double get fontSize => throw _privateConstructorUsedError; + int get fontWeight => throw _privateConstructorUsedError; + TextDecoration get decoration => throw _privateConstructorUsedError; + FontStyle get fontStyle => throw _privateConstructorUsedError; + double get letterSpacing => throw _privateConstructorUsedError; + double get wordSpacing => throw _privateConstructorUsedError; + double get height => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $TextStyleCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TextStyleCopyWith<$Res> { + factory $TextStyleCopyWith(TextStyle value, $Res Function(TextStyle) then) = + _$TextStyleCopyWithImpl<$Res, TextStyle>; + @useResult + $Res call( + {String fontFamily, + double fontSize, + int fontWeight, + TextDecoration decoration, + FontStyle fontStyle, + double letterSpacing, + double wordSpacing, + double height}); +} + +/// @nodoc +class _$TextStyleCopyWithImpl<$Res, $Val extends TextStyle> + implements $TextStyleCopyWith<$Res> { + _$TextStyleCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fontFamily = null, + Object? fontSize = null, + Object? fontWeight = null, + Object? decoration = null, + Object? fontStyle = null, + Object? letterSpacing = null, + Object? wordSpacing = null, + Object? height = null, + }) { + return _then(_value.copyWith( + fontFamily: null == fontFamily + ? _value.fontFamily + : fontFamily // ignore: cast_nullable_to_non_nullable + as String, + fontSize: null == fontSize + ? _value.fontSize + : fontSize // ignore: cast_nullable_to_non_nullable + as double, + fontWeight: null == fontWeight + ? _value.fontWeight + : fontWeight // ignore: cast_nullable_to_non_nullable + as int, + decoration: null == decoration + ? _value.decoration + : decoration // ignore: cast_nullable_to_non_nullable + as TextDecoration, + fontStyle: null == fontStyle + ? _value.fontStyle + : fontStyle // ignore: cast_nullable_to_non_nullable + as FontStyle, + letterSpacing: null == letterSpacing + ? _value.letterSpacing + : letterSpacing // ignore: cast_nullable_to_non_nullable + as double, + wordSpacing: null == wordSpacing + ? _value.wordSpacing + : wordSpacing // ignore: cast_nullable_to_non_nullable + as double, + height: null == height + ? _value.height + : height // ignore: cast_nullable_to_non_nullable + as double, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$TextStyleImplCopyWith<$Res> + implements $TextStyleCopyWith<$Res> { + factory _$$TextStyleImplCopyWith( + _$TextStyleImpl value, $Res Function(_$TextStyleImpl) then) = + __$$TextStyleImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String fontFamily, + double fontSize, + int fontWeight, + TextDecoration decoration, + FontStyle fontStyle, + double letterSpacing, + double wordSpacing, + double height}); +} + +/// @nodoc +class __$$TextStyleImplCopyWithImpl<$Res> + extends _$TextStyleCopyWithImpl<$Res, _$TextStyleImpl> + implements _$$TextStyleImplCopyWith<$Res> { + __$$TextStyleImplCopyWithImpl( + _$TextStyleImpl _value, $Res Function(_$TextStyleImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fontFamily = null, + Object? fontSize = null, + Object? fontWeight = null, + Object? decoration = null, + Object? fontStyle = null, + Object? letterSpacing = null, + Object? wordSpacing = null, + Object? height = null, + }) { + return _then(_$TextStyleImpl( + fontFamily: null == fontFamily + ? _value.fontFamily + : fontFamily // ignore: cast_nullable_to_non_nullable + as String, + fontSize: null == fontSize + ? _value.fontSize + : fontSize // ignore: cast_nullable_to_non_nullable + as double, + fontWeight: null == fontWeight + ? _value.fontWeight + : fontWeight // ignore: cast_nullable_to_non_nullable + as int, + decoration: null == decoration + ? _value.decoration + : decoration // ignore: cast_nullable_to_non_nullable + as TextDecoration, + fontStyle: null == fontStyle + ? _value.fontStyle + : fontStyle // ignore: cast_nullable_to_non_nullable + as FontStyle, + letterSpacing: null == letterSpacing + ? _value.letterSpacing + : letterSpacing // ignore: cast_nullable_to_non_nullable + as double, + wordSpacing: null == wordSpacing + ? _value.wordSpacing + : wordSpacing // ignore: cast_nullable_to_non_nullable + as double, + height: null == height + ? _value.height + : height // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc + +class _$TextStyleImpl extends _TextStyle { + const _$TextStyleImpl( + {required this.fontFamily, + required this.fontSize, + this.fontWeight = 400, + this.decoration = TextDecoration.none, + this.fontStyle = FontStyle.normal, + this.letterSpacing = 1.0, + this.wordSpacing = 1.0, + this.height = 1.0}) + : super._(); + + @override + final String fontFamily; + @override + final double fontSize; + @override + @JsonKey() + final int fontWeight; + @override + @JsonKey() + final TextDecoration decoration; + @override + @JsonKey() + final FontStyle fontStyle; + @override + @JsonKey() + final double letterSpacing; + @override + @JsonKey() + final double wordSpacing; + @override + @JsonKey() + final double height; + + @override + String toString() { + return 'TextStyle(fontFamily: $fontFamily, fontSize: $fontSize, fontWeight: $fontWeight, decoration: $decoration, fontStyle: $fontStyle, letterSpacing: $letterSpacing, wordSpacing: $wordSpacing, height: $height)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$TextStyleImpl && + (identical(other.fontFamily, fontFamily) || + other.fontFamily == fontFamily) && + (identical(other.fontSize, fontSize) || + other.fontSize == fontSize) && + (identical(other.fontWeight, fontWeight) || + other.fontWeight == fontWeight) && + (identical(other.decoration, decoration) || + other.decoration == decoration) && + (identical(other.fontStyle, fontStyle) || + other.fontStyle == fontStyle) && + (identical(other.letterSpacing, letterSpacing) || + other.letterSpacing == letterSpacing) && + (identical(other.wordSpacing, wordSpacing) || + other.wordSpacing == wordSpacing) && + (identical(other.height, height) || other.height == height)); + } + + @override + int get hashCode => Object.hash(runtimeType, fontFamily, fontSize, fontWeight, + decoration, fontStyle, letterSpacing, wordSpacing, height); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$TextStyleImplCopyWith<_$TextStyleImpl> get copyWith => + __$$TextStyleImplCopyWithImpl<_$TextStyleImpl>(this, _$identity); +} + +abstract class _TextStyle extends TextStyle { + const factory _TextStyle( + {required final String fontFamily, + required final double fontSize, + final int fontWeight, + final TextDecoration decoration, + final FontStyle fontStyle, + final double letterSpacing, + final double wordSpacing, + final double height}) = _$TextStyleImpl; + const _TextStyle._() : super._(); + + @override + String get fontFamily; + @override + double get fontSize; + @override + int get fontWeight; + @override + TextDecoration get decoration; + @override + FontStyle get fontStyle; + @override + double get letterSpacing; + @override + double get wordSpacing; + @override + double get height; + @override + @JsonKey(ignore: true) + _$$TextStyleImplCopyWith<_$TextStyleImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/domain/models/tokens_by_file_type/tokens_by_type.dart b/lib/src/domain/models/tokens_by_file_type/tokens_by_type.dart new file mode 100644 index 00000000..84accc55 --- /dev/null +++ b/lib/src/domain/models/tokens_by_file_type/tokens_by_type.dart @@ -0,0 +1,25 @@ +import 'package:figmage/src/domain/models/design_token.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'tokens_by_type.freezed.dart'; + +/// {@template tokens_by_type} +/// A collection of tokens sorted by their respective types. +/// +/// Used to allow for typesafe access of tokens when generating. +/// {@endtemplate} +@freezed +sealed class TokensByType with _$TokensByType { + /// {@macro tokens_by_type} + const factory TokensByType({ + @Default([]) Iterable> colorTokens, + @Default([]) Iterable> typographyTokens, + @Default([]) Iterable> numberTokens, + @Default([]) Iterable> stringTokens, + @Default([]) Iterable> boolTokens, + }) = _TokensByType; + + const TokensByType._(); +} diff --git a/lib/src/domain/models/tokens_by_file_type/tokens_by_type.freezed.dart b/lib/src/domain/models/tokens_by_file_type/tokens_by_type.freezed.dart new file mode 100644 index 00000000..27170985 --- /dev/null +++ b/lib/src/domain/models/tokens_by_file_type/tokens_by_type.freezed.dart @@ -0,0 +1,239 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'tokens_by_type.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$TokensByType { + Iterable> get colorTokens => + throw _privateConstructorUsedError; + Iterable> get typographyTokens => + throw _privateConstructorUsedError; + Iterable> get numberTokens => + throw _privateConstructorUsedError; + Iterable> get stringTokens => + throw _privateConstructorUsedError; + Iterable> get boolTokens => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $TokensByTypeCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TokensByTypeCopyWith<$Res> { + factory $TokensByTypeCopyWith( + TokensByType value, $Res Function(TokensByType) then) = + _$TokensByTypeCopyWithImpl<$Res, TokensByType>; + @useResult + $Res call( + {Iterable> colorTokens, + Iterable> typographyTokens, + Iterable> numberTokens, + Iterable> stringTokens, + Iterable> boolTokens}); +} + +/// @nodoc +class _$TokensByTypeCopyWithImpl<$Res, $Val extends TokensByType> + implements $TokensByTypeCopyWith<$Res> { + _$TokensByTypeCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? colorTokens = null, + Object? typographyTokens = null, + Object? numberTokens = null, + Object? stringTokens = null, + Object? boolTokens = null, + }) { + return _then(_value.copyWith( + colorTokens: null == colorTokens + ? _value.colorTokens + : colorTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + typographyTokens: null == typographyTokens + ? _value.typographyTokens + : typographyTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + numberTokens: null == numberTokens + ? _value.numberTokens + : numberTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + stringTokens: null == stringTokens + ? _value.stringTokens + : stringTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + boolTokens: null == boolTokens + ? _value.boolTokens + : boolTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$TokensByTypeImplCopyWith<$Res> + implements $TokensByTypeCopyWith<$Res> { + factory _$$TokensByTypeImplCopyWith( + _$TokensByTypeImpl value, $Res Function(_$TokensByTypeImpl) then) = + __$$TokensByTypeImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Iterable> colorTokens, + Iterable> typographyTokens, + Iterable> numberTokens, + Iterable> stringTokens, + Iterable> boolTokens}); +} + +/// @nodoc +class __$$TokensByTypeImplCopyWithImpl<$Res> + extends _$TokensByTypeCopyWithImpl<$Res, _$TokensByTypeImpl> + implements _$$TokensByTypeImplCopyWith<$Res> { + __$$TokensByTypeImplCopyWithImpl( + _$TokensByTypeImpl _value, $Res Function(_$TokensByTypeImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? colorTokens = null, + Object? typographyTokens = null, + Object? numberTokens = null, + Object? stringTokens = null, + Object? boolTokens = null, + }) { + return _then(_$TokensByTypeImpl( + colorTokens: null == colorTokens + ? _value.colorTokens + : colorTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + typographyTokens: null == typographyTokens + ? _value.typographyTokens + : typographyTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + numberTokens: null == numberTokens + ? _value.numberTokens + : numberTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + stringTokens: null == stringTokens + ? _value.stringTokens + : stringTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + boolTokens: null == boolTokens + ? _value.boolTokens + : boolTokens // ignore: cast_nullable_to_non_nullable + as Iterable>, + )); + } +} + +/// @nodoc + +class _$TokensByTypeImpl extends _TokensByType { + const _$TokensByTypeImpl( + {this.colorTokens = const [], + this.typographyTokens = const [], + this.numberTokens = const [], + this.stringTokens = const [], + this.boolTokens = const []}) + : super._(); + + @override + @JsonKey() + final Iterable> colorTokens; + @override + @JsonKey() + final Iterable> typographyTokens; + @override + @JsonKey() + final Iterable> numberTokens; + @override + @JsonKey() + final Iterable> stringTokens; + @override + @JsonKey() + final Iterable> boolTokens; + + @override + String toString() { + return 'TokensByType(colorTokens: $colorTokens, typographyTokens: $typographyTokens, numberTokens: $numberTokens, stringTokens: $stringTokens, boolTokens: $boolTokens)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$TokensByTypeImpl && + const DeepCollectionEquality() + .equals(other.colorTokens, colorTokens) && + const DeepCollectionEquality() + .equals(other.typographyTokens, typographyTokens) && + const DeepCollectionEquality() + .equals(other.numberTokens, numberTokens) && + const DeepCollectionEquality() + .equals(other.stringTokens, stringTokens) && + const DeepCollectionEquality() + .equals(other.boolTokens, boolTokens)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(colorTokens), + const DeepCollectionEquality().hash(typographyTokens), + const DeepCollectionEquality().hash(numberTokens), + const DeepCollectionEquality().hash(stringTokens), + const DeepCollectionEquality().hash(boolTokens)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$TokensByTypeImplCopyWith<_$TokensByTypeImpl> get copyWith => + __$$TokensByTypeImplCopyWithImpl<_$TokensByTypeImpl>(this, _$identity); +} + +abstract class _TokensByType extends TokensByType { + const factory _TokensByType( + {final Iterable> colorTokens, + final Iterable> typographyTokens, + final Iterable> numberTokens, + final Iterable> stringTokens, + final Iterable> boolTokens}) = _$TokensByTypeImpl; + const _TokensByType._() : super._(); + + @override + Iterable> get colorTokens; + @override + Iterable> get typographyTokens; + @override + Iterable> get numberTokens; + @override + Iterable> get stringTokens; + @override + Iterable> get boolTokens; + @override + @JsonKey(ignore: true) + _$$TokensByTypeImplCopyWith<_$TokensByTypeImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/domain/models/variable/variable.dart b/lib/src/domain/models/variable/variable.dart index 99d8abef..3f391657 100644 --- a/lib/src/domain/models/variable/variable.dart +++ b/lib/src/domain/models/variable/variable.dart @@ -1,7 +1,6 @@ +import 'package:equatable/equatable.dart'; +import 'package:figmage/src/domain/models/design_token.dart'; import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'variable.freezed.dart'; /// Figmas identifier for string variables. const String kResolvedTypeString = 'STRING'; @@ -15,82 +14,190 @@ const String kResolvedTypeColor = 'COLOR'; /// Figmas identifier for boolean variables. const String kResolvedTypeBoolean = 'BOOLEAN'; +/// {@template variable} /// Represents a Figma variable with different data types. /// -/// The [Variable] class is used to model Figma variables with various data -/// types. -/// It provides constructors for different types of variables: boolean, float, +/// The [Variable] sealed class is used to model Figma variables with various +/// data types. +/// It provides classes for different types of variables: boolean, float, /// color, and string. -/// -/// The [Variable] class is part of a sealed union type, and each constructor is -/// associated with a specific data type. -@Freezed() -sealed class Variable with _$Variable { - /// A Figma variable with bool content. - factory Variable.boolean({ - required String id, - required String name, - required bool remote, - required String key, - required String variableCollectionId, - required String variableCollectionName, - required String resolvedType, - required String description, - required bool hiddenFromPublishing, - required List scopes, - required Map codeSyntax, - required Map collectionModeNames, - required Map> valuesByMode, - }) = BooleanVariable; - - /// A Figma variable with float content. - factory Variable.float({ - required String id, - required String name, - required bool remote, - required String key, - required String variableCollectionId, - required String variableCollectionName, - required String resolvedType, - required String description, - required bool hiddenFromPublishing, - required List scopes, - required Map codeSyntax, - required Map collectionModeNames, - required Map> valuesByMode, - }) = FloatVariable; - - /// A Figma variable with color content. - factory Variable.color({ - required String id, - required String name, - required bool remote, - required String key, - required String variableCollectionId, - required String variableCollectionName, - required String resolvedType, - required String description, - required bool hiddenFromPublishing, - required List scopes, - required Map codeSyntax, - required Map collectionModeNames, - required Map> valuesByMode, - }) = ColorVariable; - - /// A Figma variable with string content. - factory Variable.string({ - required String id, - required String name, - required bool remote, - required String key, - required String variableCollectionId, - required String variableCollectionName, - required String resolvedType, - required String description, - required bool hiddenFromPublishing, - required List scopes, - required Map codeSyntax, - required Map collectionModeNames, - required Map> valuesByMode, - }) = StringVariable; +/// {@endtemplate} +sealed class Variable with EquatableMixin implements DesignToken { + /// {@macro variable} + const Variable({ + required this.id, + required this.name, + required this.remote, + required this.key, + required this.variableCollectionId, + required this.variableCollectionName, + required this.resolvedType, + required this.description, + required this.hiddenFromPublishing, + required this.scopes, + required this.codeSyntax, + required this.collectionModeNames, + }); + + /// The ID of this variable. + final String id; + + /// The name of this variable. + @override + final String name; + + /// Whether this variable is remote. + final bool remote; + + /// The key of this variable. + final String key; + + /// The ID of the variable collection this variable belongs to. + final String variableCollectionId; + + /// The name of the variable collection this variable belongs to. + final String variableCollectionName; + + /// The resolved type of this variable (see constants above) + final String resolvedType; + + /// The description of this variable. + final String description; + + /// Whether this variable is hidden from publishing. + final bool hiddenFromPublishing; + + /// The scopes of this variable. + final List scopes; + + /// The code syntax of this variable. + final Map codeSyntax; + + /// The collection mode names of this variable. + final Map collectionModeNames; + + @override + String get fullName => switch (variableCollectionName) { + "" => name, + _ => "$variableCollectionName/$name", + }; + + @override + List get props => [ + id, + name, + remote, + key, + variableCollectionId, + variableCollectionName, + resolvedType, + description, + hiddenFromPublishing, + scopes, + codeSyntax, + collectionModeNames, + ]; + + @override + bool? get stringify => true; +} + +/// {@template color_variable} +/// A [Variable] with a color value. +/// {@endtemplate} +class ColorVariable extends Variable { + /// {@macro color_variable} + const ColorVariable({ + required super.id, + required super.name, + required super.remote, + required super.key, + required super.variableCollectionId, + required super.variableCollectionName, + required super.resolvedType, + required super.description, + required super.hiddenFromPublishing, + required super.scopes, + required super.codeSyntax, + required super.collectionModeNames, + required this.valuesByMode, + }); + + @override + final Map> valuesByMode; +} + +/// {@template float_variable} +/// A variable with a float (double) value. +/// {@endtemplate} +class FloatVariable extends Variable { + /// {@macro float_variable} + const FloatVariable({ + required super.id, + required super.name, + required super.remote, + required super.key, + required super.variableCollectionId, + required super.variableCollectionName, + required super.resolvedType, + required super.description, + required super.hiddenFromPublishing, + required super.scopes, + required super.codeSyntax, + required super.collectionModeNames, + required this.valuesByMode, + }); + + @override + final Map> valuesByMode; +} + +/// {@template string_variable} +/// A variable with a string value. +/// {@endtemplate} +class StringVariable extends Variable { + /// {@macro string_variable} + const StringVariable({ + required super.id, + required super.name, + required super.remote, + required super.key, + required super.variableCollectionId, + required super.variableCollectionName, + required super.resolvedType, + required super.description, + required super.hiddenFromPublishing, + required super.scopes, + required super.codeSyntax, + required super.collectionModeNames, + required this.valuesByMode, + }); + + @override + final Map> valuesByMode; +} + +/// {@template bool_variable} +/// A variable with a boolean value. +/// {@endtemplate} +class BoolVariable extends Variable { + /// {@macro bool_variable} + const BoolVariable({ + required super.id, + required super.name, + required super.remote, + required super.key, + required super.variableCollectionId, + required super.variableCollectionName, + required super.resolvedType, + required super.description, + required super.hiddenFromPublishing, + required super.scopes, + required super.codeSyntax, + required super.collectionModeNames, + required this.valuesByMode, + }); + + @override + final Map> valuesByMode; } diff --git a/lib/src/domain/models/variable/variable.freezed.dart b/lib/src/domain/models/variable/variable.freezed.dart deleted file mode 100644 index 2dcd026a..00000000 --- a/lib/src/domain/models/variable/variable.freezed.dart +++ /dev/null @@ -1,2621 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'variable.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -/// @nodoc -mixin _$Variable { - String get id => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - bool get remote => throw _privateConstructorUsedError; - String get key => throw _privateConstructorUsedError; - String get variableCollectionId => throw _privateConstructorUsedError; - String get variableCollectionName => throw _privateConstructorUsedError; - String get resolvedType => throw _privateConstructorUsedError; - String get description => throw _privateConstructorUsedError; - bool get hiddenFromPublishing => throw _privateConstructorUsedError; - List get scopes => throw _privateConstructorUsedError; - Map get codeSyntax => throw _privateConstructorUsedError; - Map get collectionModeNames => - throw _privateConstructorUsedError; - Map> get valuesByMode => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult when({ - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - boolean, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - float, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - color, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - string, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(BooleanVariable value) boolean, - required TResult Function(FloatVariable value) float, - required TResult Function(ColorVariable value) color, - required TResult Function(StringVariable value) string, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(BooleanVariable value)? boolean, - TResult? Function(FloatVariable value)? float, - TResult? Function(ColorVariable value)? color, - TResult? Function(StringVariable value)? string, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(BooleanVariable value)? boolean, - TResult Function(FloatVariable value)? float, - TResult Function(ColorVariable value)? color, - TResult Function(StringVariable value)? string, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $VariableCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $VariableCopyWith<$Res> { - factory $VariableCopyWith(Variable value, $Res Function(Variable) then) = - _$VariableCopyWithImpl<$Res, Variable>; - @useResult - $Res call( - {String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames}); -} - -/// @nodoc -class _$VariableCopyWithImpl<$Res, $Val extends Variable> - implements $VariableCopyWith<$Res> { - _$VariableCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? remote = null, - Object? key = null, - Object? variableCollectionId = null, - Object? variableCollectionName = null, - Object? resolvedType = null, - Object? description = null, - Object? hiddenFromPublishing = null, - Object? scopes = null, - Object? codeSyntax = null, - Object? collectionModeNames = null, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - remote: null == remote - ? _value.remote - : remote // ignore: cast_nullable_to_non_nullable - as bool, - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionId: null == variableCollectionId - ? _value.variableCollectionId - : variableCollectionId // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionName: null == variableCollectionName - ? _value.variableCollectionName - : variableCollectionName // ignore: cast_nullable_to_non_nullable - as String, - resolvedType: null == resolvedType - ? _value.resolvedType - : resolvedType // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - hiddenFromPublishing: null == hiddenFromPublishing - ? _value.hiddenFromPublishing - : hiddenFromPublishing // ignore: cast_nullable_to_non_nullable - as bool, - scopes: null == scopes - ? _value.scopes - : scopes // ignore: cast_nullable_to_non_nullable - as List, - codeSyntax: null == codeSyntax - ? _value.codeSyntax - : codeSyntax // ignore: cast_nullable_to_non_nullable - as Map, - collectionModeNames: null == collectionModeNames - ? _value.collectionModeNames - : collectionModeNames // ignore: cast_nullable_to_non_nullable - as Map, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$BooleanVariableImplCopyWith<$Res> - implements $VariableCopyWith<$Res> { - factory _$$BooleanVariableImplCopyWith(_$BooleanVariableImpl value, - $Res Function(_$BooleanVariableImpl) then) = - __$$BooleanVariableImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode}); -} - -/// @nodoc -class __$$BooleanVariableImplCopyWithImpl<$Res> - extends _$VariableCopyWithImpl<$Res, _$BooleanVariableImpl> - implements _$$BooleanVariableImplCopyWith<$Res> { - __$$BooleanVariableImplCopyWithImpl( - _$BooleanVariableImpl _value, $Res Function(_$BooleanVariableImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? remote = null, - Object? key = null, - Object? variableCollectionId = null, - Object? variableCollectionName = null, - Object? resolvedType = null, - Object? description = null, - Object? hiddenFromPublishing = null, - Object? scopes = null, - Object? codeSyntax = null, - Object? collectionModeNames = null, - Object? valuesByMode = null, - }) { - return _then(_$BooleanVariableImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - remote: null == remote - ? _value.remote - : remote // ignore: cast_nullable_to_non_nullable - as bool, - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionId: null == variableCollectionId - ? _value.variableCollectionId - : variableCollectionId // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionName: null == variableCollectionName - ? _value.variableCollectionName - : variableCollectionName // ignore: cast_nullable_to_non_nullable - as String, - resolvedType: null == resolvedType - ? _value.resolvedType - : resolvedType // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - hiddenFromPublishing: null == hiddenFromPublishing - ? _value.hiddenFromPublishing - : hiddenFromPublishing // ignore: cast_nullable_to_non_nullable - as bool, - scopes: null == scopes - ? _value._scopes - : scopes // ignore: cast_nullable_to_non_nullable - as List, - codeSyntax: null == codeSyntax - ? _value._codeSyntax - : codeSyntax // ignore: cast_nullable_to_non_nullable - as Map, - collectionModeNames: null == collectionModeNames - ? _value._collectionModeNames - : collectionModeNames // ignore: cast_nullable_to_non_nullable - as Map, - valuesByMode: null == valuesByMode - ? _value._valuesByMode - : valuesByMode // ignore: cast_nullable_to_non_nullable - as Map>, - )); - } -} - -/// @nodoc - -class _$BooleanVariableImpl implements BooleanVariable { - _$BooleanVariableImpl( - {required this.id, - required this.name, - required this.remote, - required this.key, - required this.variableCollectionId, - required this.variableCollectionName, - required this.resolvedType, - required this.description, - required this.hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) - : _scopes = scopes, - _codeSyntax = codeSyntax, - _collectionModeNames = collectionModeNames, - _valuesByMode = valuesByMode; - - @override - final String id; - @override - final String name; - @override - final bool remote; - @override - final String key; - @override - final String variableCollectionId; - @override - final String variableCollectionName; - @override - final String resolvedType; - @override - final String description; - @override - final bool hiddenFromPublishing; - final List _scopes; - @override - List get scopes { - if (_scopes is EqualUnmodifiableListView) return _scopes; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_scopes); - } - - final Map _codeSyntax; - @override - Map get codeSyntax { - if (_codeSyntax is EqualUnmodifiableMapView) return _codeSyntax; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_codeSyntax); - } - - final Map _collectionModeNames; - @override - Map get collectionModeNames { - if (_collectionModeNames is EqualUnmodifiableMapView) - return _collectionModeNames; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_collectionModeNames); - } - - final Map> _valuesByMode; - @override - Map> get valuesByMode { - if (_valuesByMode is EqualUnmodifiableMapView) return _valuesByMode; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_valuesByMode); - } - - @override - String toString() { - return 'Variable.boolean(id: $id, name: $name, remote: $remote, key: $key, variableCollectionId: $variableCollectionId, variableCollectionName: $variableCollectionName, resolvedType: $resolvedType, description: $description, hiddenFromPublishing: $hiddenFromPublishing, scopes: $scopes, codeSyntax: $codeSyntax, collectionModeNames: $collectionModeNames, valuesByMode: $valuesByMode)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$BooleanVariableImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.name, name) || other.name == name) && - (identical(other.remote, remote) || other.remote == remote) && - (identical(other.key, key) || other.key == key) && - (identical(other.variableCollectionId, variableCollectionId) || - other.variableCollectionId == variableCollectionId) && - (identical(other.variableCollectionName, variableCollectionName) || - other.variableCollectionName == variableCollectionName) && - (identical(other.resolvedType, resolvedType) || - other.resolvedType == resolvedType) && - (identical(other.description, description) || - other.description == description) && - (identical(other.hiddenFromPublishing, hiddenFromPublishing) || - other.hiddenFromPublishing == hiddenFromPublishing) && - const DeepCollectionEquality().equals(other._scopes, _scopes) && - const DeepCollectionEquality() - .equals(other._codeSyntax, _codeSyntax) && - const DeepCollectionEquality() - .equals(other._collectionModeNames, _collectionModeNames) && - const DeepCollectionEquality() - .equals(other._valuesByMode, _valuesByMode)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - const DeepCollectionEquality().hash(_scopes), - const DeepCollectionEquality().hash(_codeSyntax), - const DeepCollectionEquality().hash(_collectionModeNames), - const DeepCollectionEquality().hash(_valuesByMode)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$BooleanVariableImplCopyWith<_$BooleanVariableImpl> get copyWith => - __$$BooleanVariableImplCopyWithImpl<_$BooleanVariableImpl>( - this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - boolean, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - float, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - color, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - string, - }) { - return boolean( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - }) { - return boolean?.call( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - required TResult orElse(), - }) { - if (boolean != null) { - return boolean( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(BooleanVariable value) boolean, - required TResult Function(FloatVariable value) float, - required TResult Function(ColorVariable value) color, - required TResult Function(StringVariable value) string, - }) { - return boolean(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(BooleanVariable value)? boolean, - TResult? Function(FloatVariable value)? float, - TResult? Function(ColorVariable value)? color, - TResult? Function(StringVariable value)? string, - }) { - return boolean?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(BooleanVariable value)? boolean, - TResult Function(FloatVariable value)? float, - TResult Function(ColorVariable value)? color, - TResult Function(StringVariable value)? string, - required TResult orElse(), - }) { - if (boolean != null) { - return boolean(this); - } - return orElse(); - } -} - -abstract class BooleanVariable implements Variable { - factory BooleanVariable( - {required final String id, - required final String name, - required final bool remote, - required final String key, - required final String variableCollectionId, - required final String variableCollectionName, - required final String resolvedType, - required final String description, - required final bool hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) = - _$BooleanVariableImpl; - - @override - String get id; - @override - String get name; - @override - bool get remote; - @override - String get key; - @override - String get variableCollectionId; - @override - String get variableCollectionName; - @override - String get resolvedType; - @override - String get description; - @override - bool get hiddenFromPublishing; - @override - List get scopes; - @override - Map get codeSyntax; - @override - Map get collectionModeNames; - @override - Map> get valuesByMode; - @override - @JsonKey(ignore: true) - _$$BooleanVariableImplCopyWith<_$BooleanVariableImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$FloatVariableImplCopyWith<$Res> - implements $VariableCopyWith<$Res> { - factory _$$FloatVariableImplCopyWith( - _$FloatVariableImpl value, $Res Function(_$FloatVariableImpl) then) = - __$$FloatVariableImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode}); -} - -/// @nodoc -class __$$FloatVariableImplCopyWithImpl<$Res> - extends _$VariableCopyWithImpl<$Res, _$FloatVariableImpl> - implements _$$FloatVariableImplCopyWith<$Res> { - __$$FloatVariableImplCopyWithImpl( - _$FloatVariableImpl _value, $Res Function(_$FloatVariableImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? remote = null, - Object? key = null, - Object? variableCollectionId = null, - Object? variableCollectionName = null, - Object? resolvedType = null, - Object? description = null, - Object? hiddenFromPublishing = null, - Object? scopes = null, - Object? codeSyntax = null, - Object? collectionModeNames = null, - Object? valuesByMode = null, - }) { - return _then(_$FloatVariableImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - remote: null == remote - ? _value.remote - : remote // ignore: cast_nullable_to_non_nullable - as bool, - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionId: null == variableCollectionId - ? _value.variableCollectionId - : variableCollectionId // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionName: null == variableCollectionName - ? _value.variableCollectionName - : variableCollectionName // ignore: cast_nullable_to_non_nullable - as String, - resolvedType: null == resolvedType - ? _value.resolvedType - : resolvedType // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - hiddenFromPublishing: null == hiddenFromPublishing - ? _value.hiddenFromPublishing - : hiddenFromPublishing // ignore: cast_nullable_to_non_nullable - as bool, - scopes: null == scopes - ? _value._scopes - : scopes // ignore: cast_nullable_to_non_nullable - as List, - codeSyntax: null == codeSyntax - ? _value._codeSyntax - : codeSyntax // ignore: cast_nullable_to_non_nullable - as Map, - collectionModeNames: null == collectionModeNames - ? _value._collectionModeNames - : collectionModeNames // ignore: cast_nullable_to_non_nullable - as Map, - valuesByMode: null == valuesByMode - ? _value._valuesByMode - : valuesByMode // ignore: cast_nullable_to_non_nullable - as Map>, - )); - } -} - -/// @nodoc - -class _$FloatVariableImpl implements FloatVariable { - _$FloatVariableImpl( - {required this.id, - required this.name, - required this.remote, - required this.key, - required this.variableCollectionId, - required this.variableCollectionName, - required this.resolvedType, - required this.description, - required this.hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) - : _scopes = scopes, - _codeSyntax = codeSyntax, - _collectionModeNames = collectionModeNames, - _valuesByMode = valuesByMode; - - @override - final String id; - @override - final String name; - @override - final bool remote; - @override - final String key; - @override - final String variableCollectionId; - @override - final String variableCollectionName; - @override - final String resolvedType; - @override - final String description; - @override - final bool hiddenFromPublishing; - final List _scopes; - @override - List get scopes { - if (_scopes is EqualUnmodifiableListView) return _scopes; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_scopes); - } - - final Map _codeSyntax; - @override - Map get codeSyntax { - if (_codeSyntax is EqualUnmodifiableMapView) return _codeSyntax; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_codeSyntax); - } - - final Map _collectionModeNames; - @override - Map get collectionModeNames { - if (_collectionModeNames is EqualUnmodifiableMapView) - return _collectionModeNames; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_collectionModeNames); - } - - final Map> _valuesByMode; - @override - Map> get valuesByMode { - if (_valuesByMode is EqualUnmodifiableMapView) return _valuesByMode; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_valuesByMode); - } - - @override - String toString() { - return 'Variable.float(id: $id, name: $name, remote: $remote, key: $key, variableCollectionId: $variableCollectionId, variableCollectionName: $variableCollectionName, resolvedType: $resolvedType, description: $description, hiddenFromPublishing: $hiddenFromPublishing, scopes: $scopes, codeSyntax: $codeSyntax, collectionModeNames: $collectionModeNames, valuesByMode: $valuesByMode)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$FloatVariableImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.name, name) || other.name == name) && - (identical(other.remote, remote) || other.remote == remote) && - (identical(other.key, key) || other.key == key) && - (identical(other.variableCollectionId, variableCollectionId) || - other.variableCollectionId == variableCollectionId) && - (identical(other.variableCollectionName, variableCollectionName) || - other.variableCollectionName == variableCollectionName) && - (identical(other.resolvedType, resolvedType) || - other.resolvedType == resolvedType) && - (identical(other.description, description) || - other.description == description) && - (identical(other.hiddenFromPublishing, hiddenFromPublishing) || - other.hiddenFromPublishing == hiddenFromPublishing) && - const DeepCollectionEquality().equals(other._scopes, _scopes) && - const DeepCollectionEquality() - .equals(other._codeSyntax, _codeSyntax) && - const DeepCollectionEquality() - .equals(other._collectionModeNames, _collectionModeNames) && - const DeepCollectionEquality() - .equals(other._valuesByMode, _valuesByMode)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - const DeepCollectionEquality().hash(_scopes), - const DeepCollectionEquality().hash(_codeSyntax), - const DeepCollectionEquality().hash(_collectionModeNames), - const DeepCollectionEquality().hash(_valuesByMode)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$FloatVariableImplCopyWith<_$FloatVariableImpl> get copyWith => - __$$FloatVariableImplCopyWithImpl<_$FloatVariableImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - boolean, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - float, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - color, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - string, - }) { - return float( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - }) { - return float?.call( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - required TResult orElse(), - }) { - if (float != null) { - return float( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(BooleanVariable value) boolean, - required TResult Function(FloatVariable value) float, - required TResult Function(ColorVariable value) color, - required TResult Function(StringVariable value) string, - }) { - return float(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(BooleanVariable value)? boolean, - TResult? Function(FloatVariable value)? float, - TResult? Function(ColorVariable value)? color, - TResult? Function(StringVariable value)? string, - }) { - return float?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(BooleanVariable value)? boolean, - TResult Function(FloatVariable value)? float, - TResult Function(ColorVariable value)? color, - TResult Function(StringVariable value)? string, - required TResult orElse(), - }) { - if (float != null) { - return float(this); - } - return orElse(); - } -} - -abstract class FloatVariable implements Variable { - factory FloatVariable( - {required final String id, - required final String name, - required final bool remote, - required final String key, - required final String variableCollectionId, - required final String variableCollectionName, - required final String resolvedType, - required final String description, - required final bool hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) = - _$FloatVariableImpl; - - @override - String get id; - @override - String get name; - @override - bool get remote; - @override - String get key; - @override - String get variableCollectionId; - @override - String get variableCollectionName; - @override - String get resolvedType; - @override - String get description; - @override - bool get hiddenFromPublishing; - @override - List get scopes; - @override - Map get codeSyntax; - @override - Map get collectionModeNames; - @override - Map> get valuesByMode; - @override - @JsonKey(ignore: true) - _$$FloatVariableImplCopyWith<_$FloatVariableImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$ColorVariableImplCopyWith<$Res> - implements $VariableCopyWith<$Res> { - factory _$$ColorVariableImplCopyWith( - _$ColorVariableImpl value, $Res Function(_$ColorVariableImpl) then) = - __$$ColorVariableImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode}); -} - -/// @nodoc -class __$$ColorVariableImplCopyWithImpl<$Res> - extends _$VariableCopyWithImpl<$Res, _$ColorVariableImpl> - implements _$$ColorVariableImplCopyWith<$Res> { - __$$ColorVariableImplCopyWithImpl( - _$ColorVariableImpl _value, $Res Function(_$ColorVariableImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? remote = null, - Object? key = null, - Object? variableCollectionId = null, - Object? variableCollectionName = null, - Object? resolvedType = null, - Object? description = null, - Object? hiddenFromPublishing = null, - Object? scopes = null, - Object? codeSyntax = null, - Object? collectionModeNames = null, - Object? valuesByMode = null, - }) { - return _then(_$ColorVariableImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - remote: null == remote - ? _value.remote - : remote // ignore: cast_nullable_to_non_nullable - as bool, - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionId: null == variableCollectionId - ? _value.variableCollectionId - : variableCollectionId // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionName: null == variableCollectionName - ? _value.variableCollectionName - : variableCollectionName // ignore: cast_nullable_to_non_nullable - as String, - resolvedType: null == resolvedType - ? _value.resolvedType - : resolvedType // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - hiddenFromPublishing: null == hiddenFromPublishing - ? _value.hiddenFromPublishing - : hiddenFromPublishing // ignore: cast_nullable_to_non_nullable - as bool, - scopes: null == scopes - ? _value._scopes - : scopes // ignore: cast_nullable_to_non_nullable - as List, - codeSyntax: null == codeSyntax - ? _value._codeSyntax - : codeSyntax // ignore: cast_nullable_to_non_nullable - as Map, - collectionModeNames: null == collectionModeNames - ? _value._collectionModeNames - : collectionModeNames // ignore: cast_nullable_to_non_nullable - as Map, - valuesByMode: null == valuesByMode - ? _value._valuesByMode - : valuesByMode // ignore: cast_nullable_to_non_nullable - as Map>, - )); - } -} - -/// @nodoc - -class _$ColorVariableImpl implements ColorVariable { - _$ColorVariableImpl( - {required this.id, - required this.name, - required this.remote, - required this.key, - required this.variableCollectionId, - required this.variableCollectionName, - required this.resolvedType, - required this.description, - required this.hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) - : _scopes = scopes, - _codeSyntax = codeSyntax, - _collectionModeNames = collectionModeNames, - _valuesByMode = valuesByMode; - - @override - final String id; - @override - final String name; - @override - final bool remote; - @override - final String key; - @override - final String variableCollectionId; - @override - final String variableCollectionName; - @override - final String resolvedType; - @override - final String description; - @override - final bool hiddenFromPublishing; - final List _scopes; - @override - List get scopes { - if (_scopes is EqualUnmodifiableListView) return _scopes; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_scopes); - } - - final Map _codeSyntax; - @override - Map get codeSyntax { - if (_codeSyntax is EqualUnmodifiableMapView) return _codeSyntax; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_codeSyntax); - } - - final Map _collectionModeNames; - @override - Map get collectionModeNames { - if (_collectionModeNames is EqualUnmodifiableMapView) - return _collectionModeNames; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_collectionModeNames); - } - - final Map> _valuesByMode; - @override - Map> get valuesByMode { - if (_valuesByMode is EqualUnmodifiableMapView) return _valuesByMode; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_valuesByMode); - } - - @override - String toString() { - return 'Variable.color(id: $id, name: $name, remote: $remote, key: $key, variableCollectionId: $variableCollectionId, variableCollectionName: $variableCollectionName, resolvedType: $resolvedType, description: $description, hiddenFromPublishing: $hiddenFromPublishing, scopes: $scopes, codeSyntax: $codeSyntax, collectionModeNames: $collectionModeNames, valuesByMode: $valuesByMode)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$ColorVariableImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.name, name) || other.name == name) && - (identical(other.remote, remote) || other.remote == remote) && - (identical(other.key, key) || other.key == key) && - (identical(other.variableCollectionId, variableCollectionId) || - other.variableCollectionId == variableCollectionId) && - (identical(other.variableCollectionName, variableCollectionName) || - other.variableCollectionName == variableCollectionName) && - (identical(other.resolvedType, resolvedType) || - other.resolvedType == resolvedType) && - (identical(other.description, description) || - other.description == description) && - (identical(other.hiddenFromPublishing, hiddenFromPublishing) || - other.hiddenFromPublishing == hiddenFromPublishing) && - const DeepCollectionEquality().equals(other._scopes, _scopes) && - const DeepCollectionEquality() - .equals(other._codeSyntax, _codeSyntax) && - const DeepCollectionEquality() - .equals(other._collectionModeNames, _collectionModeNames) && - const DeepCollectionEquality() - .equals(other._valuesByMode, _valuesByMode)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - const DeepCollectionEquality().hash(_scopes), - const DeepCollectionEquality().hash(_codeSyntax), - const DeepCollectionEquality().hash(_collectionModeNames), - const DeepCollectionEquality().hash(_valuesByMode)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$ColorVariableImplCopyWith<_$ColorVariableImpl> get copyWith => - __$$ColorVariableImplCopyWithImpl<_$ColorVariableImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - boolean, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - float, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - color, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - string, - }) { - return color( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - }) { - return color?.call( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - required TResult orElse(), - }) { - if (color != null) { - return color( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(BooleanVariable value) boolean, - required TResult Function(FloatVariable value) float, - required TResult Function(ColorVariable value) color, - required TResult Function(StringVariable value) string, - }) { - return color(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(BooleanVariable value)? boolean, - TResult? Function(FloatVariable value)? float, - TResult? Function(ColorVariable value)? color, - TResult? Function(StringVariable value)? string, - }) { - return color?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(BooleanVariable value)? boolean, - TResult Function(FloatVariable value)? float, - TResult Function(ColorVariable value)? color, - TResult Function(StringVariable value)? string, - required TResult orElse(), - }) { - if (color != null) { - return color(this); - } - return orElse(); - } -} - -abstract class ColorVariable implements Variable { - factory ColorVariable( - {required final String id, - required final String name, - required final bool remote, - required final String key, - required final String variableCollectionId, - required final String variableCollectionName, - required final String resolvedType, - required final String description, - required final bool hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) = - _$ColorVariableImpl; - - @override - String get id; - @override - String get name; - @override - bool get remote; - @override - String get key; - @override - String get variableCollectionId; - @override - String get variableCollectionName; - @override - String get resolvedType; - @override - String get description; - @override - bool get hiddenFromPublishing; - @override - List get scopes; - @override - Map get codeSyntax; - @override - Map get collectionModeNames; - @override - Map> get valuesByMode; - @override - @JsonKey(ignore: true) - _$$ColorVariableImplCopyWith<_$ColorVariableImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$StringVariableImplCopyWith<$Res> - implements $VariableCopyWith<$Res> { - factory _$$StringVariableImplCopyWith(_$StringVariableImpl value, - $Res Function(_$StringVariableImpl) then) = - __$$StringVariableImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode}); -} - -/// @nodoc -class __$$StringVariableImplCopyWithImpl<$Res> - extends _$VariableCopyWithImpl<$Res, _$StringVariableImpl> - implements _$$StringVariableImplCopyWith<$Res> { - __$$StringVariableImplCopyWithImpl( - _$StringVariableImpl _value, $Res Function(_$StringVariableImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? name = null, - Object? remote = null, - Object? key = null, - Object? variableCollectionId = null, - Object? variableCollectionName = null, - Object? resolvedType = null, - Object? description = null, - Object? hiddenFromPublishing = null, - Object? scopes = null, - Object? codeSyntax = null, - Object? collectionModeNames = null, - Object? valuesByMode = null, - }) { - return _then(_$StringVariableImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - remote: null == remote - ? _value.remote - : remote // ignore: cast_nullable_to_non_nullable - as bool, - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionId: null == variableCollectionId - ? _value.variableCollectionId - : variableCollectionId // ignore: cast_nullable_to_non_nullable - as String, - variableCollectionName: null == variableCollectionName - ? _value.variableCollectionName - : variableCollectionName // ignore: cast_nullable_to_non_nullable - as String, - resolvedType: null == resolvedType - ? _value.resolvedType - : resolvedType // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - hiddenFromPublishing: null == hiddenFromPublishing - ? _value.hiddenFromPublishing - : hiddenFromPublishing // ignore: cast_nullable_to_non_nullable - as bool, - scopes: null == scopes - ? _value._scopes - : scopes // ignore: cast_nullable_to_non_nullable - as List, - codeSyntax: null == codeSyntax - ? _value._codeSyntax - : codeSyntax // ignore: cast_nullable_to_non_nullable - as Map, - collectionModeNames: null == collectionModeNames - ? _value._collectionModeNames - : collectionModeNames // ignore: cast_nullable_to_non_nullable - as Map, - valuesByMode: null == valuesByMode - ? _value._valuesByMode - : valuesByMode // ignore: cast_nullable_to_non_nullable - as Map>, - )); - } -} - -/// @nodoc - -class _$StringVariableImpl implements StringVariable { - _$StringVariableImpl( - {required this.id, - required this.name, - required this.remote, - required this.key, - required this.variableCollectionId, - required this.variableCollectionName, - required this.resolvedType, - required this.description, - required this.hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) - : _scopes = scopes, - _codeSyntax = codeSyntax, - _collectionModeNames = collectionModeNames, - _valuesByMode = valuesByMode; - - @override - final String id; - @override - final String name; - @override - final bool remote; - @override - final String key; - @override - final String variableCollectionId; - @override - final String variableCollectionName; - @override - final String resolvedType; - @override - final String description; - @override - final bool hiddenFromPublishing; - final List _scopes; - @override - List get scopes { - if (_scopes is EqualUnmodifiableListView) return _scopes; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_scopes); - } - - final Map _codeSyntax; - @override - Map get codeSyntax { - if (_codeSyntax is EqualUnmodifiableMapView) return _codeSyntax; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_codeSyntax); - } - - final Map _collectionModeNames; - @override - Map get collectionModeNames { - if (_collectionModeNames is EqualUnmodifiableMapView) - return _collectionModeNames; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_collectionModeNames); - } - - final Map> _valuesByMode; - @override - Map> get valuesByMode { - if (_valuesByMode is EqualUnmodifiableMapView) return _valuesByMode; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_valuesByMode); - } - - @override - String toString() { - return 'Variable.string(id: $id, name: $name, remote: $remote, key: $key, variableCollectionId: $variableCollectionId, variableCollectionName: $variableCollectionName, resolvedType: $resolvedType, description: $description, hiddenFromPublishing: $hiddenFromPublishing, scopes: $scopes, codeSyntax: $codeSyntax, collectionModeNames: $collectionModeNames, valuesByMode: $valuesByMode)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$StringVariableImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.name, name) || other.name == name) && - (identical(other.remote, remote) || other.remote == remote) && - (identical(other.key, key) || other.key == key) && - (identical(other.variableCollectionId, variableCollectionId) || - other.variableCollectionId == variableCollectionId) && - (identical(other.variableCollectionName, variableCollectionName) || - other.variableCollectionName == variableCollectionName) && - (identical(other.resolvedType, resolvedType) || - other.resolvedType == resolvedType) && - (identical(other.description, description) || - other.description == description) && - (identical(other.hiddenFromPublishing, hiddenFromPublishing) || - other.hiddenFromPublishing == hiddenFromPublishing) && - const DeepCollectionEquality().equals(other._scopes, _scopes) && - const DeepCollectionEquality() - .equals(other._codeSyntax, _codeSyntax) && - const DeepCollectionEquality() - .equals(other._collectionModeNames, _collectionModeNames) && - const DeepCollectionEquality() - .equals(other._valuesByMode, _valuesByMode)); - } - - @override - int get hashCode => Object.hash( - runtimeType, - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - const DeepCollectionEquality().hash(_scopes), - const DeepCollectionEquality().hash(_codeSyntax), - const DeepCollectionEquality().hash(_collectionModeNames), - const DeepCollectionEquality().hash(_valuesByMode)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$StringVariableImplCopyWith<_$StringVariableImpl> get copyWith => - __$$StringVariableImplCopyWithImpl<_$StringVariableImpl>( - this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - boolean, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - float, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - color, - required TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode) - string, - }) { - return string( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult? Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - }) { - return string?.call( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - boolean, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - float, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - color, - TResult Function( - String id, - String name, - bool remote, - String key, - String variableCollectionId, - String variableCollectionName, - String resolvedType, - String description, - bool hiddenFromPublishing, - List scopes, - Map codeSyntax, - Map collectionModeNames, - Map> valuesByMode)? - string, - required TResult orElse(), - }) { - if (string != null) { - return string( - id, - name, - remote, - key, - variableCollectionId, - variableCollectionName, - resolvedType, - description, - hiddenFromPublishing, - scopes, - codeSyntax, - collectionModeNames, - valuesByMode); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(BooleanVariable value) boolean, - required TResult Function(FloatVariable value) float, - required TResult Function(ColorVariable value) color, - required TResult Function(StringVariable value) string, - }) { - return string(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(BooleanVariable value)? boolean, - TResult? Function(FloatVariable value)? float, - TResult? Function(ColorVariable value)? color, - TResult? Function(StringVariable value)? string, - }) { - return string?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(BooleanVariable value)? boolean, - TResult Function(FloatVariable value)? float, - TResult Function(ColorVariable value)? color, - TResult Function(StringVariable value)? string, - required TResult orElse(), - }) { - if (string != null) { - return string(this); - } - return orElse(); - } -} - -abstract class StringVariable implements Variable { - factory StringVariable( - {required final String id, - required final String name, - required final bool remote, - required final String key, - required final String variableCollectionId, - required final String variableCollectionName, - required final String resolvedType, - required final String description, - required final bool hiddenFromPublishing, - required final List scopes, - required final Map codeSyntax, - required final Map collectionModeNames, - required final Map> valuesByMode}) = - _$StringVariableImpl; - - @override - String get id; - @override - String get name; - @override - bool get remote; - @override - String get key; - @override - String get variableCollectionId; - @override - String get variableCollectionName; - @override - String get resolvedType; - @override - String get description; - @override - bool get hiddenFromPublishing; - @override - List get scopes; - @override - Map get codeSyntax; - @override - Map get collectionModeNames; - @override - Map> get valuesByMode; - @override - @JsonKey(ignore: true) - _$$StringVariableImplCopyWith<_$StringVariableImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/src/domain/providers/config_providers.dart b/lib/src/domain/providers/config_providers.dart new file mode 100644 index 00000000..989a0589 --- /dev/null +++ b/lib/src/domain/providers/config_providers.dart @@ -0,0 +1,15 @@ +import 'dart:io'; + +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/repositories/config_repository.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Parses and returns a [Config] from a YAML file. +/// +/// You can pass a filepath to the file you want to read from. If you don't pass +/// a filepath, the default `./figmage.yaml` will be used. +final configProvider = + FutureProvider.autoDispose.family((ref, path) { + final repo = ref.watch(configRepositoryProvider); + return repo.readConfigFromFile(file: path != null ? File(path) : null); +}); diff --git a/lib/src/domain/providers/design_token_providers.dart b/lib/src/domain/providers/design_token_providers.dart new file mode 100644 index 00000000..ff7a73f9 --- /dev/null +++ b/lib/src/domain/providers/design_token_providers.dart @@ -0,0 +1,124 @@ +import 'package:figmage/src/domain/models/design_token.dart'; +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/models/style/design_style.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; +import 'package:figmage/src/domain/models/tokens_by_file_type/tokens_by_type.dart'; +import 'package:figmage/src/domain/models/variable/variable.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/repositories/styles_repository.dart'; +import 'package:figmage/src/domain/repositories/variables_repository.dart'; +import 'package:figmage/src/domain/util/token_filter_x.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Filters all tokens by file type. +final filteredTokensProvider = + FutureProvider.family((ref, settings) async { + try { + await ref.watch(variablesProvider(settings).future); + } catch (_) {} + final variables = ref.watch(variablesProvider(settings)).valueOrNull ?? []; + + try { + await ref.watch(stylesProvider(settings).future); + } catch (_) {} + final styles = ref.watch(stylesProvider(settings)).valueOrNull ?? []; + + final allTokens = [...variables, ...styles]; + if (allTokens.isEmpty) { + throw ArgumentError.value( + allTokens, + "Tokens", + "Neither styles nor variables could be obtained from file " + "${settings.fileId} ", + ); + } + return TokensByType( + colorTokens: allTokens + .whereType>() + .filterByFrom(settings.config.colors), + typographyTokens: allTokens + .whereType>() + .filterByFrom(settings.config.typography), + numberTokens: allTokens + .whereType>() + .filterByFrom(settings.config.numbers), + stringTokens: allTokens + .whereType>() + .filterByFrom(settings.config.strings), + boolTokens: allTokens + .whereType>() + .filterByFrom(settings.config.bools), + ); +}); + +/// Provides a Iterable of all variables obtained from the file in +/// [FigmageSettings]. +/// +/// This provider doesn't filter for anything yet. +final variablesProvider = + FutureProvider.family, FigmageSettings>( + (ref, settings) async { + final logger = ref.watch(loggerProvider); + final repo = ref.watch(variablesRepositoryProvider); + final varProgress = logger.progress("Fetching all variables..."); + try { + final variables = await repo.getVariables( + fileId: settings.fileId, + token: settings.token, + ); + switch (variables) { + case []: + varProgress.fail("No variables found"); + throw ArgumentError.value( + variables, + "variables", + "No variables found in file ${settings.fileId}", + ); + case [...]: + varProgress.complete("Found ${variables.length} variables"); + return variables; + } + } on VariablesException catch (e) { + varProgress.fail("Failed to fetch variables: ${e.message}"); + rethrow; + } catch (e) { + varProgress.fail("Failed to fetch variables for unknown reason ($e)"); + rethrow; + } +}); + +/// Provides a Iterable of all styles obtained from the file in +/// [FigmageSettings]. +/// +/// This provider doesn't filter for anything yet. +final stylesProvider = + FutureProvider.family, FigmageSettings>( + (ref, settings) async { + final logger = ref.watch(loggerProvider); + final repo = ref.watch(stylesRepositoryProvider); + final stylesProgress = logger.progress("Fetching all styles..."); + try { + final styles = await repo.getStyles( + fileId: settings.fileId, + token: settings.token, + ); + switch (styles) { + case []: + stylesProgress.fail("No styles found"); + throw ArgumentError.value( + styles, + "styles", + "No styles found in file ${settings.fileId}", + ); + case [...]: + stylesProgress.complete("Found ${styles.length} variables"); + return styles; + } + } on StylesException catch (e) { + stylesProgress.fail("Failed to fetch styles: ${e.message}"); + rethrow; + } catch (e) { + stylesProgress.fail("Failed to fetch styles for unknown reason: $e"); + rethrow; + } +}); diff --git a/lib/src/domain/providers/figmage_package_generator_providers.dart b/lib/src/domain/providers/figmage_package_generator_providers.dart new file mode 100644 index 00000000..ce9f37de --- /dev/null +++ b/lib/src/domain/providers/figmage_package_generator_providers.dart @@ -0,0 +1,63 @@ +import 'dart:io'; + +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/providers/design_token_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage_package_generator/figmage_package_generator.dart'; +import 'package:path/path.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Provides the [FigmagePackageGenerator] instance. +final figmagePackageGeneratorProvider = + Provider((ref) => const FigmagePackageGenerator()); + +/// Generates a package with the [FigmagePackageGenerator] and returns +/// the generated files. +final generatedPackageProvider = + FutureProvider.family, FigmageSettings>( + (ref, settings) async { + final tokensByFileType = + await ref.watch(filteredTokensProvider(settings).future); + final logger = ref.watch(loggerProvider); + + final packageGenerator = ref.watch(figmagePackageGeneratorProvider); + + final generateColors = settings.config.colors.generate && + tokensByFileType.colorTokens.isNotEmpty; + final generateTypography = settings.config.typography.generate && + tokensByFileType.typographyTokens.isNotEmpty; + final generateNumbers = settings.config.numbers.generate && + tokensByFileType.numberTokens.isNotEmpty; + final dir = Directory(settings.path); + if (basename(settings.path) != settings.config.packageName) { + logger.warn( + "The package name ${settings.config.packageName} does not match the " + "directory name ${basename(dir.path)}}."); + } + final packageProgress = + logger.progress("Generating package in ${settings.path}..."); + + try { + final files = await packageGenerator.generate( + projectName: settings.config.packageName, + dir: dir, + description: settings.config.packageDescription, + generateColors: generateColors, + generateTypography: generateTypography, + generateNumbers: generateNumbers, + // TODO(tim): support better + generatePaddings: generateNumbers, + generateSpacers: generateNumbers, + // TODO(tim): support at all + generateStrings: false, + generateBools: false, + generateRadii: false, + ); + packageProgress.complete("Generated package at ${settings.path} with " + "${files.length} files"); + return files; + } catch (e) { + packageProgress.fail("Failed to generate package: $e"); + rethrow; + } +}); diff --git a/lib/src/domain/providers/file_writer_providers.dart b/lib/src/domain/providers/file_writer_providers.dart new file mode 100644 index 00000000..e5be4d65 --- /dev/null +++ b/lib/src/domain/providers/file_writer_providers.dart @@ -0,0 +1,22 @@ +import 'dart:io'; + +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/repositories/file_writer_repository.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Writes the generated code to files and returns the list of files written. +final fileWriterProvider = + FutureProvider.family, Map>( + (ref, codeByFiles) async { + final repo = ref.watch(fileWriterRepositoryProvider); + final logger = ref.watch(loggerProvider); + final progress = logger.progress("Writing files..."); + try { + final files = repo.writeFiles(codeByFiles: codeByFiles); + progress.complete("Wrote ${files.length} files"); + return files; + } catch (_) { + progress.fail("Failed to write files"); + rethrow; + } +}); diff --git a/lib/src/domain/providers/generator_providers.dart b/lib/src/domain/providers/generator_providers.dart new file mode 100644 index 00000000..80e33b4f --- /dev/null +++ b/lib/src/domain/providers/generator_providers.dart @@ -0,0 +1,114 @@ +import 'dart:io'; + +import 'package:code_builder/code_builder.dart'; +import 'package:figmage/src/data/generators/color_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/number_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/padding_generator.dart'; +import 'package:figmage/src/data/generators/spacer_generator.dart'; +import 'package:figmage/src/data/generators/text_style_theme_extension_generator.dart'; +import 'package:figmage/src/domain/generators/theme_class_generator.dart'; +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/models/tokens_by_file_type/tokens_by_type.dart'; +import 'package:figmage/src/domain/providers/design_token_providers.dart'; +import 'package:figmage/src/domain/providers/figmage_package_generator_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/util/token_filter_x.dart'; +import 'package:figmage_package_generator/figmage_package_generator.dart'; +import 'package:path/path.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Provides a [ThemeClassGenerator] based on the file type, variables and +/// settings, if there is a supported generator. +final generatorsProvider = + FutureProvider.family, FigmageSettings>( + (ref, settings) async { + final logger = ref.watch(loggerProvider); + final tokensByType = + await ref.watch(filteredTokensProvider(settings).future); + final files = await ref.watch(generatedPackageProvider(settings).future); + + final typesByFile = { + for (final file in files) + if (file.tokenFileType case final type?) file: type, + }; + + final progress = logger.progress( + "Generating theme classes for ${typesByFile.length} files...", + ); + + final generatorsByFile = { + for (final MapEntry(key: file, value: type) in typesByFile.entries) + file: switch ((type, tokensByType)) { + ( + TokenFileType.color, + TokensByType(colorTokens: Iterable(isEmpty: false)), + ) => + ColorThemeExtensionGenerator( + className: type.className, + valuesByNameByMode: tokensByType.colorTokens.valuesByNameByMode, + ), + ( + TokenFileType.typography, + TokensByType(typographyTokens: Iterable(isEmpty: false)), + ) => + TextStyleThemeExtensionGenerator( + className: type.className, + valuesByNameByMode: + tokensByType.typographyTokens.valuesByNameByMode, + ), + ( + TokenFileType.numbers, + TokensByType(numberTokens: Iterable(isEmpty: false)), + ) => + NumberThemeExtensionGenerator( + className: type.className, + valuesByNameByMode: tokensByType.numberTokens.valuesByNameByMode, + ), + ( + TokenFileType.spacers, + TokensByType(numberTokens: Iterable(isEmpty: false)), + ) => + SpacerGenerator( + className: type.className, + numberReference: refer( + TokenFileType.numbers.className, + TokenFileType.numbers.filename, + ), + valueNames: tokensByType.numberTokens.map((t) => t.name), + ), + ( + TokenFileType.paddings, + TokensByType(numberTokens: Iterable(isEmpty: false)), + ) => + PaddingGenerator( + className: type.className, + numberReference: refer( + TokenFileType.numbers.className, + TokenFileType.numbers.filename, + ), + valueNames: tokensByType.numberTokens.map((t) => t.name), + ), + (TokenFileType.radii, _) => null, + (TokenFileType.strings, _) => null, + (TokenFileType.bools, _) => null, + _ => null + }, + }; + + final validGenerators = { + for (final MapEntry(key: file, value: generator) + in generatorsByFile.entries) + if (generator != null) file: generator, + }; + progress.complete( + "Generated ${validGenerators.length} theme classes from tokens.", + ); + return validGenerators; + }, +); + +extension on File { + TokenFileType? get tokenFileType => TokenFileType.tryFromFilename( + basename(path), + ); +} diff --git a/lib/src/domain/providers/logger_providers.dart b/lib/src/domain/providers/logger_providers.dart new file mode 100644 index 00000000..217444ee --- /dev/null +++ b/lib/src/domain/providers/logger_providers.dart @@ -0,0 +1,5 @@ +import 'package:mason_logger/mason_logger.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Provides the current [Logger] for the app. +final loggerProvider = Provider((ref) => Logger()); diff --git a/lib/src/domain/providers/post_generation_providers.dart b/lib/src/domain/providers/post_generation_providers.dart new file mode 100644 index 00000000..1e6d9566 --- /dev/null +++ b/lib/src/domain/providers/post_generation_providers.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/repositories/post_generation_repository.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Runs maintenance tasks on the generated code using +/// [PostGenerationRepository]. +/// +/// Returns the list of files after maintenance tasks have been run. +final postGenerationTasksProvider = FutureProvider.autoDispose + .family, Iterable>((ref, files) async { + final logger = ref.watch(loggerProvider); + final repo = ref.watch(postGenerationRepositoryProvider); + final progress = logger.progress("Running post generation tasks..."); + try { + final result = await repo.runMaintenanceTasks(files, progress: progress); + progress.complete("Ran post generation tasks."); + return result; + } catch (_) { + progress.fail("Failed to run post generation tasks"); + rethrow; + } +}); diff --git a/lib/src/domain/providers/pub_updater_providers.dart b/lib/src/domain/providers/pub_updater_providers.dart new file mode 100644 index 00000000..b036bf2f --- /dev/null +++ b/lib/src/domain/providers/pub_updater_providers.dart @@ -0,0 +1,5 @@ +import 'package:pub_updater/pub_updater.dart'; +import 'package:riverpod/riverpod.dart'; + +/// Provides the [PubUpdater] instance. +final pubUpdaterProvider = Provider((ref) => PubUpdater()); diff --git a/lib/src/domain/repositories/config_repository.dart b/lib/src/domain/repositories/config_repository.dart index 0412e990..b03da075 100644 --- a/lib/src/domain/repositories/config_repository.dart +++ b/lib/src/domain/repositories/config_repository.dart @@ -1,7 +1,13 @@ import 'dart:async'; import 'dart:io'; +import 'package:figmage/src/data/repositories/yaml_config_repository.dart'; import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:riverpod/riverpod.dart'; + +/// A provider for a [ConfigRepository] that reads a configuration file. +final configRepositoryProvider = + Provider(YamlConfigRepository.new); /// A repository that can read a configuration file and return a [Config]. /// diff --git a/lib/src/domain/repositories/file_writer_repository.dart b/lib/src/domain/repositories/file_writer_repository.dart new file mode 100644 index 00000000..34c8ade7 --- /dev/null +++ b/lib/src/domain/repositories/file_writer_repository.dart @@ -0,0 +1,29 @@ +import 'dart:io'; + +import 'package:figmage/src/data/repositories/dart_code_file_writer_repository.dart'; +import 'package:riverpod/riverpod.dart'; + +/// A provider for a [FileWriterRepository] that writes code to files. +final fileWriterRepositoryProvider = + Provider((ref) => DartCodeFileWriterRepository()); + +/// A repository that can write a collection of files to disk. +abstract interface class FileWriterRepository { + /// Writes a collection of files to disk. + /// + /// [codeByFiles] includes the files to be written to as keys, and the code + /// that should be written to them as values. + /// + /// If [append] is false (default), the files get overwritten, if it is true, + /// the code gets appended to the files. + /// + /// By default, all files in [codeByFiles] get created if they don't exist. + /// If you don't want this, set [createIfNotExists] to false. + /// + /// Returns the list of successfully generated files. + Iterable writeFiles({ + required Map codeByFiles, + bool append = false, + bool createIfNotExists = true, + }); +} diff --git a/lib/src/domain/repositories/post_generation_repository.dart b/lib/src/domain/repositories/post_generation_repository.dart new file mode 100644 index 00000000..4e9c2dbe --- /dev/null +++ b/lib/src/domain/repositories/post_generation_repository.dart @@ -0,0 +1,27 @@ +import 'dart:io'; + +import 'package:figmage/src/data/repositories/dart_post_generation_repository.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:riverpod/riverpod.dart'; + +/// A provider for a [PostGenerationRepository] that runs maintenance tasks on +/// the generated code. +final postGenerationRepositoryProvider = Provider( + (_) => const DartPostGenerationRepository(), +); + +/// A repository that can run maintenance tasks on the generated code after +/// it has been generated. +abstract interface class PostGenerationRepository { + /// Runs maintenance tasks on the generated code. + /// + /// Parameters: + /// - [files]: The list of files to run maintenance tasks on. + /// - [progress]: The progress to use for updating (optional). + /// + /// Returns the list of files after maintenance tasks have been run. + Future> runMaintenanceTasks( + Iterable files, { + Progress? progress, + }); +} diff --git a/lib/src/domain/repositories/styles_repository.dart b/lib/src/domain/repositories/styles_repository.dart index 3d31eff4..30702966 100644 --- a/lib/src/domain/repositories/styles_repository.dart +++ b/lib/src/domain/repositories/styles_repository.dart @@ -1,4 +1,10 @@ -import 'package:figmage/src/domain/models/style.dart'; +import 'package:figmage/src/data/repositories/figma_styles_repository.dart'; +import 'package:figmage/src/domain/models/style/design_style.dart'; +import 'package:riverpod/riverpod.dart'; + +/// A provider for a [StylesRepository] that fetches styles from Figma. +final stylesRepositoryProvider = + Provider((ref) => FigmaStylesRepository()); /// {@template styles_repository} /// This repository is responsible for fetching styles. @@ -6,8 +12,44 @@ import 'package:figmage/src/domain/models/style.dart'; abstract interface class StylesRepository { /// Get all styles from the figma file with [fileId] using the personal /// access [token]. - Future> getStyles({ + Future>> getStyles({ required String fileId, required String token, }); } + +/// {@template styles_exception} +/// Superclass for all styles repository exceptions. +/// {@endtemplate} +sealed class StylesException implements Exception { + /// {@macro styles_exception} + const StylesException(); + + /// The message of the exception. + String get message; +} + +/// {@template unauthorized_styles_exception} +/// Exception thrown when the user is not authorized to access the styles. +/// {@endtemplate} +class UnauthorizedStylesException extends StylesException { + /// {@macro unauthorized_styles_exception} + const UnauthorizedStylesException(); + + @override + String get message => 'Unauthorized. Make sure you have a valid access token ' + 'that can access the file.'; +} + +/// {@template unknown_styles_exception} +/// An exception that is thrown during variables fetching, that can't be +/// classified as any other exception. +/// {@endtemplate} +class UnknownStylesException extends StylesException { + /// {@macro unknown_styles_exception} + const UnknownStylesException(String? message) + : message = message ?? 'Unknown error happened during styles fetching.'; + + @override + final String message; +} diff --git a/lib/src/domain/repositories/variables_repository.dart b/lib/src/domain/repositories/variables_repository.dart index e58bee91..65dd4ab1 100644 --- a/lib/src/domain/repositories/variables_repository.dart +++ b/lib/src/domain/repositories/variables_repository.dart @@ -1,9 +1,15 @@ +import 'package:figmage/src/data/repositories/figma_variables_repository.dart'; import 'package:figmage/src/domain/models/variable/variable.dart'; +import 'package:riverpod/riverpod.dart'; /// A map of variable values organized by collection, mode, and variable name. typedef VariableValuesByIdByModeByCollection = Map>>; +/// A provider for a [VariablesRepository] that fetches variables from Figma. +final variablesRepositoryProvider = + Provider((ref) => FigmaVariablesRepository()); + /// {@template variables_repository} /// A repository for fetching variable values from a Figma file. /// {@endtemplate} @@ -17,7 +23,7 @@ abstract interface class VariablesRepository { /// /// Returns a list of [Variable] instances representing the variable values in /// the Figma file. - Future> getVariables({ + Future>> getVariables({ required String fileId, required String token, }); @@ -51,8 +57,48 @@ abstract interface class VariablesRepository { /// ); /// ``` VariableValuesByIdByModeByCollection - createValueModeMap({ - required List variables, + createValueModeMap>({ + required List> variables, bool useNames = true, }); } + +/// {@template variables_exception} +/// Superclass for all styles repository exceptions. +/// {@endtemplate} +sealed class VariablesException implements Exception { + /// {@macro variables_exception} + const VariablesException(); + + /// The message of the exception. + String get message; +} + +/// {@template unauthorized_variables_exception} +/// Exception thrown when the user is not authorized to access the styles. +/// {@endtemplate} +class UnauthorizedVariablesException extends VariablesException { + /// {@macro unauthorized_variables_exception} + const UnauthorizedVariablesException(String? message) + : message = message ?? + 'Unauthorized. Make sure you have a valid access token ' + 'that can access the file and that you are a Figma Enterprise. ' + 'team member'; + + @override + final String message; +} + +/// {@template unknown_variables_exception} +/// An exception that is thrown during variables fetching, that can't be +/// classified as any other exception. +/// {@endtemplate} +class UnknownVariablesException extends VariablesException { + /// {@macro unknown_variables_exception} + const UnknownVariablesException(String? message) + : message = + message ?? 'Unknown error happened during variables fetching.'; + + @override + final String message; +} diff --git a/lib/src/domain/util/token_filter_x.dart b/lib/src/domain/util/token_filter_x.dart new file mode 100644 index 00000000..6530b8b9 --- /dev/null +++ b/lib/src/domain/util/token_filter_x.dart @@ -0,0 +1,35 @@ +import 'package:collection/collection.dart'; +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/models/design_token.dart'; +import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; + +/// An extension fo filter variables +extension TokenFilterX on Iterable> { + /// Filters the variables by the `settings.from` list + Iterable> filterByFrom(GenerationSettings settings) => where( + (variable) => + settings.from.isEmpty || + settings.from.any(variable.fullName.startsWith), + ); + + /// Turns the variables into a map of values by name by mode + /// + // TODO(tim): this is in the repo I know but I didn't get how it works + Map> get valuesByNameByMode { + final sorted = sortedBy((element) => element.name); + final allModes = expand((variable) => variable.valuesByMode.keys) + .toSet() + .sortedBy((mode) => mode); + return { + for (final mode in allModes) + mode: { + for (final variable in sorted) + if (variable.valuesByMode.containsKey(mode)) + variable.name: switch (variable.valuesByMode[mode]) { + final AliasOr alias => alias.resolveValue, + _ => throw TypeError(), + }, + }, + }; + } +} diff --git a/melos.yaml b/melos.yaml index dd6710bf..39e8678e 100644 --- a/melos.yaml +++ b/melos.yaml @@ -7,7 +7,9 @@ packages: command: bootstrap: hooks: - pre: dart pub global activate coverage + pre: | + dart pub global activate coverage + dart pub global activate full_coverage version: updateGitTagRefs: true @@ -38,6 +40,7 @@ scripts: coverage:select: run: | + dart pub global run full_coverage --ignore '*}.dart' dart test --coverage=coverage dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info -c --report-on=lib rm -rf -f coverage/test/ diff --git a/melos_figmage.iml b/melos_figmage.iml deleted file mode 100644 index 389d07a1..00000000 --- a/melos_figmage.iml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/melos_figmage_workspace.iml b/melos_figmage_workspace.iml deleted file mode 100644 index 1c75bf0b..00000000 --- a/melos_figmage_workspace.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/packages/figma_variables_api/coverage/lcov.info b/packages/figma_variables_api/coverage/lcov.info index 59f403a5..ec43978e 100644 --- a/packages/figma_variables_api/coverage/lcov.info +++ b/packages/figma_variables_api/coverage/lcov.info @@ -1,25 +1,66 @@ -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable/variable_dto.dart -DA:11,2 -DA:25,2 -DA:26,2 -DA:40,1 -DA:41,1 -DA:42,1 -DA:43,1 -DA:44,1 -DA:45,1 -DA:46,1 -DA:47,1 -DA:48,1 -DA:49,1 -DA:50,1 -DA:51,1 -DA:52,1 -DA:55,4 -LF:17 -LH:17 +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/client.dart +DA:31,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:63,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:75,0 +DA:79,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:85,0 +DA:90,0 +DA:98,0 +DA:99,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:107,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,0 +DA:124,0 +DA:125,0 +DA:126,0 +DA:132,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:138,0 +DA:139,0 +DA:140,0 +DA:141,0 +DA:142,0 +DA:145,0 +DA:146,0 +DA:149,0 +DA:151,0 +DA:154,0 +DA:155,0 +DA:158,0 +DA:159,0 +DA:161,0 +DA:168,0 +DA:176,1 +LF:58 +LH:1 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable/variable_dto.g.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable/variable_dto.g.dart DA:55,2 DA:59,0 DA:60,0 @@ -97,7 +138,145 @@ DA:215,2 LF:74 LH:51 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode_value/variable_mode_value_dto.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable/variable_dto.dart +DA:11,2 +DA:25,2 +DA:26,2 +DA:40,1 +DA:41,1 +DA:42,1 +DA:43,1 +DA:44,1 +DA:45,1 +DA:46,1 +DA:47,1 +DA:48,1 +DA:49,1 +DA:50,1 +DA:51,1 +DA:52,1 +DA:55,4 +LF:17 +LH:17 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_collection/variable_collection_dto.g.dart +DA:47,1 +DA:51,0 +DA:53,0 +DA:55,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:61,0 +DA:62,0 +DA:64,0 +DA:66,0 +DA:68,0 +DA:69,0 +DA:71,0 +DA:73,0 +DA:75,0 +DA:77,0 +DA:79,1 +DA:97,1 +DA:99,1 +DA:100,2 +DA:103,1 +DA:104,2 +DA:107,1 +DA:108,0 +DA:111,1 +DA:112,2 +DA:115,1 +DA:116,2 +DA:119,1 +DA:120,2 +DA:124,1 +DA:126,2 +DA:130,1 +DA:131,2 +DA:141,1 +DA:142,1 +DA:149,2 +DA:151,2 +DA:152,2 +DA:153,2 +DA:154,2 +DA:155,2 +DA:156,2 +DA:157,6 +DA:158,2 +DA:159,2 +DA:160,2 +DA:161,2 +DA:162,4 +DA:163,2 +DA:166,2 +DA:168,2 +DA:169,2 +DA:170,2 +DA:171,2 +DA:172,2 +DA:173,10 +DA:174,2 +DA:175,2 +DA:176,2 +LF:61 +LH:44 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_collection/variable_collection_dto.dart +DA:11,2 +DA:22,2 +DA:23,2 +DA:33,1 +DA:34,1 +DA:35,1 +DA:36,1 +DA:37,1 +DA:38,1 +DA:39,1 +DA:40,1 +DA:41,1 +DA:42,1 +DA:45,4 +LF:14 +LH:14 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode/variable_mode_dto.g.dart +DA:28,0 +DA:32,0 +DA:33,0 +DA:35,0 +DA:36,0 +DA:38,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:55,0 +DA:56,0 +DA:66,0 +DA:73,2 +DA:74,2 +DA:75,2 +DA:76,2 +DA:79,2 +DA:80,2 +DA:81,2 +DA:82,2 +LF:20 +LH:8 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode/variable_mode_dto.dart +DA:10,2 +DA:15,2 +DA:16,2 +DA:21,1 +DA:22,3 +DA:24,4 +LF:6 +LH:6 +end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode_value/variable_mode_value_dto.dart DA:7,3 DA:9,3 DA:10,3 @@ -153,7 +332,7 @@ DA:121,3 LF:52 LH:52 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode_value/variable_mode_value_dto.g.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode_value/variable_mode_value_dto.g.dart DA:9,0 DA:11,0 DA:12,0 @@ -195,89 +374,17 @@ DA:74,3 LF:38 LH:20 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/client.dart -DA:31,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:75,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:90,0 -DA:98,0 -DA:99,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:107,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:132,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:145,0 -DA:146,0 -DA:149,0 -DA:151,0 -DA:154,0 -DA:155,0 -DA:158,0 -DA:159,0 -DA:161,0 -DA:168,0 -DA:176,1 -LF:58 -LH:1 -end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/query.dart -DA:6,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:87,0 -LF:16 -LH:0 +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_response/variables_response_dto.dart +DA:12,2 +DA:18,1 +DA:19,1 +DA:30,1 +DA:31,4 +DA:33,2 +LF:6 +LH:6 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_response/variables_response_dto.g.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variable_response/variables_response_dto.g.dart DA:32,0 DA:36,0 DA:37,0 @@ -308,134 +415,7 @@ DA:99,2 LF:27 LH:10 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_response/variables_response_dto.dart -DA:12,2 -DA:18,1 -DA:19,1 -DA:30,1 -DA:31,4 -DA:33,2 -LF:6 -LH:6 -end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_collection/variable_collection_dto.g.dart -DA:47,1 -DA:51,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:59,0 -DA:61,0 -DA:62,0 -DA:64,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:73,0 -DA:75,0 -DA:77,0 -DA:79,1 -DA:97,1 -DA:99,1 -DA:100,2 -DA:103,1 -DA:104,2 -DA:107,1 -DA:108,0 -DA:111,1 -DA:112,2 -DA:115,1 -DA:116,2 -DA:119,1 -DA:120,2 -DA:124,1 -DA:126,2 -DA:130,1 -DA:131,2 -DA:141,1 -DA:142,1 -DA:149,2 -DA:151,2 -DA:152,2 -DA:153,2 -DA:154,2 -DA:155,2 -DA:156,2 -DA:157,6 -DA:158,2 -DA:159,2 -DA:160,2 -DA:161,2 -DA:162,4 -DA:163,2 -DA:166,2 -DA:168,2 -DA:169,2 -DA:170,2 -DA:171,2 -DA:172,2 -DA:173,10 -DA:174,2 -DA:175,2 -DA:176,2 -LF:61 -LH:44 -end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_collection/variable_collection_dto.dart -DA:11,2 -DA:22,2 -DA:23,2 -DA:33,1 -DA:34,1 -DA:35,1 -DA:36,1 -DA:37,1 -DA:38,1 -DA:39,1 -DA:40,1 -DA:41,1 -DA:42,1 -DA:45,4 -LF:14 -LH:14 -end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode/variable_mode_dto.g.dart -DA:28,0 -DA:32,0 -DA:33,0 -DA:35,0 -DA:36,0 -DA:38,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:55,0 -DA:56,0 -DA:66,0 -DA:73,2 -DA:74,2 -DA:75,2 -DA:76,2 -DA:79,2 -DA:80,2 -DA:81,2 -DA:82,2 -LF:20 -LH:8 -end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variable_mode/variable_mode_dto.dart -DA:10,2 -DA:15,2 -DA:16,2 -DA:21,1 -DA:22,3 -DA:24,4 -LF:6 -LH:6 -end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variables_meta/variables_meta_dto.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variables_meta/variables_meta_dto.dart DA:12,2 DA:17,1 DA:18,1 @@ -445,7 +425,7 @@ DA:25,2 LF:6 LH:4 end_of_record -SF:/home/runner/work/figmage/figmage/packages/figma_variables_api/lib/src/models/dto/variables_meta/variables_meta_dto.g.dart +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/models/dto/variables_meta/variables_meta_dto.g.dart DA:29,0 DA:33,0 DA:35,0 @@ -472,3 +452,23 @@ DA:95,5 LF:23 LH:11 end_of_record +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figma_variables_api/lib/src/query.dart +DA:6,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:87,0 +LF:16 +LH:0 +end_of_record diff --git a/packages/figma_variables_api/lib/src/client.dart b/packages/figma_variables_api/lib/src/client.dart index 4f357dad..e6594051 100644 --- a/packages/figma_variables_api/lib/src/client.dart +++ b/packages/figma_variables_api/lib/src/client.dart @@ -60,7 +60,7 @@ class FigmaClient { if (res.statusCode >= 200 && res.statusCode < 300) { return jsonDecode(res.body); } else { - throw FigmaError(code: res.statusCode, message: res.body); + throw FigmaException(code: res.statusCode, message: res.body); } }); } @@ -82,7 +82,7 @@ class FigmaClient { if (res.statusCode >= 200 && res.statusCode < 300) { return jsonDecode(res.body); } else { - throw FigmaError(code: res.statusCode, message: res.body); + throw FigmaException(code: res.statusCode, message: res.body); } }); } @@ -172,8 +172,8 @@ class _Response { } /// An error from the [Figma API docs](https://www.figma.com/developers/api#errors). -class FigmaError extends Error { - FigmaError({this.code, this.message}); +class FigmaException implements Exception { + const FigmaException({this.code, this.message}); /// HTTP status code. final int? code; diff --git a/packages/figma_variables_api/test/full_coverage_test.dart b/packages/figma_variables_api/test/full_coverage_test.dart new file mode 100644 index 00000000..fd19b84f --- /dev/null +++ b/packages/figma_variables_api/test/full_coverage_test.dart @@ -0,0 +1,13 @@ +// ignore_for_file: unused_import +import 'package:figma_variables_api/figma_variables_api.dart'; +import 'package:figma_variables_api/src/client.dart'; +import 'package:figma_variables_api/src/models.dart'; +import 'package:figma_variables_api/src/models/dto/variable/variable_dto.dart'; +import 'package:figma_variables_api/src/models/dto/variable_collection/variable_collection_dto.dart'; +import 'package:figma_variables_api/src/models/dto/variable_mode/variable_mode_dto.dart'; +import 'package:figma_variables_api/src/models/dto/variable_mode_value/variable_mode_value_dto.dart'; +import 'package:figma_variables_api/src/models/dto/variable_response/variables_response_dto.dart'; +import 'package:figma_variables_api/src/models/dto/variables_meta/variables_meta_dto.dart'; +import 'package:figma_variables_api/src/query.dart'; + +void main() {} diff --git a/packages/figma_variables_api/test/src/client_test.dart b/packages/figma_variables_api/test/src/client_test.dart index a8452614..199a45b6 100644 --- a/packages/figma_variables_api/test/src/client_test.dart +++ b/packages/figma_variables_api/test/src/client_test.dart @@ -41,7 +41,7 @@ void main() { () async { final client = MockFigmaClient(); when(client.getLocalVariables('fileIdNotExisting')).thenThrow( - FigmaError( + FigmaException( code: 404, message: 'Not found', ), @@ -50,7 +50,7 @@ void main() { () async { await fetchLocaleVariables(client, 'fileIdNotExisting'); }, - throwsA(isA()), + throwsA(isA()), ); }); }); diff --git a/packages/figmage_package_generator/coverage/lcov.info b/packages/figmage_package_generator/coverage/lcov.info index c4a8c5ec..d152bd02 100644 --- a/packages/figmage_package_generator/coverage/lcov.info +++ b/packages/figmage_package_generator/coverage/lcov.info @@ -1,19 +1,13 @@ -SF:/home/runner/work/figmage/figmage/packages/figmage_package_generator/lib/src/figmage_package_generator.dart -DA:14,1 -DA:21,1 -DA:33,1 -DA:35,1 -DA:36,1 +SF:/Users/tim/Developer/whynotmake.it/figmage/packages/figmage_package_generator/lib/src/token_file_type.dart +DA:32,1 +DA:34,1 +DA:35,3 +DA:38,1 +DA:41,1 DA:47,1 -DA:48,2 DA:49,1 -DA:53,2 -DA:54,4 -DA:57,1 -DA:58,1 -DA:59,1 -DA:61,0 -DA:63,2 -LF:15 -LH:14 +DA:59,5 +DA:60,4 +LF:9 +LH:9 end_of_record diff --git a/packages/figmage_package_generator/lib/figmage_package_generator.dart b/packages/figmage_package_generator/lib/figmage_package_generator.dart index e0440f39..c53f70e7 100644 --- a/packages/figmage_package_generator/lib/figmage_package_generator.dart +++ b/packages/figmage_package_generator/lib/figmage_package_generator.dart @@ -2,3 +2,4 @@ library figmage_package_generator; export 'src/figmage_package_generator.dart'; +export 'src/token_file_type.dart'; diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/.gitignore b/packages/figmage_package_generator/lib/src/brick/__brick__/.gitignore similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/.gitignore rename to packages/figmage_package_generator/lib/src/brick/__brick__/.gitignore diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/CHANGELOG.md b/packages/figmage_package_generator/lib/src/brick/__brick__/CHANGELOG.md similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/CHANGELOG.md rename to packages/figmage_package_generator/lib/src/brick/__brick__/CHANGELOG.md diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/README.md b/packages/figmage_package_generator/lib/src/brick/__brick__/README.md similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/README.md rename to packages/figmage_package_generator/lib/src/brick/__brick__/README.md diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/analysis_options.yaml b/packages/figmage_package_generator/lib/src/brick/__brick__/analysis_options.yaml similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/analysis_options.yaml rename to packages/figmage_package_generator/lib/src/brick/__brick__/analysis_options.yaml diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_bools}}bools.dart{{/generate_bools}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_bools}}bools.dart{{/generate_bools}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_bools}}bools.dart{{/generate_bools}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_bools}}bools.dart{{/generate_bools}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_colors}}colors.dart{{/generate_colors}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_colors}}colors.dart{{/generate_colors}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_colors}}colors.dart{{/generate_colors}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_colors}}colors.dart{{/generate_colors}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_paddings}}paddings.dart{{/generate_paddings}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_numbers}}numbers.dart{{/generate_numbers}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_paddings}}paddings.dart{{/generate_paddings}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_numbers}}numbers.dart{{/generate_numbers}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_radii}}radii.dart{{/generate_radii}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_paddings}}paddings.dart{{/generate_paddings}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_radii}}radii.dart{{/generate_radii}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_paddings}}paddings.dart{{/generate_paddings}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_spacers}}spacers.dart{{/generate_spacers}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_radii}}radii.dart{{/generate_radii}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_spacers}}spacers.dart{{/generate_spacers}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_radii}}radii.dart{{/generate_radii}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_strings}}strings.dart{{/generate_strings}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_spacers}}spacers.dart{{/generate_spacers}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_strings}}strings.dart{{/generate_strings}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_spacers}}spacers.dart{{/generate_spacers}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_typography}}typography.dart{{/generate_typography}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_strings}}strings.dart{{/generate_strings}} similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/src/{{#generate_typography}}typography.dart{{/generate_typography}} rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_strings}}strings.dart{{/generate_strings}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_typography}}typography.dart{{/generate_typography}} b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/src/{{#generate_typography}}typography.dart{{/generate_typography}} new file mode 100644 index 00000000..e69de29b diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/{{project_name.snakeCase()}}.dart b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/{{project_name.snakeCase()}}.dart similarity index 88% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/{{project_name.snakeCase()}}.dart rename to packages/figmage_package_generator/lib/src/brick/__brick__/lib/{{project_name.snakeCase()}}.dart index fe7f4871..845d63fa 100644 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/lib/{{project_name.snakeCase()}}.dart +++ b/packages/figmage_package_generator/lib/src/brick/__brick__/lib/{{project_name.snakeCase()}}.dart @@ -3,6 +3,7 @@ library {{project_name.snakeCase()}}; {{#generate_bools}}export 'src/bools.dart';{{/generate_bools}} {{#generate_colors}}export 'src/colors.dart';{{/generate_colors}} +{{#generate_numbers}}export 'src/numbers.dart';{{/generate_numbers}} {{#generate_paddings}}export 'src/paddings.dart';{{/generate_paddings}} {{#generate_radii}}export 'src/radii.dart';{{/generate_radii}} {{#generate_spacers}}export 'src/spacers.dart';{{/generate_spacers}} diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/pubspec.yaml b/packages/figmage_package_generator/lib/src/brick/__brick__/pubspec.yaml similarity index 100% rename from packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/pubspec.yaml rename to packages/figmage_package_generator/lib/src/brick/__brick__/pubspec.yaml diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/bug_report.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 50a4c7b8..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Bug Report -about: Create a report to help us improve -title: "fix: " -labels: bug ---- - -**Description** - -A clear and concise description of what the bug is. - -**Steps To Reproduce** - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected Behavior** - -A clear and concise description of what you expected to happen. - -**Screenshots** - -If applicable, add screenshots to help explain your problem. - -**Additional Context** - -Add any other context about the problem here. diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/build.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/build.md deleted file mode 100644 index 0cf8e62c..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/build.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Build System -about: Changes that affect the build system or external dependencies -title: "build: " -labels: build ---- - -**Description** - -Describe what changes need to be done to the build system and why. - -**Requirements** - -- [ ] The build system is passing diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/chore.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/chore.md deleted file mode 100644 index 498ebfd8..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/chore.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Chore -about: Other changes that don't modify src or test files -title: "chore: " -labels: chore ---- - -**Description** - -Clearly describe what change is needed and why. If this changes code then please use another issue type. - -**Requirements** - -- [ ] No functional changes to the code diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/ci.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/ci.md deleted file mode 100644 index fa2dd9e2..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/ci.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Continuous Integration -about: Changes to the CI configuration files and scripts -title: "ci: " -labels: ci ---- - -**Description** - -Describe what changes need to be done to the ci/cd system and why. - -**Requirements** - -- [ ] The ci system is passing diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/config.yml b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index ec4bb386..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: false \ No newline at end of file diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/documentation.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/documentation.md deleted file mode 100644 index f494a4d9..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/documentation.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Documentation -about: Improve the documentation so all collaborators have a common understanding -title: "docs: " -labels: documentation ---- - -**Description** - -Clearly describe what documentation you are looking to add or improve. - -**Requirements** - -- [ ] Requirements go here diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/feature_request.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index ddd2fcca..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: Feature Request -about: A new feature to be added to the project -title: "feat: " -labels: feature ---- - -**Description** - -Clearly describe what you are looking to add. The more context the better. - -**Requirements** - -- [ ] Checklist of requirements to be fulfilled - -**Additional Context** - -Add any other context or screenshots about the feature request go here. diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/performance.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/performance.md deleted file mode 100644 index 699b8d45..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/performance.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Performance Update -about: A code change that improves performance -title: "perf: " -labels: performance ---- - -**Description** - -Clearly describe what code needs to be changed and what the performance impact is going to be. Bonus point's if you can tie this directly to user experience. - -**Requirements** - -- [ ] There is no drop in test coverage. diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/refactor.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/refactor.md deleted file mode 100644 index 1626c570..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/refactor.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Refactor -about: A code change that neither fixes a bug nor adds a feature -title: "refactor: " -labels: refactor ---- - -**Description** - -Clearly describe what needs to be refactored and why. Please provide links to related issues (bugs or upcoming features) in order to help prioritize. - -**Requirements** - -- [ ] There is no drop in test coverage. diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/revert.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/revert.md deleted file mode 100644 index 9d121dc5..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/revert.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Revert Commit -about: Reverts a previous commit -title: "revert: " -labels: revert ---- - -**Description** - -Provide a link to a PR/Commit that you are looking to revert and why. - -**Requirements** - -- [ ] Change has been reverted -- [ ] No change in test coverage has happened -- [ ] A new ticket is created for any follow on work that needs to happen diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/style.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/style.md deleted file mode 100644 index 02244a7b..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/style.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Style Changes -about: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc) -title: "style: " -labels: style ---- - -**Description** - -Clearly describe what you are looking to change and why. - -**Requirements** - -- [ ] There is no drop in test coverage. diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/test.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/test.md deleted file mode 100644 index 431a7ea7..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/ISSUE_TEMPLATE/test.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Test -about: Adding missing tests or correcting existing tests -title: "test: " -labels: test ---- - -**Description** - -List out the tests that need to be added or changed. Please also include any information as to why this was not covered in the past. - -**Requirements** - -- [ ] There is no drop in test coverage. diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/PULL_REQUEST_TEMPLATE.md b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 2f4c71d2..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,18 +0,0 @@ - - -## Description - - - -## Checklist - - -- [ ] My PR title is in the style of [conventional commits](https://www.conventionalcommits.org/) -- [ ] All public facing APIs are doccumented with [dartdoc](https://dart.dev/guides/language/effective-dart/documentation) -- [ ] I have added tests to cover my changes diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/dependabot.yaml b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/dependabot.yaml deleted file mode 100644 index 63b035cd..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/dependabot.yaml +++ /dev/null @@ -1,11 +0,0 @@ -version: 2 -enable-beta-ecosystems: true -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - - package-ecosystem: "pub" - directory: "/" - schedule: - interval: "daily" diff --git a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/workflows/main.yaml b/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/workflows/main.yaml deleted file mode 100644 index 2278e38e..00000000 --- a/packages/figmage_package_generator/lib/src/brick/__brick__/{{project_name.snakeCase()}}/{{#main}}.github{{/main}}/workflows/main.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: ci - -concurrency: - group: ${{#mustacheCase}}github.workflow{{/mustacheCase}}-${{#mustacheCase}}github.ref{{/mustacheCase}} - cancel-in-progress: true - -on: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - semantic_pull_request: - uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/semantic_pull_request.yml@v1 - - flutter-check: - name: Build Check - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: 📚 Checkout - uses: actions/checkout@v4 - - - name: 🐦 Setup Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - cache: true - - - name: Ⓜ️ Set up Melos - uses: bluefireteam/melos-action@v2 - - - name: 🧪 Run Analyze - run: melos run analyze - - - name: 📝 Run Test - run: melos run coverage - \ No newline at end of file diff --git a/packages/figmage_package_generator/lib/src/brick/brick.yaml b/packages/figmage_package_generator/lib/src/brick/brick.yaml index a91cffad..0d39b531 100644 --- a/packages/figmage_package_generator/lib/src/brick/brick.yaml +++ b/packages/figmage_package_generator/lib/src/brick/brick.yaml @@ -27,6 +27,11 @@ vars: description: Whether to generate a file for TextStyles and typography default: true prompt: Generate typography? + generate_numbers: + type: boolean + description: Whether to generate a file for numbers + default: true + prompt: Generate numbers? generate_spacers: type: boolean description: Whether to generate a file for spacers diff --git a/packages/figmage_package_generator/lib/src/brick/hooks/post_gen.dart b/packages/figmage_package_generator/lib/src/brick/hooks/post_gen.dart deleted file mode 100644 index 9cc54097..00000000 --- a/packages/figmage_package_generator/lib/src/brick/hooks/post_gen.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'dart:io'; -import 'package:mason/mason.dart'; - -Future run(HookContext context) async { - if (context.vars['main'] == true) { - final progress = context.logger.progress('Installing melos'); - await Process.run('dart', ['pub', 'global', 'activate', 'melos']); - await Process.run('melos', ['bootstrap']); - progress.complete(); - } - - // Run `flutter packages get` after generation. - final progress = context.logger.progress('Running pub get'); - await Process.run('dart', ['pub', 'get']); - await Process.run('dart', ['fix', '--apply']); - progress.complete(); - - if (context.vars['main'] == false) { - context.logger.alert( - "Make sure to run 'melos bootstrap' in your main package", - ); - } -} diff --git a/packages/figmage_package_generator/lib/src/brick/hooks/pubspec.yaml b/packages/figmage_package_generator/lib/src/brick/hooks/pubspec.yaml deleted file mode 100644 index 1aaa5fe9..00000000 --- a/packages/figmage_package_generator/lib/src/brick/hooks/pubspec.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: pubspec_hooks - -environment: - sdk: ">=3.0.0 <4.0.0" - -dependencies: - mason: ^0.1.0-dev.51 \ No newline at end of file diff --git a/packages/figmage_package_generator/lib/src/figmage_package_generator.dart b/packages/figmage_package_generator/lib/src/figmage_package_generator.dart index 899da421..f9747fd8 100644 --- a/packages/figmage_package_generator/lib/src/figmage_package_generator.dart +++ b/packages/figmage_package_generator/lib/src/figmage_package_generator.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'dart:isolate'; @@ -6,12 +7,29 @@ import 'package:mason/mason.dart'; /// The name of this package const packageName = 'figmage_package_generator'; +/// A resolver for package uris +typedef PackageUriResolver = FutureOr Function(Uri packageUri); + +/// A factory for [GeneratorTarget]s +typedef GeneratorTargetFactory = GeneratorTarget Function(Directory dir); + /// {@template figmage_package_generator} /// A generator for an empty figmage styles dart package /// {@endtemplate} class FigmagePackageGenerator { /// {@macro figmage_package_generator} - const FigmagePackageGenerator(); + /// + /// Allows to override the [packageUriResolver] for testing purposes. + const FigmagePackageGenerator({ + PackageUriResolver? packageUriResolver, + GeneratorTargetFactory? generatorTargetFactory, + }) : _packageUriResolver = packageUriResolver ?? Isolate.resolvePackageUri, + _generatorTargetFactory = + generatorTargetFactory ?? DirectoryGeneratorTarget.new; + + final PackageUriResolver _packageUriResolver; + + final GeneratorTargetFactory _generatorTargetFactory; /// Generates a figmage styles dart package. /// @@ -24,6 +42,7 @@ class FigmagePackageGenerator { required Directory dir, bool generateColors = true, bool generateTypography = true, + bool generateNumbers = true, bool generateSpacers = true, bool generatePaddings = true, bool generateRadii = true, @@ -38,13 +57,14 @@ class FigmagePackageGenerator { 'description': description, 'generate_colors': generateColors, 'generate_typography': generateTypography, + 'generate_numbers': generateNumbers, 'generate_spacers': generateSpacers, 'generate_paddings': generatePaddings, 'generate_radii': generateRadii, 'generate_strings': generateStrings, 'generate_bools': generateBools, }; - final target = DirectoryGeneratorTarget(dir); + final target = _generatorTargetFactory(dir); await generator.hooks.preGen(vars: vars); final files = await generator.generate( target, @@ -56,10 +76,24 @@ class FigmagePackageGenerator { Future _getBrick() async { final packageUri = Uri.parse("package:$packageName/src/brick/"); - final fileSystemUri = await Isolate.resolvePackageUri(packageUri); + final fileSystemUri = await _packageUriResolver(packageUri); if (fileSystemUri == null) { - throw Exception("Could not resolve package uri for package $packageName"); + throw const PackageUriException(packageName); } return Brick.path(fileSystemUri.toFilePath()); } } + +/// {@template package_uri_exception} +/// An exception thrown when the package uri could not be resolved +/// {@endtemplate} +class PackageUriException implements Exception { + /// {@macro package_uri_exception} + const PackageUriException(this.packageName); + + /// The name of the package that could not be resolved + final String packageName; + + @override + String toString() => "Could not resolve package uri for package $packageName"; +} diff --git a/packages/figmage_package_generator/lib/src/token_file_type.dart b/packages/figmage_package_generator/lib/src/token_file_type.dart new file mode 100644 index 00000000..65668ef6 --- /dev/null +++ b/packages/figmage_package_generator/lib/src/token_file_type.dart @@ -0,0 +1,62 @@ +/// The types of generated token files. +enum TokenFileType { + /// Color tokens + color("colors.dart"), + + /// Typography (text style) tokens + typography("typography.dart"), + + /// Spacers (SizedBox) tokens + numbers("numbers.dart"), + + /// Spacers (SizedBox) tokens + spacers("spacers.dart"), + + /// Paddings (EdgeInsets) tokens + paddings("paddings.dart"), + + /// Radii (BorderRadius) tokens + radii("radii.dart"), + + /// Strings tokens + strings("strings.dart"), + + /// Bools tokens + bools("bools.dart"); + + const TokenFileType(this.filename); + + /// Gets the token file type from the filename. + /// + /// Throws if the filename is invalid. + static TokenFileType fromFilename(String filename) { + try { + return TokenFileType.values.firstWhere( + (element) => element.filename == filename, + ); + } catch (_) { + throw ArgumentError.value( + filename, + "filename", + "The filename $filename is not a valid token file name.", + ); + } + } + + /// The same as [fromFilename], but returns null if the filename is invalid. + static TokenFileType? tryFromFilename(String value) { + try { + return TokenFileType.fromFilename(value); + } catch (_) { + return null; + } + } + + /// The name of the generated file for this token. + final String filename; + + /// Gets the class name for the file type. + String get className => switch (filename.split(".").first.trim()) { + final name => name[0].toUpperCase() + name.substring(1), + }; +} diff --git a/packages/figmage_package_generator/test/full_coverage_test.dart b/packages/figmage_package_generator/test/full_coverage_test.dart new file mode 100644 index 00000000..673bb5ea --- /dev/null +++ b/packages/figmage_package_generator/test/full_coverage_test.dart @@ -0,0 +1,6 @@ +// ignore_for_file: unused_import +import 'package:figmage_package_generator/figmage_package_generator.dart'; +import 'package:figmage_package_generator/src/figmage_package_generator.dart'; +import 'package:figmage_package_generator/src/token_file_type.dart'; + +void main() {} diff --git a/packages/figmage_package_generator/test/src/figmage_package_generator_test.dart b/packages/figmage_package_generator/test/src/figmage_package_generator_test.dart index 19a665b1..e443efe6 100644 --- a/packages/figmage_package_generator/test/src/figmage_package_generator_test.dart +++ b/packages/figmage_package_generator/test/src/figmage_package_generator_test.dart @@ -1,36 +1,46 @@ // ignore_for_file: prefer_const_constructors, avoid_slow_async_io +import 'dart:convert'; import 'dart:io'; import 'package:figmage_package_generator/figmage_package_generator.dart'; +import 'package:mason/mason.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; +class _MockGeneratorTarget extends Mock implements GeneratorTarget {} + +class _MockDirectory extends Mock implements Directory {} + void main() { group('FigmagePackageGenerator', () { test('can be instantiated', () { expect(FigmagePackageGenerator(), isNotNull); }); + late _MockGeneratorTarget generatorTarget; + + late _MockDirectory testDirectory; + late FigmagePackageGenerator sut; setUp(() async { - sut = FigmagePackageGenerator(); + generatorTarget = _MockGeneratorTarget(); + when(() => generatorTarget.createFile(any(), any())).thenAnswer( + (invocation) => Future.value( + GeneratedFile.created( + path: invocation.positionalArguments[0] as String, + ), + ), + ); + + testDirectory = _MockDirectory(); + sut = FigmagePackageGenerator( + generatorTargetFactory: (_) => generatorTarget, + ); }); group("generate", () { - late Directory testDirectory; - - setUp(() async { - testDirectory = Directory("${Directory.current.path}/test_generated"); - if (await testDirectory.exists() == false) { - await testDirectory.create(); - } - }); - - tearDown(() async { - await testDirectory.delete(recursive: true); - }); - - test('generates directory with files', () async { + test('generates files', () async { final files = await sut.generate( projectName: "figmage_example", dir: testDirectory, @@ -41,45 +51,55 @@ void main() { isNotEmpty, reason: "No files were generated", ); - - final dir = Directory("${testDirectory.path}/figmage_example"); - expect( - await dir.exists(), - isTrue, - reason: "Directory was not created", + }); + test('generates pubspec.yaml', () async { + await sut.generate( + projectName: "figmage_example", + dir: testDirectory, + description: "A test ", ); - final pubspec = - File("${testDirectory.path}/figmage_example/pubspec.yaml"); - expect( - await pubspec.exists(), - isTrue, - reason: "pubspec.yaml was not created", - ); + verify( + () => generatorTarget.createFile( + any(that: equals("pubspec.yaml")), + any(), + ), + ).called(1); + }); - final readme = File("${testDirectory.path}/figmage_example/README.md"); - expect( - await readme.exists(), - isTrue, - reason: "README.md was not created", + test('pubspec contains project name and description', () async { + await sut.generate( + projectName: "figmage_example", + dir: testDirectory, + description: "A test ", ); + + final content = verify( + () => generatorTarget.createFile( + any(that: equals("pubspec.yaml")), + captureAny(), + ), + ).captured.first as List; + + final decoded = utf8.decode(content); + + expect(decoded, contains("figmage_example")); + expect(decoded, contains("A test")); }); - test('generated project is without analysis issues', () async { + test('generates non-empty README.md', () async { await sut.generate( projectName: "figmage_example", - description: "A test ", dir: testDirectory, + description: "A test ", ); - await Process.run("dart", ["pub", "get"]); - final result = await Process.run("dart", [ - "analyze", - testDirectory.path, - "--fatal-infos", - ]); - - expect(result.exitCode, 0); + verify( + () => generatorTarget.createFile( + any(that: equals("README.md")), + any(that: isNotEmpty), + ), + ).called(1); }); test('generates all extra type files by default', () async { @@ -88,17 +108,37 @@ void main() { dir: testDirectory, description: "A test ", ); - expect(files.any((element) => element.name == "colors.dart"), isTrue); - expect( - files.any((element) => element.name == "typography.dart"), - isTrue, + for (final type in TokenFileType.values) { + expect( + files, + contains( + isA().having( + (f) => f.path, + "path", + contains("lib/src/${type.filename}"), + ), + ), + reason: "Expected to find ${type.filename} in generated files", + ); + } + }); + + test('generated type files are generated empty', () async { + await sut.generate( + projectName: "figmage_example", + dir: testDirectory, + description: "A test ", ); - expect(files.any((element) => element.name == "spacers.dart"), isTrue); - expect(files.any((element) => element.name == "paddings.dart"), isTrue); - expect(files.any((element) => element.name == "radii.dart"), isTrue); - expect(files.any((element) => element.name == "strings.dart"), isTrue); - expect(files.any((element) => element.name == "bools.dart"), isTrue); + for (final type in TokenFileType.values) { + verify( + () => generatorTarget.createFile( + any(that: contains(type.filename)), + any(that: isEmpty), + ), + ); + } }); + test('generates no extra type files if unwanted', () async { final files = await sut.generate( projectName: "figmage_example", @@ -106,30 +146,55 @@ void main() { description: "A test ", generateColors: false, generateTypography: false, + generateNumbers: false, generateSpacers: false, generatePaddings: false, generateRadii: false, generateStrings: false, generateBools: false, ); - expect(files.any((element) => element.name == "colors.dart"), isFalse); - expect( - files.any((element) => element.name == "typography.dart"), - isFalse, + for (final type in TokenFileType.values) { + expect( + files, + isNot( + contains( + isA().having( + (f) => f.path, + "path", + contains(type.filename), + ), + ), + ), + reason: "Expected not to find ${type.filename} in generated files", + ); + } + }); + test('throws if package URI could not be resolved', () async { + sut = FigmagePackageGenerator( + generatorTargetFactory: (_) => _MockGeneratorTarget(), + packageUriResolver: (_) => null, ); - expect(files.any((element) => element.name == "spacers.dart"), isFalse); - expect( - files.any((element) => element.name == "paddings.dart"), - isFalse, + await expectLater( + () => sut.generate( + projectName: "figmage_example", + dir: testDirectory, + description: "A test ", + ), + throwsA( + isA() + .having( + (p0) => p0.packageName, + "packageName", + "figmage_package_generator", + ) + .having( + (p0) => p0.toString(), + "toString()", + contains("figmage_package_generator"), + ), + ), ); - expect(files.any((element) => element.name == "radii.dart"), isFalse); - expect(files.any((element) => element.name == "strings.dart"), isFalse); - expect(files.any((element) => element.name == "bools.dart"), isFalse); }); }); }); } - -extension on File { - String get name => path.split("/").last; -} diff --git a/packages/figmage_package_generator/test/src/token_file_type_test.dart b/packages/figmage_package_generator/test/src/token_file_type_test.dart new file mode 100644 index 00000000..f3e110eb --- /dev/null +++ b/packages/figmage_package_generator/test/src/token_file_type_test.dart @@ -0,0 +1,118 @@ +import 'package:figmage_package_generator/src/token_file_type.dart'; +import 'package:test/test.dart'; + +void main() { + group("TokenFileType", () { + group('.fromFilename', () { + test('works for colors', () async { + expect( + TokenFileType.fromFilename('colors.dart'), + equals(TokenFileType.color), + ); + }); + + test('works for typography', () async { + expect( + TokenFileType.fromFilename('typography.dart'), + equals(TokenFileType.typography), + ); + }); + + test('works for numbers', () async { + expect( + TokenFileType.fromFilename('numbers.dart'), + equals(TokenFileType.numbers), + ); + }); + + test('works for spacers', () async { + expect( + TokenFileType.fromFilename('spacers.dart'), + equals(TokenFileType.spacers), + ); + }); + + test('works for paddings', () async { + expect( + TokenFileType.fromFilename('paddings.dart'), + equals(TokenFileType.paddings), + ); + }); + + test('works for radii', () async { + expect( + TokenFileType.fromFilename('radii.dart'), + equals(TokenFileType.radii), + ); + }); + + test('works for strings', () async { + expect( + TokenFileType.fromFilename('strings.dart'), + equals(TokenFileType.strings), + ); + }); + + test('works for bools', () async { + expect( + TokenFileType.fromFilename('bools.dart'), + equals(TokenFileType.bools), + ); + }); + + test('throws for unknown file', () async { + expect( + () => TokenFileType.fromFilename('unknown.dart'), + throwsA(isA()), + ); + }); + }); + + group('tryFromFilename', () { + test('works for colors', () async { + expect( + TokenFileType.tryFromFilename('colors.dart'), + equals(TokenFileType.color), + ); + }); + + test('returns null for unknown', () async { + expect(TokenFileType.tryFromFilename("unknown.dart"), isNull); + }); + }); + + group("className", () { + test('works for colors', () async { + expect(TokenFileType.color.className, equals("Colors")); + }); + + test('works for typography', () async { + expect(TokenFileType.typography.className, equals("Typography")); + }); + + test('works for numbers', () async { + expect(TokenFileType.numbers.className, equals("Numbers")); + }); + + test('works for spacers', () async { + expect(TokenFileType.spacers.className, equals("Spacers")); + }); + + test('works for paddings', () async { + expect(TokenFileType.paddings.className, equals("Paddings")); + }); + + test('works for radii', () async { + expect(TokenFileType.radii.className, equals("Radii")); + }); + + test('works for strings', () async { + expect(TokenFileType.strings.className, equals("Strings")); + }); + + test('works for bools', () async { + expect(TokenFileType.bools.className, equals("Bools")); + }); + }); + }); +} diff --git a/pubspec.yaml b/pubspec.yaml index 820b0d4a..18e12b15 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,6 +2,8 @@ name: figmage description: A CLI tool for generating Figma styles for Flutter version: 0.1.0+1 publish_to: none +executables: + figmage: environment: sdk: ">=3.0.0 <4.0.0" @@ -13,9 +15,14 @@ dependencies: collection: ^1.18.0 dart_style: ^2.3.3 equatable: ^2.0.5 - figma: ^7.0.0 + figma: + git: + url: https://github.com/whynotmake-it/figma.git + ref: fix/add-id-to-styles figma_variables_api: - path: packages/figma_variables_api + git: + url: https://github.com/whynotmake-it/figmage.git + path: packages/figma_variables_api figmage_package_generator: git: url: https://github.com/whynotmake-it/figmage.git @@ -23,8 +30,10 @@ dependencies: freezed_annotation: ^2.4.1 json_annotation: ^4.8.1 mason_logger: ^0.2.5 + meta: ^1.11.0 path: ^1.8.3 pub_updater: ^0.3.0 + riverpod: ^2.4.6 source_gen: ^1.4.0 yaml: ^3.1.2 diff --git a/test/full_coverage_test.dart b/test/full_coverage_test.dart new file mode 100644 index 00000000..b698b49f --- /dev/null +++ b/test/full_coverage_test.dart @@ -0,0 +1,50 @@ +// ignore_for_file: unused_import +import 'package:figmage/figmage.dart'; +import 'package:figmage/src/command_runner.dart'; +import 'package:figmage/src/commands/commands.dart'; +import 'package:figmage/src/commands/forge/forge_command.dart'; +import 'package:figmage/src/commands/reforge/reforge_command.dart'; +import 'package:figmage/src/commands/shared/arg_names.dart'; +import 'package:figmage/src/commands/shared/forge_settings_providers.dart'; +import 'package:figmage/src/commands/shared/generation_notifier.dart'; +import 'package:figmage/src/commands/update/update_command.dart'; +import 'package:figmage/src/data/generators/color_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/generator_util.dart'; +import 'package:figmage/src/data/generators/number_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/padding_generator.dart'; +import 'package:figmage/src/data/generators/spacer_generator.dart'; +import 'package:figmage/src/data/generators/text_style_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/value_names_theme_class_generator.dart'; +import 'package:figmage/src/data/generators/values_by_mode_theme_extension_generator.dart'; +import 'package:figmage/src/data/repositories/dart_code_file_writer_repository.dart'; +import 'package:figmage/src/data/repositories/figma_styles_repository.dart'; +import 'package:figmage/src/data/repositories/figma_variables_repository.dart'; +import 'package:figmage/src/data/repositories/yaml_config_repository.dart'; +import 'package:figmage/src/data/util/converters/color_conversion_x.dart'; +import 'package:figmage/src/data/util/converters/string_dart_conversion_x.dart'; +import 'package:figmage/src/data/util/converters/type_style_conversion_x.dart'; +import 'package:figmage/src/domain/generators/theme_class_generator.dart'; +import 'package:figmage/src/domain/generators/theme_extension_generator.dart'; +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/models/design_token.dart'; +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/models/style/design_style.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; +import 'package:figmage/src/domain/models/tokens_by_file_type/tokens_by_type.dart'; +import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; +import 'package:figmage/src/domain/models/variable/variable.dart'; +import 'package:figmage/src/domain/providers/config_providers.dart'; +import 'package:figmage/src/domain/providers/design_token_providers.dart'; +import 'package:figmage/src/domain/providers/figmage_package_generator_providers.dart'; +import 'package:figmage/src/domain/providers/file_writer_providers.dart'; +import 'package:figmage/src/domain/providers/generator_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/providers/pub_updater_providers.dart'; +import 'package:figmage/src/domain/repositories/config_repository.dart'; +import 'package:figmage/src/domain/repositories/file_writer_repository.dart'; +import 'package:figmage/src/domain/repositories/styles_repository.dart'; +import 'package:figmage/src/domain/repositories/variables_repository.dart'; +import 'package:figmage/src/domain/util/token_filter_x.dart'; +import 'package:figmage/src/version.dart'; + +void main() {} diff --git a/test/src/command_runner_test.dart b/test/src/command_runner_test.dart index d41fda4f..c499b230 100644 --- a/test/src/command_runner_test.dart +++ b/test/src/command_runner_test.dart @@ -1,12 +1,14 @@ import 'dart:io'; import 'package:args/command_runner.dart'; -import 'package:cli_completion/cli_completion.dart'; import 'package:figmage/src/command_runner.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/providers/pub_updater_providers.dart'; import 'package:figmage/src/version.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; import 'package:pub_updater/pub_updater.dart'; +import 'package:riverpod/riverpod.dart'; import 'package:test/test.dart'; class _MockLogger extends Mock implements Logger {} @@ -23,6 +25,7 @@ Run ${lightCyan.wrap('$executableName update')} to update'''; void main() { group('FigmageCommandRunner', () { + late ProviderContainer container; late PubUpdater pubUpdater; late Logger logger; late FigmageCommandRunner commandRunner; @@ -36,10 +39,18 @@ void main() { logger = _MockLogger(); - commandRunner = FigmageCommandRunner( - logger: logger, - pubUpdater: pubUpdater, + container = ProviderContainer( + overrides: [ + loggerProvider.overrideWith((ref) => logger), + pubUpdaterProvider.overrideWith((ref) => pubUpdater), + ], ); + + commandRunner = FigmageCommandRunner(container); + }); + + tearDown(() { + container.dispose(); }); test('shows update message when newer version exists', () async { @@ -98,13 +109,6 @@ void main() { verifyNever(() => logger.info(updatePrompt)); }); - test('can be instantiated without an explicit analytics/logger instance', - () { - final commandRunner = FigmageCommandRunner(); - expect(commandRunner, isNotNull); - expect(commandRunner, isA>()); - }); - test('handles FormatException', () async { const exception = FormatException('oops!'); var isFirstInvocation = true; @@ -143,15 +147,6 @@ void main() { }); }); - group('forge command', () { - test('requires token argument', () async { - final result = await commandRunner.run(['forge']); - expect(result, equals(ExitCode.usage.code)); - verify(() => logger.err('Both token and fileId are required.')) - .called(1); - }); - }); - group('--verbose', () { test('enables verbose logging', () async { final result = await commandRunner.run(['--verbose']); diff --git a/test/src/commands/forge/forge_command_test.dart b/test/src/commands/forge/forge_command_test.dart index 85af95dc..2eecf75d 100644 --- a/test/src/commands/forge/forge_command_test.dart +++ b/test/src/commands/forge/forge_command_test.dart @@ -3,9 +3,13 @@ import 'package:figmage/src/command_runner.dart'; import 'package:figmage/src/data/repositories/figma_variables_repository.dart'; import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; import 'package:figmage/src/domain/models/variable/variable.dart'; +import 'package:figmage/src/domain/providers/figmage_package_generator_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/repositories/variables_repository.dart'; import 'package:figmage_package_generator/figmage_package_generator.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:riverpod/riverpod.dart'; import 'package:test/test.dart'; class _MockLogger extends Mock implements Logger {} @@ -18,36 +22,37 @@ class _MockFigmaVariablesRepository extends Mock class _MockFigmagePackageGenerator extends Mock implements FigmagePackageGenerator {} -void main() { - group('forge', () { - final variableList = [ - ColorVariable( - id: 'VariableID:1:2', - name: 'green', - remote: false, - key: '26a211e627a2da8a80c0f06e0b776ba97a8780e3', - variableCollectionId: 'VariableCollectionId:0:3', - variableCollectionName: 'collection', - resolvedType: 'COLOR', - description: '', - hiddenFromPublishing: false, - scopes: ['ALL_SCOPES'], - codeSyntax: {}, - collectionModeNames: {'0:0': 'dark', '1:0': 'light'}, - valuesByMode: { - '0:0': const AliasData(data: 4290117398), - '1:0': const AliasData(data: 4286038042), - }, - ), - ]; +final _variableList = [ + const ColorVariable( + id: 'VariableID:1:2', + name: 'green', + remote: false, + key: '26a211e627a2da8a80c0f06e0b776ba97a8780e3', + variableCollectionId: 'VariableCollectionId:0:3', + variableCollectionName: 'collection', + resolvedType: 'COLOR', + description: '', + hiddenFromPublishing: false, + scopes: ['ALL_SCOPES'], + codeSyntax: {}, + collectionModeNames: {'0:0': 'dark', '1:0': 'light'}, + valuesByMode: { + '0:0': AliasData(data: 4290117398), + '1:0': AliasData(data: 4286038042), + }, + ), +]; - final colorValueMap = { - 'collection': { - 'dark': {'green': 4290117398}, - 'light': {'green': 4286038042}, - }, - }; +final _colorValueMap = { + 'collection': { + 'dark': {'green': 4290117398}, + 'light': {'green': 4286038042}, + }, +}; +void main() { + group('forge', () { + late ProviderContainer container; late Logger logger; late FigmageCommandRunner commandRunner; late FigmaVariablesRepository figmaVariablesRepository; @@ -62,13 +67,19 @@ void main() { logger = _MockLogger(); figmaVariablesRepository = _MockFigmaVariablesRepository(); figmagePackageGenerator = _MockFigmagePackageGenerator(); - commandRunner = FigmageCommandRunner( - logger: logger, - figmaVariablesRepository: figmaVariablesRepository, - figmagePackageGenerator: figmagePackageGenerator, - appendCodeEntriesToFile: (entries, path) {}, + + container = ProviderContainer( + overrides: [ + loggerProvider.overrideWith((ref) => logger), + variablesRepositoryProvider + .overrideWith((ref) => figmaVariablesRepository), + figmagePackageGeneratorProvider + .overrideWith((ref) => figmagePackageGenerator), + ], ); + commandRunner = FigmageCommandRunner(container); + // Stub the package generator behavior when( () => figmagePackageGenerator.generate( @@ -87,13 +98,13 @@ void main() { fileId: any(named: 'fileId'), token: any(named: 'token'), ), - ).thenAnswer((_) async => variableList); + ).thenAnswer((_) async => _variableList); when( () => figmaVariablesRepository.createValueModeMap( - variables: variableList, + variables: _variableList, ), - ).thenAnswer((_) => colorValueMap); + ).thenAnswer((_) => _colorValueMap); when(() => progress.complete(any())).thenAnswer((_) { final message = _.positionalArguments.elementAt(0) as String?; @@ -102,29 +113,6 @@ void main() { when(() => logger.progress(any())).thenReturn(progress); }); - test('successfully generates package and appends color tokens', () async { - final exitCode = await commandRunner.run( - ['forge', '--token=token', '--fileId=fileId'], - ); - verify(() => logger.progress('Generating package')).called(1); - verify( - () => figmagePackageGenerator.generate( - projectName: any(named: 'projectName'), - dir: any(named: 'dir'), - description: any(named: 'description'), - ), - ).called(1); - expect(exitCode, equals(ExitCode.success.code)); - }); - - test('requires both token and fileId', () async { - final exitCode = await commandRunner.run(['forge']); - expect(exitCode, equals(ExitCode.usage.code)); - verify(() => logger.err('Both token and fileId are required.')).called( - 1, - ); - }); - test('tells user how to use command when wrong arguments provided', () async { final exitCode = await commandRunner.run(['forge', '-p']); diff --git a/test/src/commands/shared/forge_settings_providers_test.dart b/test/src/commands/shared/forge_settings_providers_test.dart new file mode 100644 index 00000000..586e839e --- /dev/null +++ b/test/src/commands/shared/forge_settings_providers_test.dart @@ -0,0 +1,83 @@ +import 'package:args/args.dart'; +import 'package:figmage/src/commands/shared/forge_settings_providers.dart'; +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/providers/config_providers.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:test/test.dart'; + +class _MockArgResults extends Mock implements ArgResults {} + +void main() { + group("settingsProvider", () { + late ProviderContainer container; + const config = Config(fileId: "fileId", packageName: "packageName"); + + late _MockArgResults argResults; + setUp(() { + container = ProviderContainer( + overrides: [ + configProvider.overrideWith((ref, _) => config), + ], + ); + argResults = _MockArgResults(); + + when(() => argResults['token']).thenReturn("arg_token"); + when(() => argResults['fileId']).thenReturn("arg_fileId"); + when(() => argResults['path']).thenReturn("arg_path"); + }); + + tearDown(() { + container.dispose(); + }); + + group('settingsProvider', () { + test('returns token from argResults', () async { + final result = await container + .read(settingsProvider((argResults: argResults)).future); + expect(result.token, "arg_token"); + }); + + test('prefers fileId from argResults', () async { + final result = await container + .read(settingsProvider((argResults: argResults)).future); + expect(result.fileId, "arg_fileId"); + }); + + test('takes fileId from config if not in args', () async { + when(() => argResults['fileId']).thenReturn(null); + final result = await container + .read(settingsProvider((argResults: argResults)).future); + expect(result.fileId, config.fileId); + }); + + test('returns path from argResults', () async { + final result = await container + .read(settingsProvider((argResults: argResults)).future); + expect(result.path, "arg_path"); + }); + + test('throws ArgumentError if token is missing', () async { + when(() => argResults['token']).thenReturn(null); + await expectLater( + () => + container.read(settingsProvider((argResults: argResults)).future), + throwsA( + isA().having((p0) => p0.name, 'name', 'token'), + ), + ); + }); + + test('throws ArgumentError if path is missing', () async { + when(() => argResults['path']).thenReturn(null); + await expectLater( + () => + container.read(settingsProvider((argResults: argResults)).future), + throwsA( + isA().having((p0) => p0.name, 'name', 'path'), + ), + ); + }); + }); + }); +} diff --git a/test/src/commands/shared/generation_notifier_test.dart b/test/src/commands/shared/generation_notifier_test.dart new file mode 100644 index 00000000..1f3dd721 --- /dev/null +++ b/test/src/commands/shared/generation_notifier_test.dart @@ -0,0 +1,79 @@ +import 'package:args/args.dart'; +import 'package:figmage/src/commands/shared/forge_settings_providers.dart'; +import 'package:figmage/src/commands/shared/generation_notifier.dart'; +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/providers/figmage_package_generator_providers.dart'; +import 'package:figmage/src/domain/providers/file_writer_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/repositories/variables_repository.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:test/test.dart'; + +import '../../../test_util/mock/mock_variables.dart'; + +class _MockLogger extends Mock implements Logger {} + +class _MockProgress extends Mock implements Progress {} + +class _MockVariablesRepository extends Mock implements VariablesRepository {} + +class _MockArgResults extends Mock implements ArgResults {} + +void main() { + group("GenerationNotifier", () { + late List overrides; + late ProviderContainer container; + + late _MockVariablesRepository variablesRepository; + late _MockLogger logger; + late _MockArgResults argResults; + + setUp(() { + variablesRepository = _MockVariablesRepository(); + when( + () => variablesRepository.getVariables( + fileId: any(named: "fileId"), + token: any(named: "token"), + ), + ).thenAnswer((_) async => mockVariables); + logger = _MockLogger(); + when(() => logger.progress(any())).thenReturn(_MockProgress()); + + argResults = _MockArgResults(); + overrides = [ + variablesRepositoryProvider.overrideWith((ref) => variablesRepository), + generatedPackageProvider.overrideWith((ref, arg) => Future.value({})), + fileWriterProvider.overrideWith((ref, args) => Future.value(args.keys)), + loggerProvider.overrideWith((ref) => logger), + settingsProvider.overrideWith( + (ref, arg) => Future.value( + ( + token: "token", + fileId: "fileId", + path: "path", + config: const Config( + fileId: "fileId", + packageName: "packageName", + ), + ), + ), + ), + ]; + container = ProviderContainer( + overrides: overrides, + ); + }); + tearDown(() { + container.dispose(); + }); + + test('returns success Exit Code', () async { + final result = + await container.read(generationStateProvider(argResults).future); + + expect(result, ExitCode.success); + }); + }); +} diff --git a/test/src/data/generators/color_theme_extension_generator_test.dart b/test/src/data/generators/color_theme_extension_generator_test.dart index ca0edbd4..ed9c8cbc 100644 --- a/test/src/data/generators/color_theme_extension_generator_test.dart +++ b/test/src/data/generators/color_theme_extension_generator_test.dart @@ -26,6 +26,20 @@ void main() { equals(_expectedNullableColorThemeExtensionString), ); }); + + test('Can deal with only one empty mode', () async { + final generator = ColorThemeExtensionGenerator( + className: 'MyColorTheme', + valuesByNameByMode: { + '': {'color1': 0xFF000000, 'color2': 0xFFFFFFFF}, + }, + buildContextExtensionNullable: true, + ); + expect( + generator.generate(), + equals(_expectedSingleModeOutputString), + ); + }); } // ************************************************************************** @@ -47,6 +61,14 @@ class MyColorTheme extends ThemeExtension { required this.color2, }); + const MyColorTheme.mode1() + : color1 = const Color(0xff000000), + color2 = const Color(0xffffffff); + + const MyColorTheme.mode2() + : color1 = const Color(0xff111111), + color2 = const Color(0xff222222); + final Color? color1; final Color? color2; @@ -85,15 +107,6 @@ class MyColorTheme extends ThemeExtension { extension MyColorThemeBuildContextX on BuildContext { MyColorTheme get myColorTheme => Theme.of(this).extension()!; } - -const MyColorTheme mode1MyColorTheme = MyColorTheme( - color1: Color(0xff000000), - color2: Color(0xffffffff), -); -const MyColorTheme mode2MyColorTheme = MyColorTheme( - color1: Color(0xff111111), - color2: Color(0xff222222), -); '''; const _expectedNullableColorThemeExtensionString = ''' @@ -111,6 +124,14 @@ class MyColorTheme extends ThemeExtension { required this.color2, }); + const MyColorTheme.mode1() + : color1 = const Color(0xff000000), + color2 = const Color(0xffffffff); + + const MyColorTheme.mode2() + : color1 = const Color(0xff111111), + color2 = const Color(0xff222222); + final Color? color1; final Color? color2; @@ -149,13 +170,63 @@ class MyColorTheme extends ThemeExtension { extension MyColorThemeBuildContextX on BuildContext { MyColorTheme? get myColorTheme => Theme.of(this).extension(); } +'''; + +const _expectedSingleModeOutputString = ''' +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +@immutable +class MyColorTheme extends ThemeExtension { + const MyColorTheme({ + required this.color1, + required this.color2, + }); + + const MyColorTheme.standard() + : color1 = const Color(0xff000000), + color2 = const Color(0xffffffff); + + final Color? color1; + + final Color? color2; + + @override + MyColorTheme copyWith([ + Color? color1, + Color? color2, + ]) => + MyColorTheme( + color1: color1 ?? this.color1, + color2: color2 ?? this.color2, + ); + + @override + MyColorTheme lerp( + MyColorTheme? other, + double t, + ) { + if (other is! MyColorTheme) return this; + return MyColorTheme( + color1: Color.lerp( + color1, + other.color1, + t, + ), + color2: Color.lerp( + color2, + other.color2, + t, + ), + ); + } +} -const MyColorTheme mode1MyColorTheme = MyColorTheme( - color1: Color(0xff000000), - color2: Color(0xffffffff), -); -const MyColorTheme mode2MyColorTheme = MyColorTheme( - color1: Color(0xff111111), - color2: Color(0xff222222), -); +extension MyColorThemeBuildContextX on BuildContext { + MyColorTheme? get myColorTheme => Theme.of(this).extension(); +} '''; diff --git a/test/src/data/generators/genarator_util_test.dart b/test/src/data/generators/generator_util_test.dart similarity index 70% rename from test/src/data/generators/genarator_util_test.dart rename to test/src/data/generators/generator_util_test.dart index dbcd82b3..8ad305fa 100644 --- a/test/src/data/generators/genarator_util_test.dart +++ b/test/src/data/generators/generator_util_test.dart @@ -76,6 +76,49 @@ void main() { }); }); + group("convertToValidConstantName", () { + test('converts path to camel case and adds k', () async { + expect(convertToValidConstantName('Hello/world'), equals('kHelloWorld')); + expect( + convertToValidConstantName('Hello/world/Again'), + equals('kHelloWorldAgain'), + ); + }); + + test('removes non-alphanumeric characters', () { + expect( + convertToValidConstantName('Hello/world/Again!!'), + equals('kHelloWorldAgain'), + ); + expect( + convertToValidConstantName('Hello/world/Again/123'), + equals('kHelloWorldAgain123'), + ); + }); + + test('works with leading numbers', () { + expect( + convertToValidConstantName('123Hello/world/Again'), + equals('k123HelloWorldAgain'), + ); + }); + + test('can deal with only numbers', () { + expect( + convertToValidConstantName('123'), + equals('k123'), + ); + expect( + convertToValidConstantName('123/hello'), + equals('k123Hello'), + ); + }); + + test('throws for empty string', () async { + expect(() => convertToValidConstantName(''), throwsArgumentError); + }); + }); + group("convertToValidClassName", () { test('leaves valid class names unchanged', () { expect(convertToValidClassName('HelloWorld'), equals('HelloWorld')); @@ -83,7 +126,7 @@ void main() { }); test('converts leading lowercase letters to uppercase', () { - expect(convertToValidClassName('helloWorld'), equals('HelloWorld')); + expect(convertToValidClassName('hello/world'), equals('HelloWorld')); expect(convertToValidClassName('hello123'), equals('Hello123')); }); diff --git a/test/src/data/generators/number_theme_extension_generator_test.dart b/test/src/data/generators/number_theme_extension_generator_test.dart index 95c6b1ae..66e902aa 100644 --- a/test/src/data/generators/number_theme_extension_generator_test.dart +++ b/test/src/data/generators/number_theme_extension_generator_test.dart @@ -48,6 +48,14 @@ class MyNumbersTheme extends ThemeExtension { required this.m, }); + const MyNumbersTheme.small() + : s = 1.0, + m = 2.0; + + const MyNumbersTheme.large() + : s = 2.0, + m = 4.0; + final double? s; final double? m; @@ -87,15 +95,6 @@ extension MyNumbersThemeBuildContextX on BuildContext { MyNumbersTheme get myNumbersTheme => Theme.of(this).extension()!; } - -const MyNumbersTheme smallMyNumbersTheme = MyNumbersTheme( - s: 1.0, - m: 2.0, -); -const MyNumbersTheme largeMyNumbersTheme = MyNumbersTheme( - s: 2.0, - m: 4.0, -); '''; const _expectedNullableNumberExtensionString = ''' // coverage:ignore-file @@ -114,6 +113,14 @@ class MyNumbersTheme extends ThemeExtension { required this.m, }); + const MyNumbersTheme.small() + : s = 1.0, + m = 2.0; + + const MyNumbersTheme.large() + : s = 2.0, + m = 4.0; + final double? s; final double? m; @@ -153,13 +160,4 @@ extension MyNumbersThemeBuildContextX on BuildContext { MyNumbersTheme? get myNumbersTheme => Theme.of(this).extension(); } - -const MyNumbersTheme smallMyNumbersTheme = MyNumbersTheme( - s: 1.0, - m: 2.0, -); -const MyNumbersTheme largeMyNumbersTheme = MyNumbersTheme( - s: 2.0, - m: 4.0, -); '''; diff --git a/test/src/data/generators/text_style_theme_extension_generator_test.dart b/test/src/data/generators/text_style_theme_extension_generator_test.dart new file mode 100644 index 00000000..64e2914e --- /dev/null +++ b/test/src/data/generators/text_style_theme_extension_generator_test.dart @@ -0,0 +1,254 @@ +import 'package:figmage/src/data/generators/text_style_theme_extension_generator.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; +import 'package:test/test.dart'; + +void main() { + group('TextStyleThemeExtensionsGenerator', () { + const valuesByNameByMode = { + 'mode1': { + 'textStyle1': TextStyle( + fontSize: 16, + fontFamily: 'Roboto', + decoration: TextDecoration.underline, + ), + 'textStyle2': TextStyle( + fontSize: 24, + fontFamily: 'Roboto', + decoration: TextDecoration.lineThrough, + ), + }, + 'mode2': { + 'textStyle1': TextStyle( + fontSize: 16, + fontFamily: 'Roboto', + fontWeight: 700, + decoration: TextDecoration.underline, + ), + 'textStyle2': TextStyle( + fontSize: 24, + fontFamily: 'Roboto', + fontWeight: 700, + decoration: TextDecoration.lineThrough, + ), + }, + }; + test('Generates a ThemeExtension output file', () async { + final generator = TextStyleThemeExtensionGenerator( + className: 'MyTextStyles', + valuesByNameByMode: valuesByNameByMode, + extensionSymbolUrl: 'dart:ui', + ); + expect(generator.generate(), _expectedTextStyleThemeExtensionString); + }); + test('Output file with nullable BuildContext extension', () async { + final generator = TextStyleThemeExtensionGenerator( + className: 'MyTextStyles', + valuesByNameByMode: valuesByNameByMode, + extensionSymbolUrl: 'dart:ui', + buildContextExtensionNullable: true, + ); + + expect( + generator.generate(), + _expectedNullableTextStyleThemeExtensionString, + ); + }); + }); +} + +// ************************************************************************** +// TEST RESOURCES +// ************************************************************************** +const _expectedTextStyleThemeExtensionString = ''' +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint + +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +@immutable +class MyTextStyles extends ThemeExtension { + const MyTextStyles({ + required this.textStyle1, + required this.textStyle2, + }); + + const MyTextStyles.mode1() + : textStyle1 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 16.0, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.underline, + ), + textStyle2 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 24.0, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.lineThrough, + ); + + const MyTextStyles.mode2() + : textStyle1 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 16.0, + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.underline, + ), + textStyle2 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 24.0, + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.lineThrough, + ); + + final TextStyle? textStyle1; + + final TextStyle? textStyle2; + + @override + MyTextStyles copyWith([ + TextStyle? textStyle1, + TextStyle? textStyle2, + ]) => + MyTextStyles( + textStyle1: textStyle1 ?? this.textStyle1, + textStyle2: textStyle2 ?? this.textStyle2, + ); + + @override + MyTextStyles lerp( + MyTextStyles? other, + double t, + ) { + if (other is! MyTextStyles) return this; + return MyTextStyles( + textStyle1: TextStyle.lerp( + textStyle1, + other.textStyle1, + t, + ), + textStyle2: TextStyle.lerp( + textStyle2, + other.textStyle2, + t, + ), + ); + } +} + +extension MyTextStylesBuildContextX on BuildContext { + MyTextStyles get myTextStyles => Theme.of(this).extension()!; +} +'''; + +const _expectedNullableTextStyleThemeExtensionString = ''' +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint + +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +@immutable +class MyTextStyles extends ThemeExtension { + const MyTextStyles({ + required this.textStyle1, + required this.textStyle2, + }); + + const MyTextStyles.mode1() + : textStyle1 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 16.0, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.underline, + ), + textStyle2 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 24.0, + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.lineThrough, + ); + + const MyTextStyles.mode2() + : textStyle1 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 16.0, + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.underline, + ), + textStyle2 = const TextStyle( + fontFamily: 'Roboto', + fontSize: 24.0, + fontWeight: FontWeight.w700, + fontStyle: FontStyle.normal, + letterSpacing: 1.0, + height: 1.0, + decoration: TextDecoration.lineThrough, + ); + + final TextStyle? textStyle1; + + final TextStyle? textStyle2; + + @override + MyTextStyles copyWith([ + TextStyle? textStyle1, + TextStyle? textStyle2, + ]) => + MyTextStyles( + textStyle1: textStyle1 ?? this.textStyle1, + textStyle2: textStyle2 ?? this.textStyle2, + ); + + @override + MyTextStyles lerp( + MyTextStyles? other, + double t, + ) { + if (other is! MyTextStyles) return this; + return MyTextStyles( + textStyle1: TextStyle.lerp( + textStyle1, + other.textStyle1, + t, + ), + textStyle2: TextStyle.lerp( + textStyle2, + other.textStyle2, + t, + ), + ); + } +} + +extension MyTextStylesBuildContextX on BuildContext { + MyTextStyles? get myTextStyles => Theme.of(this).extension(); +} +'''; diff --git a/test/src/data/generators/text_style_theme_generator_test.dart b/test/src/data/generators/text_style_theme_generator_test.dart deleted file mode 100644 index bcda41b4..00000000 --- a/test/src/data/generators/text_style_theme_generator_test.dart +++ /dev/null @@ -1,284 +0,0 @@ -import 'package:figma/figma.dart'; -import 'package:figmage/src/data/generators/text_style_theme_extension_generator.dart'; -import 'package:test/test.dart'; - -void main() { - test('Generates a ThemeExtension output file', () async { - final generator = TextStyleThemeExtensionGenerator( - className: 'MyTextStyles', - valuesByNameByMode: { - 'mode1': { - 'textStyle1': TypeStyle( - fontSize: 16, - fontWeight: 500, - fontFamily: 'Roboto', - textDecoration: TextDecoration.underline, - letterSpacing: 1, - ), - 'textStyle2': TypeStyle( - fontSize: 32, - fontWeight: 900, - fontFamily: 'Roboto', - textDecoration: TextDecoration.strikeThrough, - letterSpacing: 1, - ), - }, - 'mode2': { - 'textStyle1': TypeStyle( - fontSize: 1, - fontWeight: 400, - fontFamily: 'Roboto', - textDecoration: TextDecoration.underline, - letterSpacing: 1, - ), - 'textStyle2': TypeStyle( - fontSize: 2, - fontWeight: 400, - fontFamily: 'Roboto', - textDecoration: TextDecoration.strikeThrough, - letterSpacing: 1, - ), - }, - }, - extensionSymbolUrl: 'dart:ui', - ); - expect(generator.generate(), _expectedTextStyleThemeExtensionString); - }); - test('Output file with nullable BuildContext extension', () async { - final generator = TextStyleThemeExtensionGenerator( - className: 'MyTextStyles', - valuesByNameByMode: { - 'mode1': { - 'textStyle1': TypeStyle( - fontSize: 16, - fontWeight: 500, - fontFamily: 'Roboto', - textDecoration: TextDecoration.underline, - letterSpacing: 1, - ), - 'textStyle2': TypeStyle( - fontSize: 32, - fontWeight: 900, - fontFamily: 'Roboto', - textDecoration: TextDecoration.strikeThrough, - letterSpacing: 1, - ), - }, - 'mode2': { - 'textStyle1': TypeStyle( - fontSize: 1, - fontWeight: 400, - fontFamily: 'Roboto', - textDecoration: TextDecoration.underline, - letterSpacing: 1, - ), - 'textStyle2': TypeStyle( - fontSize: 2, - fontWeight: 400, - fontFamily: 'Roboto', - textDecoration: TextDecoration.strikeThrough, - letterSpacing: 1, - ), - }, - }, - extensionSymbolUrl: 'dart:ui', - buildContextExtensionNullable: true, - ); - - expect( - generator.generate(), - _expectedNullableTextStyleThemeExtensionString, - ); - }); -} - -// ************************************************************************** -// TEST RESOURCES -// ************************************************************************** -const _expectedTextStyleThemeExtensionString = ''' -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint - -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -@immutable -class MyTextStyles extends ThemeExtension { - const MyTextStyles({ - required this.textStyle1, - required this.textStyle2, - }); - - final TextStyle? textStyle1; - - final TextStyle? textStyle2; - - @override - MyTextStyles copyWith([ - TextStyle? textStyle1, - TextStyle? textStyle2, - ]) => - MyTextStyles( - textStyle1: textStyle1 ?? this.textStyle1, - textStyle2: textStyle2 ?? this.textStyle2, - ); - - @override - MyTextStyles lerp( - MyTextStyles? other, - double t, - ) { - if (other is! MyTextStyles) return this; - return MyTextStyles( - textStyle1: TextStyle.lerp( - textStyle1, - other.textStyle1, - t, - ), - textStyle2: TextStyle.lerp( - textStyle2, - other.textStyle2, - t, - ), - ); - } -} - -extension MyTextStylesBuildContextX on BuildContext { - MyTextStyles get myTextStyles => Theme.of(this).extension()!; -} - -const MyTextStyles mode1MyTextStyles = MyTextStyles( - textStyle1: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.underline, - fontFamily: 'Roboto', - ), - textStyle2: TextStyle( - fontSize: 32, - fontWeight: FontWeight.w900, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.lineThrough, - fontFamily: 'Roboto', - ), -); -const MyTextStyles mode2MyTextStyles = MyTextStyles( - textStyle1: TextStyle( - fontSize: 1, - fontWeight: FontWeight.w400, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.underline, - fontFamily: 'Roboto', - ), - textStyle2: TextStyle( - fontSize: 2, - fontWeight: FontWeight.w400, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.lineThrough, - fontFamily: 'Roboto', - ), -); -'''; - -const _expectedNullableTextStyleThemeExtensionString = ''' -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint - -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -@immutable -class MyTextStyles extends ThemeExtension { - const MyTextStyles({ - required this.textStyle1, - required this.textStyle2, - }); - - final TextStyle? textStyle1; - - final TextStyle? textStyle2; - - @override - MyTextStyles copyWith([ - TextStyle? textStyle1, - TextStyle? textStyle2, - ]) => - MyTextStyles( - textStyle1: textStyle1 ?? this.textStyle1, - textStyle2: textStyle2 ?? this.textStyle2, - ); - - @override - MyTextStyles lerp( - MyTextStyles? other, - double t, - ) { - if (other is! MyTextStyles) return this; - return MyTextStyles( - textStyle1: TextStyle.lerp( - textStyle1, - other.textStyle1, - t, - ), - textStyle2: TextStyle.lerp( - textStyle2, - other.textStyle2, - t, - ), - ); - } -} - -extension MyTextStylesBuildContextX on BuildContext { - MyTextStyles? get myTextStyles => Theme.of(this).extension(); -} - -const MyTextStyles mode1MyTextStyles = MyTextStyles( - textStyle1: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.underline, - fontFamily: 'Roboto', - ), - textStyle2: TextStyle( - fontSize: 32, - fontWeight: FontWeight.w900, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.lineThrough, - fontFamily: 'Roboto', - ), -); -const MyTextStyles mode2MyTextStyles = MyTextStyles( - textStyle1: TextStyle( - fontSize: 1, - fontWeight: FontWeight.w400, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.underline, - fontFamily: 'Roboto', - ), - textStyle2: TextStyle( - fontSize: 2, - fontWeight: FontWeight.w400, - fontStyle: FontStyle.normal, - letterSpacing: 1, - decoration: TextDecoration.lineThrough, - fontFamily: 'Roboto', - ), -); -'''; diff --git a/test/src/data/repositories/dart_post_generation_repository_test.dart b/test/src/data/repositories/dart_post_generation_repository_test.dart new file mode 100644 index 00000000..f69c157b --- /dev/null +++ b/test/src/data/repositories/dart_post_generation_repository_test.dart @@ -0,0 +1,91 @@ +import 'dart:io'; + +import 'package:figmage/src/data/repositories/dart_post_generation_repository.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +class _MockProgress extends Mock implements Progress {} + +class _MockProcessRunner extends Mock { + Future call( + String command, + List args, { + String? workingDirectory, + }); +} + +void main() { + group("DartPostGenerationRepository", () { + late DartPostGenerationRepository sut; + late _MockProcessRunner processRunner; + late _MockProgress progress; + setUp(() { + processRunner = _MockProcessRunner(); + progress = _MockProgress(); + sut = DartPostGenerationRepository( + processRunner: processRunner.call, + ); + when( + () => processRunner.call( + any(), + any(), + workingDirectory: any(named: "workingDirectory"), + ), + ).thenAnswer((_) async => ProcessResult(0, 0, '', '')); + }); + + group('runMaintenanceTasks', () { + test('returns files if no pubspec.yaml is found', () async { + final files = [ + File('file1'), + File('file2'), + ]; + when(() => progress.fail(any())).thenReturn(null); + final result = await sut.runMaintenanceTasks(files, progress: progress); + verify(() => progress.fail("No pubspec.yaml found in generated files")) + .called(1); + expect(result, files); + }); + + test('runs pub get, format and fix on the directory', () async { + final files = [ + File('dir/file1'), + File('dir/file2'), + File('dir/pubspec.yaml'), + ]; + + final result = await sut.runMaintenanceTasks( + files, + progress: progress, + ); + + verify( + () => processRunner.call( + 'dart', + ['pub', 'get'], + workingDirectory: 'dir', + ), + ).called(1); + + verify( + () => processRunner.call( + 'dart', + ['format'], + workingDirectory: 'dir', + ), + ).called(1); + + verify( + () => processRunner.call( + 'dart', + ['fix', '--apply'], + workingDirectory: 'dir', + ), + ).called(1); + + expect(result, files); + }); + }); + }); +} diff --git a/test/src/data/repositories/figma_variables_repository_test.dart b/test/src/data/repositories/figma_variables_repository_test.dart index 02928ddb..d5901bf3 100644 --- a/test/src/data/repositories/figma_variables_repository_test.dart +++ b/test/src/data/repositories/figma_variables_repository_test.dart @@ -104,7 +104,7 @@ void main() { final repository = FigmaVariablesRepository(); final variables = repository.fromDtoToModel(variablesResponseDto); - expect(variables, isA>()); + expect(variables, isA>>()); // Specific expected equal statements for each field expect( variables.first.key, @@ -116,6 +116,7 @@ void main() { variables.first.variableCollectionId, equals('VariableCollectionId:0:3'), ); + expect(variables.first.variableCollectionName, "collection"); expect(variables.first.scopes, equals(const ['ALL_SCOPES'])); expect(variables.first.codeSyntax, equals(const {})); expect(variables.first.resolvedType, equals('COLOR')); diff --git a/test/src/data/repositories/yaml_config_repository_test.dart b/test/src/data/repositories/yaml_config_repository_test.dart index 13ff1b09..eca7ab48 100644 --- a/test/src/data/repositories/yaml_config_repository_test.dart +++ b/test/src/data/repositories/yaml_config_repository_test.dart @@ -2,33 +2,32 @@ import 'dart:io'; import 'package:figmage/src/data/repositories/yaml_config_repository.dart'; import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage/src/domain/repositories/config_repository.dart'; import 'package:mason_logger/mason_logger.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:riverpod/riverpod.dart'; import 'package:test/test.dart'; -class MockFile extends Mock implements File {} +class _MockFile extends Mock implements File {} -class MockLogger extends Mock implements Logger {} +class _MockLogger extends Mock implements Logger {} void main() { group('YamlConfigRepository', () { - group('constructor', () { - test('has default logger', () async { - final sut = YamlConfigRepository(); - - expect(sut, isA()); - }); - }); - group('readConfigFromFile', () { + late ProviderContainer container; + late _MockFile file; + late _MockLogger logger; + late YamlConfigRepository sut; - late MockFile file; - late MockLogger logger; setUp(() { - file = MockFile(); - logger = MockLogger(); - sut = YamlConfigRepository(logger: logger); - + logger = _MockLogger(); + container = ProviderContainer( + overrides: [loggerProvider.overrideWith((ref) => logger)], + ); + sut = container.read(configRepositoryProvider) as YamlConfigRepository; + file = _MockFile(); when( () => file.path, ).thenReturn('./figmage.yaml'); @@ -42,20 +41,34 @@ void main() { when(() => logger.warn(any())).thenReturn(null); }); - test('defaults to ./figmage.yaml and logs path', () { + tearDown(() { + container.dispose(); + }); + + test('defaults to ./figmage.yaml and logs path', () async { sut.readConfigFromFile(); - verify(() => logger.info("Reading config from ./figmage.yaml")); + verify(() => logger.info("Reading config from ./figmage.yaml")) + .called(1); }); - test('checks if file exists', () async { + test('checks if file exists and returns default config if not', () async { when(() => file.existsSync()).thenReturn(false); - expect( - () async => await sut.readConfigFromFile(file: file), - throwsA(isA()), - ); + final result = await sut.readConfigFromFile(file: file); + verify( + () => logger.info('Config file not found, using default config.'), + ).called(1); + expect(result, const Config()); verify(() => file.existsSync()).called(1); }); + test('returns default if file does not exist', () async { + when(() => file.existsSync()).thenReturn(false); + await expectLater( + await sut.readConfigFromFile(file: file), + const Config(), + ); + }); + test('reads the file', () async { await sut.readConfigFromFile(file: file); verify(() => file.readAsString()).called(1); @@ -119,16 +132,6 @@ void main() { ); }); - test('throws FormatException if values are missing', () async { - when(() => file.readAsString()).thenAnswer( - (_) => Future.value('fileId: fileId'), - ); - expect( - () => sut.readConfigFromFile(file: file), - throwsA(isA()), - ); - }); - test('does not warn for good yaml', () async { await sut.readConfigFromFile(file: file); verifyNever(() => logger.warn(any())).called(0); diff --git a/test/src/domain/models/config/config_test.dart b/test/src/domain/models/config/config_test.dart index a93a2360..f369c881 100644 --- a/test/src/domain/models/config/config_test.dart +++ b/test/src/domain/models/config/config_test.dart @@ -34,6 +34,10 @@ void main() { "generate": true, "from": ["path1", "path2"], }, + "numbers": { + "generate": true, + "from": ["path1", "path2"], + }, "spacers": { "generate": true, "from": ["path1", "path2"], @@ -65,6 +69,9 @@ void main() { bools: GenerationSettings( from: ["path1", "path2"], ), + numbers: GenerationSettings( + from: ["path1", "path2"], + ), spacers: GenerationSettings( from: ["path1", "path2"], ), @@ -87,6 +94,8 @@ void main() { expect(sut.strings.from, isEmpty); expect(sut.bools.generate, isTrue); expect(sut.bools.from, isEmpty); + expect(sut.numbers.generate, isTrue); + expect(sut.numbers.from, isEmpty); expect(sut.spacers.generate, isFalse); expect(sut.spacers.from, isEmpty); expect(sut.paddings.generate, isFalse); @@ -119,6 +128,7 @@ void main() { fullExample.typography, fullExample.strings, fullExample.bools, + fullExample.numbers, fullExample.spacers, fullExample.paddings, fullExample.radii, diff --git a/test/src/domain/models/style/color_style_test.dart b/test/src/domain/models/style/color_style_test.dart new file mode 100644 index 00000000..9b2de7cf --- /dev/null +++ b/test/src/domain/models/style/color_style_test.dart @@ -0,0 +1,14 @@ +import 'package:figmage/src/domain/models/design_token.dart'; +import 'package:figmage/src/domain/models/style/design_style.dart'; +import 'package:test/test.dart'; + +void main() { + group("ColorStyle", () { + test("is a DesignToken", () { + const style = ColorDesignStyle(id: "id", name: "name", value: 0xFFFFFFFF); + expect(style, isA>()); + + expect([style].whereType>(), hasLength(1)); + }); + }); +} diff --git a/test/src/domain/models/variable/variable_test.dart b/test/src/domain/models/variable/variable_test.dart new file mode 100644 index 00000000..eb5f4698 --- /dev/null +++ b/test/src/domain/models/variable/variable_test.dart @@ -0,0 +1,20 @@ +import 'package:test/test.dart'; + +import '../../../../test_util/mock/mock_variables.dart'; + +void main() { + group('Variable', () { + group('fullName', () { + test('should return the name if collection is empty', () { + expect(mockVariableEmptyCollection.variableCollectionName, ""); + expect( + mockVariableEmptyCollection.fullName, + mockVariableEmptyCollection.name, + ); + }); + test('should put slash between collection name and variable name', () { + expect(mockBoolVariable.fullName, 'collection1/boolName'); + }); + }); + }); +} diff --git a/test/src/domain/providers/config_providers_test.dart b/test/src/domain/providers/config_providers_test.dart new file mode 100644 index 00000000..09041ae5 --- /dev/null +++ b/test/src/domain/providers/config_providers_test.dart @@ -0,0 +1,66 @@ +import 'dart:io'; + +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/providers/config_providers.dart'; +import 'package:figmage/src/domain/repositories/config_repository.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:test/test.dart'; + +import '../../../test_util/test_provider_listener.dart'; + +class _MockConfigRepository extends Mock implements ConfigRepository {} + +void main() { + group("configProvider", () { + late ProviderContainer container; + late _MockConfigRepository configRepository; + const config = Config(fileId: "fileId", packageName: "packageName"); + + setUp(() { + configRepository = _MockConfigRepository(); + when(() => configRepository.readConfigFromFile(file: any(named: 'file'))) + .thenAnswer((_) async => config); + + container = ProviderContainer( + overrides: [ + configRepositoryProvider.overrideWith((ref) => configRepository), + ], + ); + }); + tearDown(() { + container.dispose(); + }); + + test('pipes through mockRepository', () async { + final listener = TestListener>(); + container.listen( + configProvider('path/to/file'), + listener.call, + fireImmediately: true, + ); + await container.read(configProvider('path').future); + verify( + () => configRepository.readConfigFromFile( + file: any( + named: 'file', + that: isA().having((f) => f.path, 'path', 'path/to/file'), + ), + ), + ).called(1); + verifyInOrder([ + () => listener.call(null, const AsyncLoading()), + () => listener.call(const AsyncLoading(), const AsyncData(config)), + ]); + }); + + test('calls repo with null if no path provided', () { + container.read(configProvider(null).future); + verify( + () => configRepository.readConfigFromFile( + file: any(named: 'file', that: isNull), + ), + ).called(1); + }); + }); +} diff --git a/test/src/domain/providers/generator_providers_test.dart b/test/src/domain/providers/generator_providers_test.dart new file mode 100644 index 00000000..12fe867b --- /dev/null +++ b/test/src/domain/providers/generator_providers_test.dart @@ -0,0 +1,110 @@ +import 'dart:io'; + +import 'package:figmage/src/data/generators/color_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/number_theme_extension_generator.dart'; +import 'package:figmage/src/data/generators/padding_generator.dart'; +import 'package:figmage/src/data/generators/spacer_generator.dart'; +import 'package:figmage/src/data/generators/text_style_theme_extension_generator.dart'; +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/models/figmage_settings.dart'; +import 'package:figmage/src/domain/models/tokens_by_file_type/tokens_by_type.dart'; +import 'package:figmage/src/domain/providers/design_token_providers.dart'; +import 'package:figmage/src/domain/providers/figmage_package_generator_providers.dart'; +import 'package:figmage/src/domain/providers/generator_providers.dart'; +import 'package:figmage/src/domain/providers/logger_providers.dart'; +import 'package:figmage_package_generator/figmage_package_generator.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:test/test.dart'; + +import '../../../test_util/mock/mock_styles.dart'; +import '../../../test_util/mock/mock_variables.dart'; + +class _MockLogger extends Mock implements Logger {} + +class _MockProgress extends Mock implements Progress {} + +void main() { + group("generatorsProvider", () { + late _MockLogger logger; + late TokensByType mockTokensByFileType; + late Iterable mockGenerated; + + late ProviderContainer container; + + late FigmageSettings settings; + + setUp(() { + logger = _MockLogger(); + when(() => logger.progress(any())).thenReturn(_MockProgress()); + + mockTokensByFileType = TokensByType( + colorTokens: [ + mockColorDesignStyle, + // mockColorVariable, + ], + typographyTokens: [ + mockTextDesignStyle, + ], + numberTokens: [mockFloatVariable], + boolTokens: [mockBoolVariable], + stringTokens: [mockStringVariable], + ); + mockGenerated = [ + for (final type in TokenFileType.values) + File("lib/src/${type.filename}"), + ]; + + container = ProviderContainer( + overrides: [ + loggerProvider.overrideWith((ref) => logger), + filteredTokensProvider + .overrideWith((ref, arg) => mockTokensByFileType), + generatedPackageProvider.overrideWith((ref, arg) => mockGenerated), + ], + ); + + settings = ( + fileId: "fileId", + path: ".", + token: "token", + config: const Config(), + ); + }); + tearDown(() { + container.dispose(); + }); + + test('returns all existing in test case where everything exists', () async { + final result = await container.read(generatorsProvider(settings).future); + expect(result, hasLength(5)); + expect( + result.values, + containsAll( + [ + isA(), + isA(), + isA(), + isA(), + isA(), + ], + ), + ); + }); + + test('all file paths are included', () async { + final result = await container.read(generatorsProvider(settings).future); + expect( + result.keys.map((e) => e.path), + containsAll([ + "lib/src/colors.dart", + "lib/src/typography.dart", + "lib/src/numbers.dart", + "lib/src/spacers.dart", + "lib/src/paddings.dart", + ]), + ); + }); + }); +} diff --git a/test/src/domain/util/token_filter_x_test.dart b/test/src/domain/util/token_filter_x_test.dart new file mode 100644 index 00000000..0d271ddb --- /dev/null +++ b/test/src/domain/util/token_filter_x_test.dart @@ -0,0 +1,81 @@ +import 'package:figmage/src/domain/models/config/config.dart'; +import 'package:figmage/src/domain/models/variable/variable.dart'; +import 'package:figmage/src/domain/util/token_filter_x.dart'; +import 'package:test/test.dart'; + +import '../../../test_util/mock/mock_variables.dart'; + +void main() { + group('VariableFilterX', () { + group("filterByFrom", () { + test("should return all if from is empty", () { + final variables = + mockVariables.filterByFrom(const GenerationSettings()); + expect(variables, mockVariables); + }); + test("filters by prefix correctly", () { + final variables = mockVariables.filterByFrom( + const GenerationSettings(from: ['collection1/']), + ); + expect(variables, hasLength(2)); + expect( + variables, + everyElement( + isA>().having( + (p0) => p0.variableCollectionName, + "variable collection name", + "collection1", + ), + ), + ); + }); + }); + group("valuesByNameByMode", () { + test("should return an empty map if there are no variables", () { + final valuesByNameByMode = >[].valuesByNameByMode; + expect(valuesByNameByMode, isEmpty); + }); + test("should return a map of values by name by mode", () { + final valuesByNameByMode = mockVariables.valuesByNameByMode; + expect(valuesByNameByMode, { + "light": { + "boolName": true, + "colorName": 0xFF000000, + "floatName": 1, + "stringName": "light", + }, + "dark": { + "boolName": false, + "colorName": 0xFFFFFFFF, + "floatName": 0, + "stringName": "dark", + }, + }); + }); + + test("should order modes alphabetically", () { + final valuesByNameByMode = mockVariables.valuesByNameByMode; + expect(valuesByNameByMode.keys, containsAllInOrder(["dark", "light"])); + }); + + test("should order names alphabetically", () { + final valuesByNameByMode = mockVariables.valuesByNameByMode; + expect( + valuesByNameByMode.values, + everyElement( + isA>().having( + (p0) => p0.keys, + "keys", + containsAllInOrder([ + "boolName", + "colorName", + "floatName", + "stringName", + ]), + ), + ), + ); + }); + }); + }); +} diff --git a/test/test_util/mock/mock_styles.dart b/test/test_util/mock/mock_styles.dart new file mode 100644 index 00000000..bee9d3f0 --- /dev/null +++ b/test/test_util/mock/mock_styles.dart @@ -0,0 +1,19 @@ +import 'package:figmage/src/domain/models/style/design_style.dart'; +import 'package:figmage/src/domain/models/text_style/text_style.dart'; + +const mockColorDesignStyle = ColorDesignStyle( + id: "color_id", + name: "color_name", + value: 0xFFFFFFFF, +); + +const mockTextDesignStyle = TextDesignStyle( + id: "text_id", + name: "text_name", + value: TextStyle(fontFamily: "Inter", fontSize: 12), +); + +const mockStyles = >[ + mockColorDesignStyle, + mockTextDesignStyle, +]; diff --git a/test/test_util/mock/mock_variables.dart b/test/test_util/mock/mock_variables.dart new file mode 100644 index 00000000..c62c01b7 --- /dev/null +++ b/test/test_util/mock/mock_variables.dart @@ -0,0 +1,108 @@ +// Due to the analyer raising weird issues when using the const constructors, +// we have to ignore the prefer_const_constructors rule. +// ignore_for_file: prefer_const_constructors + +import 'package:figmage/src/domain/models/variable/alias_or/alias_or.dart'; +import 'package:figmage/src/domain/models/variable/variable.dart'; + +final mockColorVariable = ColorVariable( + id: "color_id", + name: "colorName", + remote: false, + key: "key", + variableCollectionId: "variableCollectionId", + variableCollectionName: "collection1", + resolvedType: "COLOR", + description: "description", + hiddenFromPublishing: false, + scopes: [], + codeSyntax: {}, + collectionModeNames: {}, + valuesByMode: { + "light": AliasOr.data(data: 0xFF000000), + "dark": AliasOr.data(data: 0xFFFFFFFF), + }, +); + +final mockFloatVariable = FloatVariable( + id: "float_id", + name: "floatName", + remote: false, + key: "key", + variableCollectionId: "variableCollectionId", + variableCollectionName: "collection2", + resolvedType: "FLOAT", + description: "description", + hiddenFromPublishing: false, + scopes: [], + codeSyntax: {}, + collectionModeNames: {}, + valuesByMode: { + "light": AliasOr.data(data: 1), + "dark": AliasOr.data(data: 0), + }, +); + +final mockBoolVariable = BoolVariable( + id: "bool_id", + name: "boolName", + remote: false, + key: "key", + variableCollectionId: "variableCollectionId", + variableCollectionName: "collection1", + resolvedType: "BOOLEAN", + description: "description", + hiddenFromPublishing: false, + scopes: [], + codeSyntax: {}, + collectionModeNames: {}, + valuesByMode: { + "light": AliasOr.data(data: true), + "dark": AliasOr.data(data: false), + }, +); + +final mockStringVariable = StringVariable( + id: "string_id", + name: "stringName", + remote: false, + key: "key", + variableCollectionId: "variableCollectionId", + variableCollectionName: "collection2", + resolvedType: "STRING", + description: "description", + hiddenFromPublishing: false, + scopes: [], + codeSyntax: {}, + collectionModeNames: {}, + valuesByMode: { + "light": AliasOr.data(data: "light"), + "dark": AliasOr.data(data: "dark"), + }, +); + +final mockVariables = >[ + mockColorVariable, + mockBoolVariable, + mockFloatVariable, + mockStringVariable, +]; + +final mockVariableEmptyCollection = BoolVariable( + id: "bool_id", + name: "boolName", + remote: false, + key: "key", + variableCollectionId: "variableCollectionId", + variableCollectionName: "", + resolvedType: "BOOLEAN", + description: "description", + hiddenFromPublishing: false, + scopes: [], + codeSyntax: {}, + collectionModeNames: {}, + valuesByMode: { + "light": AliasOr.data(data: true), + "dark": AliasOr.data(data: false), + }, +); diff --git a/test/test_util/test_provider_listener.dart b/test/test_util/test_provider_listener.dart new file mode 100644 index 00000000..af019f5b --- /dev/null +++ b/test/test_util/test_provider_listener.dart @@ -0,0 +1,6 @@ +import 'package:mocktail/mocktail.dart'; + +/// A helper class to verify provider state changes with mocktail. +class TestListener extends Mock { + void call(T? previous, T value); +}