From a81e7b6ec2d64e9f8723b6fb4f9ecfe03eb00b43 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Tue, 6 Jan 2026 14:50:43 -0600 Subject: [PATCH] Enable stricter dynamic-related analysis --- analysis_options.yaml | 5 ++++- .../src/tools/booking/booking_service.dart | 6 ++---- .../lib/features/state/loading_state.dart | 2 +- .../lib/features/widgets/app_navigator.dart | 2 +- .../genui/test/model/data_model_test.dart | 19 ++++++++++++------- .../example/lib/src/jumping_dots.dart | 6 ++++-- .../test/dartantic_schema_adapter_test.dart | 2 +- .../lib/src/schema_registry.dart | 4 ++-- .../lib/src/schema_validation.dart | 10 +++++----- .../test/fix_copyright_test.dart | 2 +- 10 files changed, 33 insertions(+), 25 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a8a2f26cc..281a71bf8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -8,6 +8,7 @@ analyzer: language: strict-casts: true strict-inference: true + strict-raw-types: true linter: rules: @@ -28,6 +29,7 @@ linter: # correctness - always_declare_return_types + - avoid_annotating_with_dynamic - avoid_catching_errors - avoid_dynamic_calls - comment_references @@ -41,4 +43,5 @@ linter: - omit_obvious_local_variable_types - specify_nonobvious_local_variable_types - - specify_nonobvious_property_types \ No newline at end of file + - specify_nonobvious_property_types + - strict_top_level_inference diff --git a/examples/travel_app/lib/src/tools/booking/booking_service.dart b/examples/travel_app/lib/src/tools/booking/booking_service.dart index 88b93d4a5..04fd0d30b 100644 --- a/examples/travel_app/lib/src/tools/booking/booking_service.dart +++ b/examples/travel_app/lib/src/tools/booking/booking_service.dart @@ -24,8 +24,7 @@ class BookingService { } Future listHotels(HotelSearch search) async { - // ignore: inference_failure_on_instance_creation - await Future.delayed(const Duration(milliseconds: 100)); + await Future.delayed(const Duration(milliseconds: 100)); return listHotelsSync(search); } @@ -33,8 +32,7 @@ class BookingService { List listingSelectionIds, String paymentMethodId, ) async { - // ignore: inference_failure_on_instance_creation - await Future.delayed(const Duration(milliseconds: 400)); + await Future.delayed(const Duration(milliseconds: 400)); } /// Synchronous version for example data generation. diff --git a/examples/verdure/client/lib/features/state/loading_state.dart b/examples/verdure/client/lib/features/state/loading_state.dart index 5f43688ef..97e53e976 100644 --- a/examples/verdure/client/lib/features/state/loading_state.dart +++ b/examples/verdure/client/lib/features/state/loading_state.dart @@ -36,7 +36,7 @@ class LoadingState { } else if (_isProcessingValue && !isProcessing.value) { // Went from true to false, reset messages after a short delay // to allow the fade-out animation to complete. - Future.delayed(const Duration(milliseconds: 500), clearMessages); + Future.delayed(const Duration(milliseconds: 500), clearMessages); } _isProcessingValue = isProcessing.value; }); diff --git a/examples/verdure/client/lib/features/widgets/app_navigator.dart b/examples/verdure/client/lib/features/widgets/app_navigator.dart index b48e8a3ea..67576d8da 100644 --- a/examples/verdure/client/lib/features/widgets/app_navigator.dart +++ b/examples/verdure/client/lib/features/widgets/app_navigator.dart @@ -23,7 +23,7 @@ class AppNavigator extends ConsumerStatefulWidget { } class _AppNavigatorState extends ConsumerState { - StreamSubscription? _subscription; + StreamSubscription? _subscription; @override void initState() { diff --git a/packages/genui/test/model/data_model_test.dart b/packages/genui/test/model/data_model_test.dart index 4832d0bff..a7540bb02 100644 --- a/packages/genui/test/model/data_model_test.dart +++ b/packages/genui/test/model/data_model_test.dart @@ -148,9 +148,9 @@ void main() { }); test('notifies on child updates', () { - final ValueNotifier?> notifier = dataModel - .subscribe(DataPath('/a')); - Map? value; + final ValueNotifier?> notifier = dataModel + .subscribe>(DataPath('/a')); + Map? value; notifier.addListener(() => value = notifier.value); dataModel.update(DataPath('/a/b'), 1); expect(value, {'b': 1}); @@ -180,8 +180,8 @@ void main() { }); test('does not notify on child updates', () { - final ValueNotifier?> notifier = dataModel - .subscribeToValue(DataPath('/a')); + final ValueNotifier?> notifier = dataModel + .subscribeToValue>(DataPath('/a')); var callCount = 0; notifier.addListener(() => callCount++); dataModel.update(DataPath('/a/b'), 1); @@ -232,7 +232,10 @@ void main() { ], }, ]); - expect(dataModel.getValue(DataPath('/d')), {'d1': 'v1', 'd2': 2}); + expect(dataModel.getValue>(DataPath('/d')), { + 'd1': 'v1', + 'd2': 2, + }); }); test('is permissive with multiple value types', () { @@ -304,7 +307,9 @@ void main() { test('Empty path on getValue returns current data', () { dataModel.update(DataPath('/a'), {'b': 1}); - expect(dataModel.getValue(DataPath('/a')), {'b': 1}); + expect(dataModel.getValue>(DataPath('/a')), { + 'b': 1, + }); }); test('Nested structures are created automatically', () { diff --git a/packages/genui_dartantic/example/lib/src/jumping_dots.dart b/packages/genui_dartantic/example/lib/src/jumping_dots.dart index 8247987cf..4aebfc3f3 100644 --- a/packages/genui_dartantic/example/lib/src/jumping_dots.dart +++ b/packages/genui_dartantic/example/lib/src/jumping_dots.dart @@ -55,9 +55,11 @@ class _JumpingDotsState extends State controller.reverse(); } }); - await Future.delayed(const Duration(milliseconds: 100)); // Stagger delay + await Future.delayed( + const Duration(milliseconds: 100), + ); // Stagger delay } - await Future.delayed( + await Future.delayed( const Duration(milliseconds: 1000), ); // Delay between loops if (mounted) _startAnimations(); // Loop diff --git a/packages/genui_dartantic/test/dartantic_schema_adapter_test.dart b/packages/genui_dartantic/test/dartantic_schema_adapter_test.dart index c31f86188..267b6f4b0 100644 --- a/packages/genui_dartantic/test/dartantic_schema_adapter_test.dart +++ b/packages/genui_dartantic/test/dartantic_schema_adapter_test.dart @@ -116,7 +116,7 @@ void main() { final result = adaptSchema(schema); expect(result, isNotNull); - expect(result!.schemaMap!['anyOf'], isA()); + expect(result!.schemaMap!['anyOf'], isA>()); }); }); } diff --git a/packages/json_schema_builder/lib/src/schema_registry.dart b/packages/json_schema_builder/lib/src/schema_registry.dart index 8036f7ac6..d33598edd 100644 --- a/packages/json_schema_builder/lib/src/schema_registry.dart +++ b/packages/json_schema_builder/lib/src/schema_registry.dart @@ -97,7 +97,7 @@ class SchemaRegistry { _registerIds(Schema.fromMap(map), baseUri); } - void recurseOnList(List list) { + void recurseOnList(List list) { for (final item in list) { if (item is Map) { recurseOnMap(item); @@ -144,7 +144,7 @@ class SchemaRegistry { // Keywords with list-of-schemas values const listOfSchemasKeywords = ['allOf', 'anyOf', 'oneOf', 'prefixItems']; for (final keyword in listOfSchemasKeywords) { - if (schema.value[keyword] case final List list) { + if (schema.value[keyword] case final List list) { recurseOnList(list); } } diff --git a/packages/json_schema_builder/lib/src/schema_validation.dart b/packages/json_schema_builder/lib/src/schema_validation.dart index ff466498c..4e29e2658 100644 --- a/packages/json_schema_builder/lib/src/schema_validation.dart +++ b/packages/json_schema_builder/lib/src/schema_validation.dart @@ -352,7 +352,7 @@ extension SchemaValidation on Schema { } // 2. Schema Combiners: allOf, anyOf, oneOf, not - if (allOf case final List allOfList?) { + if (allOf case final List allOfList) { final allOfAnnotations = []; for (final subSchema in allOfList) { final ValidationResult result = await validateSubSchema( @@ -370,7 +370,7 @@ extension SchemaValidation on Schema { allAnnotations = allAnnotations.mergeAll(allOfAnnotations); } - if (anyOf case final List anyOfList?) { + if (anyOf case final List anyOfList) { var passedCount = 0; final anyOfAnnotations = []; final allAnyOfErrors = []; @@ -397,7 +397,7 @@ extension SchemaValidation on Schema { allAnnotations = allAnnotations.mergeAll(anyOfAnnotations); } - if (oneOf case final List oneOfList?) { + if (oneOf case final List oneOfList) { var passedCount = 0; AnnotationSet? oneOfAnnotations; for (final subSchema in oneOfList) { @@ -590,7 +590,7 @@ extension SchemaValidation on Schema { ); case JsonType.list: return await (this as ListSchema).validateList( - data as List, + data as List, currentPath, context, dynamicScope, @@ -895,7 +895,7 @@ extension SchemaValidation on Schema { /// This method is called by [validateTypeSpecificKeywords] when the data is /// a [List]. Future validateList( - List data, + List data, List currentPath, ValidationContext context, List dynamicScope, diff --git a/tool/fix_copyright/test/fix_copyright_test.dart b/tool/fix_copyright/test/fix_copyright_test.dart index d2b9c64f3..8a4310a3a 100644 --- a/tool/fix_copyright/test/fix_copyright_test.dart +++ b/tool/fix_copyright/test/fix_copyright_test.dart @@ -388,7 +388,7 @@ class FakeProcessManager implements ProcessManager { final List> commands = []; @override - bool canRun(dynamic executable, {String? workingDirectory}) => true; + bool canRun(Object? executable, {String? workingDirectory}) => true; @override bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) => true;